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

View File

@ -1,9 +1,11 @@
import 'package:cheminova/screens/Add_products_screen.dart'; import 'package:cheminova/provider/pd_rd_provider.dart';
import 'package:flutter/material.dart'; import 'package:cheminova/screens/add_products_screen.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_app_bar.dart';
import 'package:cheminova/widgets/common_drawer.dart'; import 'package:cheminova/widgets/common_drawer.dart';
import 'package:cheminova/widgets/common_elevated_button.dart'; import 'package:cheminova/widgets/common_elevated_button.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class UpdateInventoryScreen extends StatefulWidget { class UpdateInventoryScreen extends StatefulWidget {
const UpdateInventoryScreen({super.key}); const UpdateInventoryScreen({super.key});
@ -13,14 +15,17 @@ class UpdateInventoryScreen extends StatefulWidget {
} }
class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> { class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
final List<String> principalDistributors = ['vaibhav', 'sonu', 'monu'];
final List<String> retailerDistributors = ['shivam', 'vivek'];
String? selectedDistributorType; String? selectedDistributorType;
String? selectedDistributor; String? selectedDistributor;
@override @override
void initState() { void initState() {
super.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 @override
@ -66,75 +71,97 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
}, },
), ),
), ),
body: Stack( body: Consumer<PdRdProvider>(
children: [ builder: (context, provider, child) {
Column( 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: [ children: [
// Dropdown for selecting distributor type Column(
Padding( children: [
padding: const EdgeInsets.symmetric( // Dropdown for selecting distributor type
horizontal: 15.0, vertical: 25), Padding(
child: DropdownButtonFormField<String>( padding: const EdgeInsets.symmetric(
decoration: const InputDecoration( horizontal: 15.0, vertical: 25),
labelText: 'Select Distributor Type', child: DropdownButtonFormField<String>(
fillColor: Colors.white, decoration: const InputDecoration(
filled: true, labelText: 'Select Distributor Type',
border: OutlineInputBorder(), 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, // Dropdown for selecting distributor name based on type
items: ['Principal Distributor', 'Retailer Distributor'] Padding(
.map((String type) { padding: const EdgeInsets.symmetric(
return DropdownMenuItem<String>( horizontal: 15.0, vertical: 25),
value: type, child: DropdownButtonFormField<String>(
child: Text(type), decoration: const InputDecoration(
); labelText: 'Select Distributor Name',
}).toList(), fillColor: Colors.white,
onChanged: (value) { filled: true,
setState(() { border: OutlineInputBorder(),
selectedDistributorType = value; ),
selectedDistributor = value: selectedDistributor,
null; // Reset distributor selection when type changes items:
}); (selectedDistributorType == 'Principal Distributor'
}, ? principalDistributors
), : retailerDistributors)
), .map((String distributor) {
// Dropdown for selecting distributor name based on type return DropdownMenuItem<String>(
Padding( value: distributor,
padding: const EdgeInsets.symmetric( child: Text(distributor),
horizontal: 15.0, vertical: 25), );
child: DropdownButtonFormField<String>( }).toList(),
decoration: const InputDecoration( onChanged: (value) {
labelText: 'Select Distributor Name', setState(() {
fillColor: Colors.white, selectedDistributor = value;
filled: true, });
border: OutlineInputBorder(), },
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 notificationUrl = '$baseUrl/get-notification-tm';
static const String fcmUrl = '${baseUrl}kyc/save-fcm-tm'; static const String fcmUrl = '${baseUrl}kyc/save-fcm-tm';
static const String getProducts = '${baseUrl}product/getAll/user/'; static const String getProducts = '${baseUrl}product/getAll/user/';
static const String getPdRdUrl =
'inventory/distributors-TM/RetailDistributor';
} }