From de188372d9a9ed9abbca8b1cca4db468d341ffd0 Mon Sep 17 00:00:00 2001 From: kratikpal Date: Wed, 14 Aug 2024 14:37:47 +0530 Subject: [PATCH] Pd and Rd list added --- lib/main.dart | 2 + lib/models/pd_rd_response_model.dart | 156 ++++++++++++++++++++++ lib/provider/pd_rd_provider.dart | 40 ++++++ lib/screens/add_products_screen.dart | 154 ++++++++++++--------- lib/screens/update_inventory_screen.dart | 163 +++++++++++++---------- lib/services/api_urls.dart | 2 + 6 files changed, 383 insertions(+), 134 deletions(-) create mode 100644 lib/models/pd_rd_response_model.dart create mode 100644 lib/provider/pd_rd_provider.dart diff --git a/lib/main.dart b/lib/main.dart index a83d3a6..5724c7b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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 main() async { ChangeNotifierProvider(create: (context) => CollectKycProvider()), ChangeNotifierProvider(create: (_) => UserProvider()), ChangeNotifierProvider(create: (_) => ProductProvider()), + ChangeNotifierProvider(create: (_) => PdRdProvider()), ], child: const MyApp(), ), diff --git a/lib/models/pd_rd_response_model.dart b/lib/models/pd_rd_response_model.dart new file mode 100644 index 0000000..41f5ec1 --- /dev/null +++ b/lib/models/pd_rd_response_model.dart @@ -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 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 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.from(json["notes"].map((x) => Note.fromJson(x))), + createdAt: DateTime.parse(json["createdAt"]), + updatedAt: DateTime.parse(json["updatedAt"]), + v: json["__v"], + ); + + Map 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.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 json) => ImageModel( + publicId: json["public_id"], + url: json["url"], + ); + + Map 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 json) => Note( + message: json["message"], + replyDate: DateTime.parse(json["replyDate"]), + id: json["_id"], + ); + + Map toJson() => { + "message": message, + "replyDate": replyDate.toIso8601String(), + "_id": id, + }; +} diff --git a/lib/provider/pd_rd_provider.dart b/lib/provider/pd_rd_provider.dart new file mode 100644 index 0000000..1abfb66 --- /dev/null +++ b/lib/provider/pd_rd_provider.dart @@ -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 _pdRdList = []; + List get pdRdList => _pdRdList; + + final _apiClient = ApiClient(); + + void setLoading(bool loading) { + _isLoading = loading; + notifyListeners(); + } + + Future 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 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); + } + } +} diff --git a/lib/screens/add_products_screen.dart b/lib/screens/add_products_screen.dart index 43a2327..75f3876 100644 --- a/lib/screens/add_products_screen.dart +++ b/lib/screens/add_products_screen.dart @@ -19,12 +19,20 @@ class _AddProductsScreenState extends State { List selectedProducts = []; List filteredProducts = []; final searchController = TextEditingController(); + late ProductProvider provider; @override void initState() { super.initState(); + loadProducts(); + } + + Future loadProducts() async { final provider = Provider.of(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 { 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 { 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( + 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(() { diff --git a/lib/screens/update_inventory_screen.dart b/lib/screens/update_inventory_screen.dart index 23b412c..f858e81 100644 --- a/lib/screens/update_inventory_screen.dart +++ b/lib/screens/update_inventory_screen.dart @@ -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 { - final List principalDistributors = ['vaibhav', 'sonu', 'monu']; - final List 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(context, listen: false); + provider.getPdRd(); + }); } @override @@ -66,75 +71,97 @@ class _UpdateInventoryScreenState extends State { }, ), ), - body: Stack( - children: [ - Column( + body: Consumer( + 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 principalDistributors = provider.pdRdList + .where((item) => item.userType == 'SalesCoOrdinator') + .map((item) => item.name) + .toList(); + + List 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( - 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( + 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( + 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( - 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( - 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( + 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( + 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( - 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'), - ), + ], ), ], - ), - ], + ); + }, ), ), ); diff --git a/lib/services/api_urls.dart b/lib/services/api_urls.dart index 7ce167a..8ef1b52 100644 --- a/lib/services/api_urls.dart +++ b/lib/services/api_urls.dart @@ -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'; }