Pd and Rd list added

This commit is contained in:
kratikpal 2024-08-14 14:37:47 +05:30
parent 7e86e93c8e
commit de188372d9
6 changed files with 383 additions and 134 deletions

View File

@ -1,6 +1,7 @@
import 'dart:developer';
import 'dart:io';
import 'package:cheminova/provider/collect_kyc_provider.dart';
import 'package:cheminova/provider/pd_rd_provider.dart';
import 'package:cheminova/provider/product_provider.dart';
import 'package:cheminova/provider/user_provider.dart';
import 'package:cheminova/screens/splash_screen.dart';
@ -98,6 +99,7 @@ Future<void> main() async {
ChangeNotifierProvider(create: (context) => CollectKycProvider()),
ChangeNotifierProvider(create: (_) => UserProvider()),
ChangeNotifierProvider(create: (_) => ProductProvider()),
ChangeNotifierProvider(create: (_) => PdRdProvider()),
],
child: const MyApp(),
),

View File

@ -0,0 +1,156 @@
class PdRdResponseModel {
String id;
String name;
String tradeName;
String address;
String state;
String city;
String district;
String pincode;
String mobileNumber;
String principalDistributer;
String panNumber;
ImageModel panImg;
String aadharNumber;
ImageModel aadharImg;
String gstNumber;
ImageModel gstImg;
ImageModel pesticideLicenseImg;
ImageModel selfieEntranceImg;
String status;
String addedBy;
String? userType;
List<Note> notes;
DateTime createdAt;
DateTime updatedAt;
int v;
PdRdResponseModel({
required this.id,
required this.name,
required this.tradeName,
required this.address,
required this.state,
required this.city,
required this.district,
required this.pincode,
required this.mobileNumber,
required this.principalDistributer,
required this.panNumber,
required this.panImg,
required this.aadharNumber,
required this.aadharImg,
required this.gstNumber,
required this.gstImg,
required this.pesticideLicenseImg,
required this.selfieEntranceImg,
required this.status,
required this.addedBy,
this.userType,
required this.notes,
required this.createdAt,
required this.updatedAt,
required this.v,
});
factory PdRdResponseModel.fromJson(Map<String, dynamic> json) =>
PdRdResponseModel(
id: json["_id"],
name: json["name"],
tradeName: json["trade_name"],
address: json["address"],
state: json["state"],
city: json["city"],
district: json["district"],
pincode: json["pincode"],
mobileNumber: json["mobile_number"],
principalDistributer: json["principal_distributer"],
panNumber: json["pan_number"],
panImg: ImageModel.fromJson(json["pan_img"]),
aadharNumber: json["aadhar_number"],
aadharImg: ImageModel.fromJson(json["aadhar_img"]),
gstNumber: json["gst_number"],
gstImg: ImageModel.fromJson(json["gst_img"]),
pesticideLicenseImg: ImageModel.fromJson(json["pesticide_license_img"]),
selfieEntranceImg: ImageModel.fromJson(json["selfie_entrance_img"]),
status: json["status"],
addedBy: json["addedBy"],
userType: json["userType"],
notes: List<Note>.from(json["notes"].map((x) => Note.fromJson(x))),
createdAt: DateTime.parse(json["createdAt"]),
updatedAt: DateTime.parse(json["updatedAt"]),
v: json["__v"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"name": name,
"trade_name": tradeName,
"address": address,
"state": state,
"city": city,
"district": district,
"pincode": pincode,
"mobile_number": mobileNumber,
"principal_distributer": principalDistributer,
"pan_number": panNumber,
"pan_img": panImg.toJson(),
"aadhar_number": aadharNumber,
"aadhar_img": aadharImg.toJson(),
"gst_number": gstNumber,
"gst_img": gstImg.toJson(),
"pesticide_license_img": pesticideLicenseImg.toJson(),
"selfie_entrance_img": selfieEntranceImg.toJson(),
"status": status,
"addedBy": addedBy,
"userType": userType,
"notes": List<dynamic>.from(notes.map((x) => x.toJson())),
"createdAt": createdAt.toIso8601String(),
"updatedAt": updatedAt.toIso8601String(),
"__v": v,
};
}
class ImageModel {
String publicId;
String url;
ImageModel({
required this.publicId,
required this.url,
});
factory ImageModel.fromJson(Map<String, dynamic> json) => ImageModel(
publicId: json["public_id"],
url: json["url"],
);
Map<String, dynamic> toJson() => {
"public_id": publicId,
"url": url,
};
}
class Note {
String message;
DateTime replyDate;
String id;
Note({
required this.message,
required this.replyDate,
required this.id,
});
factory Note.fromJson(Map<String, dynamic> json) => Note(
message: json["message"],
replyDate: DateTime.parse(json["replyDate"]),
id: json["_id"],
);
Map<String, dynamic> toJson() => {
"message": message,
"replyDate": replyDate.toIso8601String(),
"_id": id,
};
}

View File

@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:cheminova/models/pd_rd_response_model.dart';
import 'package:cheminova/services/api_client.dart';
import 'package:cheminova/services/api_urls.dart';
class PdRdProvider extends ChangeNotifier {
bool _isLoading = false;
bool get isLoading => _isLoading;
List<PdRdResponseModel> _pdRdList = [];
List<PdRdResponseModel> get pdRdList => _pdRdList;
final _apiClient = ApiClient();
void setLoading(bool loading) {
_isLoading = loading;
notifyListeners();
}
Future<void> getPdRd() async {
setLoading(true);
try {
Response response = await _apiClient.get(ApiUrls.getPdRdUrl);
if (response.statusCode == 200) {
// Assuming the response data is a list of PdRdResponseModel objects
List<PdRdResponseModel> data = (response.data as List)
.map((json) => PdRdResponseModel.fromJson(json))
.toList();
_pdRdList = data;
} else {
print("Failed to load data: ${response.statusCode}");
}
} catch (e) {
print("Error occurred: $e");
} finally {
setLoading(false);
}
}
}

View File

@ -19,12 +19,20 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
List<Product> selectedProducts = [];
List<Product> filteredProducts = [];
final searchController = TextEditingController();
late ProductProvider provider;
@override
void initState() {
super.initState();
loadProducts();
}
Future<void> loadProducts() async {
final provider = Provider.of<ProductProvider>(context, listen: false);
filteredProducts = provider.productList;
await provider.getProducts();
setState(() {
filteredProducts = provider.productList;
});
}
void filterProducts(String query) {
@ -56,12 +64,15 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
padding: const EdgeInsets.only(right: 20),
),
],
title: const Text('Add Products',
style: TextStyle(
fontSize: 20,
color: Colors.black,
fontWeight: FontWeight.w400,
fontFamily: 'Anek')),
title: const Text(
'Add Products',
style: TextStyle(
fontSize: 20,
color: Colors.black,
fontWeight: FontWeight.w400,
fontFamily: 'Anek',
),
),
backgroundColor: Colors.transparent,
elevation: 0,
),
@ -100,73 +111,84 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
FloatingActionButton.extended(
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
constraints: BoxConstraints(
maxHeight:
MediaQuery.of(context).size.height * 0.9,
),
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: searchController,
decoration: const InputDecoration(
labelText:
'Search by name or SKU',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.search),
return Consumer<ProductProvider>(
builder: (context, value, child) =>
StatefulBuilder(
builder: (context, setState) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(18.0),
child: TextField(
controller: searchController,
decoration: const InputDecoration(
labelText:
'Search by name or SKU',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.search),
),
onChanged: (value) {
filterProducts(value);
setState(() {});
},
),
onChanged: (value) {
filterProducts(value);
setState(() {});
},
),
),
Expanded(
child: ListView.builder(
itemCount: filteredProducts.length,
itemBuilder: (context, index) {
bool isAlreadySelected =
selectedProducts.contains(
filteredProducts[index]);
return Card(
child: ListTile(
title: Text(
filteredProducts[index]
.name,
style: TextStyle(
color: isAlreadySelected
? Colors.grey
: Colors.black,
Expanded(
child: ListView.builder(
itemCount:
filteredProducts.length,
itemBuilder: (context, index) {
bool isAlreadySelected =
selectedProducts.contains(
filteredProducts[
index]);
return Card(
child: ListTile(
title: Text(
filteredProducts[index]
.name,
style: TextStyle(
color: isAlreadySelected
? Colors.grey
: Colors.black,
),
),
),
subtitle: Text(
filteredProducts[index].SKU,
style: TextStyle(
color: isAlreadySelected
? Colors.grey
: Colors.black,
subtitle: Text(
filteredProducts[index]
.SKU,
style: TextStyle(
color: isAlreadySelected
? Colors.grey
: Colors.black,
),
),
onTap: isAlreadySelected
? null
: () {
setState(() {
selectedProducts.add(
filteredProducts[
index]);
});
Navigator.pop(
context);
},
),
onTap: isAlreadySelected
? null
: () {
setState(() {
selectedProducts.add(
filteredProducts[
index]);
});
Navigator.pop(
context);
},
),
);
},
);
},
),
),
),
],
);
},
],
);
},
),
);
},
).whenComplete(() {

View File

@ -1,9 +1,11 @@
import 'package:cheminova/screens/Add_products_screen.dart';
import 'package:flutter/material.dart';
import 'package:cheminova/provider/pd_rd_provider.dart';
import 'package:cheminova/screens/add_products_screen.dart';
import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_app_bar.dart';
import 'package:cheminova/widgets/common_drawer.dart';
import 'package:cheminova/widgets/common_elevated_button.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class UpdateInventoryScreen extends StatefulWidget {
const UpdateInventoryScreen({super.key});
@ -13,14 +15,17 @@ class UpdateInventoryScreen extends StatefulWidget {
}
class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
final List<String> principalDistributors = ['vaibhav', 'sonu', 'monu'];
final List<String> retailerDistributors = ['shivam', 'vivek'];
String? selectedDistributorType;
String? selectedDistributor;
@override
void initState() {
super.initState();
// Fetch the PdRd data when the screen is initialized
WidgetsBinding.instance.addPostFrameCallback((_) {
final provider = Provider.of<PdRdProvider>(context, listen: false);
provider.getPdRd();
});
}
@override
@ -66,75 +71,97 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
},
),
),
body: Stack(
children: [
Column(
body: Consumer<PdRdProvider>(
builder: (context, provider, child) {
if (provider.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (provider.pdRdList.isEmpty) {
return const Center(child: Text('No distributors available.'));
}
List<String> principalDistributors = provider.pdRdList
.where((item) => item.userType == 'SalesCoOrdinator')
.map((item) => item.name)
.toList();
List<String> retailerDistributors = provider.pdRdList
.where((item) => item.userType != 'SalesCoOrdinator')
.map((item) => item.name)
.toList();
return Stack(
children: [
// Dropdown for selecting distributor type
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15.0, vertical: 25),
child: DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: 'Select Distributor Type',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
Column(
children: [
// Dropdown for selecting distributor type
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15.0, vertical: 25),
child: DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: 'Select Distributor Type',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
),
value: selectedDistributorType,
items: ['Principal Distributor', 'Retailer Distributor']
.map((String type) {
return DropdownMenuItem<String>(
value: type,
child: Text(type),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedDistributorType = value;
selectedDistributor =
null; // Reset distributor selection when type changes
});
},
),
),
value: selectedDistributorType,
items: ['Principal Distributor', 'Retailer Distributor']
.map((String type) {
return DropdownMenuItem<String>(
value: type,
child: Text(type),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedDistributorType = value;
selectedDistributor =
null; // Reset distributor selection when type changes
});
},
),
),
// Dropdown for selecting distributor name based on type
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15.0, vertical: 25),
child: DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: 'Select Distributor Name',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
// Dropdown for selecting distributor name based on type
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15.0, vertical: 25),
child: DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: 'Select Distributor Name',
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(),
),
value: selectedDistributor,
items:
(selectedDistributorType == 'Principal Distributor'
? principalDistributors
: retailerDistributors)
.map((String distributor) {
return DropdownMenuItem<String>(
value: distributor,
child: Text(distributor),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedDistributor = value;
});
},
isExpanded: true,
isDense: true,
iconSize: 24,
hint: Text(
'Please select a ${selectedDistributorType ?? "Distributor Type"} first'),
),
),
value: selectedDistributor,
items: (selectedDistributorType == 'Principal Distributor'
? principalDistributors
: retailerDistributors)
.map((String distributor) {
return DropdownMenuItem<String>(
value: distributor,
child: Text(distributor),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedDistributor = value;
});
},
// Disable the dropdown if no distributor type is selected
isExpanded: true,
isDense: true,
iconSize: 24,
hint: Text(
'Please select a ${selectedDistributorType ?? "Distributor Type"} first'),
),
],
),
],
),
],
);
},
),
),
);

View File

@ -12,4 +12,6 @@ class ApiUrls {
static const String notificationUrl = '$baseUrl/get-notification-tm';
static const String fcmUrl = '${baseUrl}kyc/save-fcm-tm';
static const String getProducts = '${baseUrl}product/getAll/user/';
static const String getPdRdUrl =
'inventory/distributors-TM/RetailDistributor';
}