Update sales data task

This commit is contained in:
kratikpal 2024-09-11 16:56:08 +05:30
parent 2d393a9885
commit 5326f4bd86
21 changed files with 1081 additions and 178 deletions

View File

@ -8,3 +8,5 @@ final GlobalKey<ScaffoldMessengerState> _scaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState> get scaffoldMessengerKey => GlobalKey<ScaffoldMessengerState> get scaffoldMessengerKey =>
_scaffoldMessengerKey; _scaffoldMessengerKey;
GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

View File

@ -1,5 +1,7 @@
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:cheminova/constants/constant.dart';
import 'package:cheminova/provider/add_sales_provider.dart';
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/pd_rd_provider.dart';
import 'package:cheminova/provider/product_manual_provider.dart'; import 'package:cheminova/provider/product_manual_provider.dart';
@ -106,6 +108,7 @@ Future<void> main() async {
ChangeNotifierProvider(create: (_) => PdRdProvider()), ChangeNotifierProvider(create: (_) => PdRdProvider()),
ChangeNotifierProvider(create: (_) => TaskProvider()), ChangeNotifierProvider(create: (_) => TaskProvider()),
ChangeNotifierProvider(create: (_) => ProductManualProvider()), ChangeNotifierProvider(create: (_) => ProductManualProvider()),
ChangeNotifierProvider(create: (_) => AddSalesProvider()),
], ],
child: const MyApp(), child: const MyApp(),
), ),
@ -123,6 +126,7 @@ class _MyAppState extends State<MyApp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
// scaffoldMessengerKey: SnackBarService().scaffoldMessengerKey, // scaffoldMessengerKey: SnackBarService().scaffoldMessengerKey,
title: 'cheminova', title: 'cheminova',

View File

@ -2,15 +2,16 @@ class PdRdResponseModel {
String? id; String? id;
String? uniqueId; String? uniqueId;
String? name; String? name;
String? tradeNameRd;
ShippingAddress? shippingAddress; ShippingAddress? shippingAddress;
Kyc? kyc;
String? salesCoordinator; // Nullable property for SalesCoordinator String? salesCoordinator; // Nullable property for SalesCoordinator
PdRdResponseModel({ PdRdResponseModel({
this.id, this.id,
this.uniqueId, this.uniqueId,
this.name, this.name,
this.tradeNameRd, this.kyc,
this.shippingAddress, this.shippingAddress,
this.salesCoordinator, // Initialize SalesCoordinator this.salesCoordinator, // Initialize SalesCoordinator
}); });
@ -20,7 +21,7 @@ class PdRdResponseModel {
id: json["_id"], id: json["_id"],
name: json["name"], name: json["name"],
uniqueId: json["uniqueId"], uniqueId: json["uniqueId"],
tradeNameRd: json["trade_name"], kyc: json["kyc"] != null ? Kyc.fromJson(json["kyc"]) : null,
shippingAddress: json['shippingAddress'] != null shippingAddress: json['shippingAddress'] != null
? ShippingAddress.fromJson(json['shippingAddress']) ? ShippingAddress.fromJson(json['shippingAddress'])
: null, : null,
@ -70,3 +71,53 @@ class ShippingAddress {
); );
} }
} }
class Kyc {
final String id;
final String street;
final String city;
final String state;
final String postalCode;
final String country;
final String panNumber;
final String tradeName;
final String gstNumber;
final bool isDefault;
final String? panImgUrl; // New field for PAN image URL
final String? aadharImgUrl; // New field for Aadhar image URL
final String? gstImgUrl; // New field for GST image URL
Kyc({
required this.id,
required this.street,
required this.city,
required this.state,
required this.postalCode,
required this.country,
required this.panNumber,
required this.tradeName,
required this.gstNumber,
required this.isDefault,
this.panImgUrl,
this.aadharImgUrl,
this.gstImgUrl,
});
factory Kyc.fromJson(Map<String, dynamic> json) {
return Kyc(
id: json['_id'] ?? '',
street: json['street'] ?? '',
city: json['city'] ?? '',
state: json['state'] ?? '',
postalCode: json['postalCode'] ?? '',
country: json['country'] ?? '',
panNumber: json['panNumber'] ?? '',
tradeName: json['trade_name'] ?? '',
gstNumber: json['gstNumber'] ?? '',
isDefault: json['isDefault'] ?? false,
panImgUrl: json['pan_img']?['url'],
aadharImgUrl: json['aadhar_img']?['url'],
gstImgUrl: json['gst_img']?['url'],
);
}
}

View File

@ -0,0 +1,174 @@
class SalesTaskResponse {
bool? success;
int? totalData;
int? totalPages;
List<SalesProduct>? products;
SalesTaskResponse(
{this.success, this.totalData, this.totalPages, this.products});
SalesTaskResponse.fromJson(Map<String, dynamic> json) {
success = json['success'];
totalData = json['total_data'];
totalPages = json['total_pages'];
if (json['products'] != null) {
products = <SalesProduct>[];
json['products'].forEach((v) {
products!.add(SalesProduct.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['success'] = success;
data['total_data'] = totalData;
data['total_pages'] = totalPages;
if (products != null) {
data['products'] = products!.map((v) => v.toJson()).toList();
}
return data;
}
}
class SalesProduct {
String? sId;
String? SKU;
String? ProductName;
Category? category;
Brand? brand;
int? price;
int? gST;
int? hSNCode;
String? description;
String? productStatus;
AddedBy? addedBy;
List<Null>? image;
String? createdAt;
String? updatedAt;
int? SalesAmount;
int? QuantitySold;
String? comments;
int? iV;
SalesProduct(
{this.sId,
this.SKU,
this.ProductName,
this.category,
this.brand,
this.price,
this.gST,
this.hSNCode,
this.description,
this.productStatus,
this.addedBy,
this.image,
this.createdAt,
this.updatedAt,
this.QuantitySold,
this.comments,
this.SalesAmount,
this.iV});
SalesProduct.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
SKU = json['SKU'];
ProductName = json['name'];
category =
json['category'] != null ? Category.fromJson(json['category']) : null;
brand = json['brand'] != null ? Brand.fromJson(json['brand']) : null;
price = json['price'];
gST = json['GST'];
hSNCode = json['HSN_Code'];
description = json['description'];
productStatus = json['product_Status'];
addedBy =
json['addedBy'] != null ? AddedBy.fromJson(json['addedBy']) : null;
createdAt = json['createdAt'];
updatedAt = json['updatedAt'];
iV = json['__v'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = sId;
data['SKU'] = SKU;
data['name'] = ProductName;
if (category != null) {
data['category'] = category!.toJson();
}
if (brand != null) {
data['brand'] = brand!.toJson();
}
data['price'] = price;
data['GST'] = gST;
data['HSN_Code'] = hSNCode;
data['description'] = description;
data['product_Status'] = productStatus;
if (addedBy != null) {
data['addedBy'] = addedBy!.toJson();
}
data['createdAt'] = createdAt;
data['updatedAt'] = updatedAt;
data['__v'] = iV;
return data;
}
}
class Category {
String? sId;
String? categoryName;
Category({this.sId, this.categoryName});
Category.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
categoryName = json['categoryName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = sId;
data['categoryName'] = categoryName;
return data;
}
}
class Brand {
String? sId;
String? brandName;
Brand({this.sId, this.brandName});
Brand.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
brandName = json['brandName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = sId;
data['brandName'] = brandName;
return data;
}
}
class AddedBy {
String? sId;
String? name;
AddedBy({this.sId, this.name});
AddedBy.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = sId;
data['name'] = name;
return data;
}
}

View File

@ -0,0 +1,126 @@
import 'dart:convert';
import 'package:cheminova/constants/constant.dart';
import 'package:cheminova/models/sales_task_response.dart';
import 'package:cheminova/screens/data_submit_successfull.dart';
import 'package:cheminova/services/api_client.dart';
import 'package:cheminova/services/api_urls.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
class AddSalesProvider with ChangeNotifier {
final _apiClient = ApiClient();
List<SalesProduct> tasksList = [];
List<SalesProduct> searchList = [];
bool _isLoading = false;
bool get isLoading => _isLoading;
List<SalesProduct> selectedProducts = [];
void setLoading(bool loading) {
_isLoading = loading;
notifyListeners();
}
Future<void> getTask() async {
setLoading(true);
try {
Response response = await _apiClient.get(ApiUrls.salesTaskUrl);
setLoading(false);
if (response.statusCode == 200) {
final data = SalesTaskResponse.fromJson(response.data);
tasksList = data.products ?? [];
notifyListeners();
}
} catch (e) {
setLoading(false);
debugPrint("Error occurred while fetching sales tasks: $e");
}
}
void filterProducts(String val) {
tasksList = tasksList.where((element) {
final productNameLower = element.ProductName!.toLowerCase();
final productSkuLower = element.SKU!.toLowerCase();
final searchLower = val.toLowerCase();
return productNameLower.contains(searchLower) ||
productSkuLower.contains(searchLower);
}).toList();
notifyListeners();
}
Future<void> submitProducts(
{required String distributorType,
required String pdRdId,
required String date,
String? inventoryId,
required String tradeName}) async {
setLoading(true);
try {
Response response = await _apiClient.post(ApiUrls.postSalesTaskUrl,
data: json.encode({
"addedFor": distributorType.replaceAll(' ', ''),
"addedForId": pdRdId,
"tradename": tradeName,
"date": date,
"products": selectedProducts.map((product) {
return {
"SKU": product.SKU,
"ProductName": product.ProductName,
"QuantitySold": product.QuantitySold,
"comments": product.comments,
"SalesAmount": product.SalesAmount
};
}).toList()
// "products": selectedProducts.map((e) => e.toJson()).toList()
}));
setLoading(false);
if (response.statusCode == 201) {
ScaffoldMessenger.of(
navigatorKey.currentContext!,
).showSnackBar(
SnackBar(content: Text(response.data['message'])),
);
if (inventoryId != null) {
_apiClient
.put(ApiUrls.updateTaskInventoryUrl + inventoryId, data: null)
.then((value) {
debugPrint('Task Updated');
if (value.statusCode == 200) {
resetProducts();
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) =>
const DataSubmitSuccessfull()));
} else {
ScaffoldMessenger.of(
navigatorKey.currentContext!,
).showSnackBar(
const SnackBar(content: Text('Task not updated')),
);
}
});
} else {
resetProducts();
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => const DataSubmitSuccessfull()));
}
}
} catch (e) {
setLoading(false);
debugPrint("Error: $e");
}
}
void resetProducts() {
selectedProducts.clear();
tasksList.clear();
notifyListeners();
}
}

View File

@ -30,6 +30,7 @@ class CollectKycProvider extends ChangeNotifier {
final aadharNumberController = TextEditingController(); final aadharNumberController = TextEditingController();
final panNumberController = TextEditingController(); final panNumberController = TextEditingController();
final gstNumberController = TextEditingController(); final gstNumberController = TextEditingController();
final emailController = TextEditingController();
String? selectedDistributor; String? selectedDistributor;
@ -210,6 +211,12 @@ class CollectKycProvider extends ChangeNotifier {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Selfie of Entrance Board is required')), const SnackBar(content: Text('Selfie of Entrance Board is required')),
); );
} else if (emailController.text.trim().isEmpty ||
!emailController.text.trim().contains(RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"))) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Invalid email address')),
);
} else { } else {
submitCollectKycForm(context); submitCollectKycForm(context);
} }
@ -221,6 +228,7 @@ class CollectKycProvider extends ChangeNotifier {
'name': nameController.text.trim(), 'name': nameController.text.trim(),
'trade_name': tradeNameController.text.trim(), 'trade_name': tradeNameController.text.trim(),
'address': addressController.text.trim(), 'address': addressController.text.trim(),
'email': emailController.text.trim(),
'state': state.text.trim(), 'state': state.text.trim(),
'city': city.text.trim(), 'city': city.text.trim(),
'district': districtController.text.trim(), 'district': districtController.text.trim(),
@ -267,8 +275,13 @@ class CollectKycProvider extends ChangeNotifier {
} }
} else { } else {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(
content: Text('Submission failed: ${response.statusMessage}'))); SnackBar(
content: Text(
'${response.data['message'] ?? 'Something went wrong'}',
),
),
);
} }
} }
} catch (e) { } catch (e) {

View File

@ -112,7 +112,7 @@ class TaskProvider extends ChangeNotifier {
'addedForId': _selectedDistributor!.id, 'addedForId': _selectedDistributor!.id,
'tradename': selectedDistributorType == 'PrincipalDistributor' 'tradename': selectedDistributorType == 'PrincipalDistributor'
? _selectedDistributor!.shippingAddress!.tradeName ? _selectedDistributor!.shippingAddress!.tradeName
: _selectedDistributor!.tradeNameRd, : _selectedDistributor!.kyc!.tradeName,
}); });
} }
@ -180,7 +180,7 @@ class TaskProvider extends ChangeNotifier {
.map((json) => PdRdResponseModel.fromJson(json)) .map((json) => PdRdResponseModel.fromJson(json))
.toList(); .toList();
_rdList = data; _rdList = data;
print("RDTradeName ${data[0].tradeNameRd}"); print("RDTradeName ${data[0].kyc!.tradeName}");
} else { } else {
print("Failed to load data: ${response.statusCode}"); print("Failed to load data: ${response.statusCode}");
} }

View File

@ -2,6 +2,7 @@ import 'package:cheminova/models/pd_rd_response_model.dart';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/provider/product_provider.dart'; import 'package:cheminova/provider/product_provider.dart';
import 'package:cheminova/screens/data_submit_successfull.dart'; import 'package:cheminova/screens/data_submit_successfull.dart';
import 'package:cheminova/utils/string_extension.dart';
import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_app_bar.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_drawer.dart'; import 'package:cheminova/widgets/common_drawer.dart';
@ -72,7 +73,7 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
), ),
], ],
title: Text( title: Text(
widget.distributor.name!, widget.distributor.name!.capitalize(),
style: const TextStyle( style: const TextStyle(
fontSize: 20, fontSize: 20,
color: Colors.black, color: Colors.black,
@ -160,7 +161,7 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
child: ListTile( child: ListTile(
title: Text( title: Text(
filteredProducts[index] filteredProducts[index]
.name, .name.capitalize(),
style: TextStyle( style: TextStyle(
color: isAlreadySelected color: isAlreadySelected
? Colors.grey ? Colors.grey
@ -308,7 +309,7 @@ class _ProductBlockState extends State<ProductBlock> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Product: ${provider.selectedProducts[widget.index].name}', Text('Product: ${provider.selectedProducts[widget.index].name.capitalize()}',
style: const TextStyle(fontSize: 16)), style: const TextStyle(fontSize: 16)),
Text('SKU: ${provider.selectedProducts[widget.index].SKU}', Text('SKU: ${provider.selectedProducts[widget.index].SKU}',
style: const TextStyle(fontSize: 15)), style: const TextStyle(fontSize: 15)),

View File

@ -0,0 +1,463 @@
import 'package:cheminova/models/sales_task_response.dart';
import 'package:cheminova/provider/add_sales_provider.dart';
import 'package:cheminova/utils/string_extension.dart';
import 'package:cheminova/widgets/common_app_bar.dart';
import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_drawer.dart';
import 'package:cheminova/widgets/common_elevated_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class AddSalesProductScreen extends StatefulWidget {
final String distributorType;
final String tradeName;
final String pdRdId;
final String? inventoryId;
const AddSalesProductScreen(
{super.key,
required this.distributorType,
required this.tradeName,
required this.pdRdId,
this.inventoryId});
@override
State<AddSalesProductScreen> createState() => _AddSalesProductScreenState();
}
class _AddSalesProductScreenState extends State<AddSalesProductScreen> {
final searchController = TextEditingController();
late AddSalesProvider salesTaskProvider;
final dateController = TextEditingController();
final formKey = GlobalKey<FormState>();
@override
void initState() {
salesTaskProvider = Provider.of<AddSalesProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
salesTaskProvider.getTask();
});
super.initState();
}
@override
void dispose() {
if (mounted) {
salesTaskProvider.resetProducts();
}
super.dispose();
}
datePicker() async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2101),
);
if (picked != null) {
setState(
() => dateController.text = DateFormat('dd/MM/yyyy').format(picked));
}
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: true,
child: CommonBackground(
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: CommonAppBar(
actions: [
IconButton(
onPressed: () => Navigator.pop(context),
icon: Image.asset('assets/Back_attendance.png'),
padding: const EdgeInsets.only(right: 20))
],
title: Text(
'${widget.distributorType}\n${widget.tradeName.capitalize()}',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 20,
color: Colors.black,
fontWeight: FontWeight.w400,
fontFamily: 'Anek')),
backgroundColor: Colors.transparent,
elevation: 0),
drawer: const CommonDrawer(),
bottomNavigationBar: Consumer<AddSalesProvider>(
builder: (context, value, child) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Align(
alignment: value.tasksList.isEmpty
? Alignment.center
: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton.extended(
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
constraints: BoxConstraints(
maxHeight:
MediaQuery.of(context).size.height *
0.9),
context: context,
builder: (BuildContext context) {
return Consumer<AddSalesProvider>(
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: (val) {
value.filterProducts(val);
setState(() {});
})),
Expanded(
child: ListView.builder(
itemCount: searchController
.text.isEmpty
? value.tasksList.length
: value.searchList.length,
itemBuilder: (context, index) {
bool isAlreadySelected = value
.selectedProducts
.any((selectedProduct) =>
selectedProduct.SKU ==
value.tasksList[index]
.SKU);
final data = searchController
.text.isEmpty
? value.tasksList[index]
: value.searchList[index];
return Card(
child: ListTile(
title: Text(
data.ProductName
?.capitalize() ??
'',
style: TextStyle(
color: isAlreadySelected
? Colors.grey
: Colors
.black)),
subtitle: Text(
data.SKU ?? '',
style: TextStyle(
color: isAlreadySelected
? Colors.grey
: Colors
.black)),
onTap: isAlreadySelected
? null
: () {
setState(() => value
.selectedProducts
.add(data));
Navigator.pop(
context);
},
),
);
},
),
)
],
);
},
),
);
},
).whenComplete(() => setState(() {}));
},
backgroundColor: Colors.white,
icon: const Icon(Icons.add, color: Colors.black),
label: const Text('Add Products',
style: TextStyle(color: Colors.black))),
if (value.selectedProducts.isNotEmpty) ...[
const SizedBox(height: 16.0),
Consumer<AddSalesProvider>(
builder: (context, value, child) =>
CommonElevatedButton(
borderRadius: 30,
width: double.infinity,
height: kToolbarHeight - 10,
text: 'SUBMIT',
backgroundColor: const Color(0xff004791),
onPressed: () {
if (formKey.currentState!.validate()) {
if (value.selectedProducts.isNotEmpty &&
value.selectedProducts.every((product) =>
product.SKU!.isNotEmpty &&
product.ProductName!.isNotEmpty &&
product.SalesAmount != null &&
product.QuantitySold != null)) {
value.submitProducts(
distributorType: widget.distributorType,
pdRdId: widget.pdRdId,
inventoryId: widget.inventoryId,
date: dateController.text.trim(),
tradeName: widget.tradeName);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Please fill out all product details, including sale and inventory.',
),
),
);
}
}
},
),
),
]
],
),
),
),
],
),
),
body: Consumer<AddSalesProvider>(
builder: (context, value, child) {
return Stack(
children: [
Column(
children: [
GestureDetector(
onTap: () => datePicker(),
child: AbsorbPointer(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: formKey,
child: TextFormField(
controller: dateController,
validator: (value) {
if (value!.isEmpty) {
return 'Please select a date';
}
return null;
},
decoration: const InputDecoration(
labelText: 'Date',
fillColor: Colors.white,
filled: true,
border: InputBorder.none,
suffixIcon: Icon(Icons.calendar_today),
),
),
),
),
),
),
if (value.selectedProducts.isNotEmpty)
Expanded(
child: ListView.builder(
itemCount: value.selectedProducts.length,
itemBuilder: (context, index) {
return ProductBlock(
onUpdate: (updatedProduct) {
setState(() {
value.selectedProducts[index] =
updatedProduct;
});
},
onRemove: () {
setState(() {
value.selectedProducts.removeAt(index);
});
},
product: value.selectedProducts[index]);
},
),
)
],
),
(value.isLoading)
? Container(
color: Colors.black12,
child: const Center(
child: CircularProgressIndicator(),
),
)
: const SizedBox()
],
);
},
),
),
),
);
}
}
class ProductBlock extends StatefulWidget {
final SalesProduct product;
final ValueChanged<SalesProduct> onUpdate;
final VoidCallback onRemove;
const ProductBlock({
super.key,
required this.product,
required this.onUpdate,
required this.onRemove,
});
@override
State<ProductBlock> createState() => _ProductBlockState();
}
class _ProductBlockState extends State<ProductBlock> {
final saleAmountController = TextEditingController();
final quantitySoldController = TextEditingController();
final commentController = TextEditingController();
String? errorMessage;
@override
void initState() {
super.initState();
saleAmountController.text = (widget.product.SalesAmount ?? '').toString();
commentController.text = (widget.product.comments ?? '').toString();
quantitySoldController.text =
(widget.product.QuantitySold ?? '').toString();
}
void validateInput() {
setState(() {
String? quantitySoldError;
String? salesAmountError;
if (saleAmountController.text.isEmpty) {
quantitySoldError = 'Quantity sold cannot be empty.';
}
if (quantitySoldController.text.isEmpty) {
salesAmountError = 'Sales amount cannot be empty.';
}
errorMessage = null;
if (quantitySoldError == null && salesAmountError == null) {
int quantitySold = int.parse(quantitySoldController.text);
int salesAmount = int.parse(saleAmountController.text);
String comments = commentController.text;
widget.onUpdate(SalesProduct(
SKU: widget.product.SKU,
ProductName: widget.product.ProductName,
QuantitySold: quantitySold,
SalesAmount: salesAmount,
comments: comments,
));
} else {
errorMessage = quantitySoldError ?? salesAmountError;
}
});
}
@override
Widget build(BuildContext context) {
return Card(
color: Colors.white,
margin: const EdgeInsets.all(8),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.all(16),
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text('Product: ${widget.product.ProductName!.capitalize()}',
style: const TextStyle(fontSize: 16)),
Text('SKU: ${widget.product.SKU}',
style: const TextStyle(fontSize: 15)),
const SizedBox(height: 8),
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
TextField(
controller: saleAmountController,
onTapOutside: (event) => FocusScope.of(context).unfocus(),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: InputDecoration(
labelText: 'Sales amount',
errorText: saleAmountController.text.isEmpty
? 'Sales amount cannot be empty.'
: null),
keyboardType: TextInputType.number,
enabled: true,
onChanged: (_) => validateInput()),
TextField(
controller: quantitySoldController,
onTapOutside: (event) => FocusScope.of(context).unfocus(),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: InputDecoration(
labelText: 'Quantity sold',
errorText: quantitySoldController.text.isEmpty
? 'Quantity sold cannot be empty.'
: null),
keyboardType: TextInputType.number,
enabled: true,
onChanged: (_) => validateInput()),
TextField(
controller: commentController,
onTapOutside: (event) => FocusScope.of(context).unfocus(),
decoration: const InputDecoration(
labelText: 'Comments',
),
enabled: true,
onChanged: (_) => validateInput())
]),
]),
),
Positioned(
top: 0,
right: 0,
child: IconButton(
icon: const Icon(
Icons.delete_outlined,
color: Colors.red,
),
onPressed: widget.onRemove)),
],
),
);
}
}
class ProductModel {
final String sku;
final String productName;
final int? sale;
final int? inventory;
final String? comments;
final String? date;
ProductModel({
required this.sku,
required this.productName,
this.sale,
this.inventory,
this.comments,
this.date,
});
}

View File

@ -119,15 +119,15 @@ class _AssignTaskDashBoardScreenState extends State<AssignTaskDashBoardScreen> {
), ),
), ),
), ),
const SizedBox(height: 15), // const SizedBox(height: 15),
CommonElevatedButton( // CommonElevatedButton(
backgroundColor: const Color(0xff004791), // backgroundColor: const Color(0xff004791),
borderRadius: 30, // borderRadius: 30,
width: double.infinity, // width: double.infinity,
height: kToolbarHeight - 10, // height: kToolbarHeight - 10,
text: 'MANAGE SCs', // text: 'MANAGE SCs',
onPressed: () {}, // onPressed: () {},
), // ),
], ],
), ),
), ),

View File

@ -1,6 +1,7 @@
import 'package:cheminova/models/pd_rd_response_model.dart'; import 'package:cheminova/models/pd_rd_response_model.dart';
import 'package:cheminova/provider/task_provider.dart'; import 'package:cheminova/provider/task_provider.dart';
import 'package:cheminova/screens/confirm_task_screen.dart'; import 'package:cheminova/screens/confirm_task_screen.dart';
import 'package:cheminova/utils/string_extension.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_app_bar.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
@ -149,15 +150,6 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Text(
'Assign Tasks',
style: TextStyle(
fontSize: 24,
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'Anek',
),
),
const SizedBox(height: 20), const SizedBox(height: 20),
SearchField( SearchField(
suggestionsDecoration: SuggestionDecoration( suggestionsDecoration: SuggestionDecoration(
@ -166,7 +158,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
bottomRight: Radius.circular(8), bottomRight: Radius.circular(8),
), ),
border: Border.all( border: Border.all(
color: Colors.grey.withOpacity(0.5), color: Colors.white.withOpacity(0.5),
), ),
), ),
suggestionItemDecoration: BoxDecoration( suggestionItemDecoration: BoxDecoration(
@ -216,7 +208,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
(e) => SearchFieldListItem( (e) => SearchFieldListItem(
e.name!, e.name!,
item: e, item: e,
child: Text(e.name!), child: Text(e.name!.capitalize()),
), ),
) )
.toList(), .toList(),
@ -266,7 +258,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
taskProvider.setSelectedTask(value); taskProvider.setSelectedTask(value);
}, },
title: const Text( title: const Text(
"Update Sales Data Data", "Update Sales Data",
), ),
), ),
), ),
@ -321,6 +313,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
), ),
child: TextFormField( child: TextFormField(
controller: taskProvider.noteController, controller: taskProvider.noteController,
textCapitalization: TextCapitalization.sentences,
expands: true, expands: true,
maxLines: null, maxLines: null,
minLines: null, minLines: null,
@ -345,11 +338,12 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
if (taskProvider.selectedTask == if (taskProvider.selectedTask ==
'Update Inventory Data' || 'Update Inventory Data' ||
taskProvider.selectedTask == 'Visit RD/PD' || taskProvider.selectedTask == 'Visit RD/PD' ||
taskProvider.selectedTask == 'Update Sales Data') ...{ taskProvider.selectedTask ==
'Update Sales Data') ...{
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 15.0, horizontal: 5.0,
vertical: 5, vertical: 15,
), ),
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<String>(
decoration: const InputDecoration( decoration: const InputDecoration(
@ -384,7 +378,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
if (selectedDistributorType != null) if (selectedDistributorType != null)
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 15.0, vertical: 25), horizontal: 5.0, vertical: 15),
child: DropdownButtonFormField<PdRdResponseModel>( child: DropdownButtonFormField<PdRdResponseModel>(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Select Distributor Name', labelText: 'Select Distributor Name',
@ -400,7 +394,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
.map((PdRdResponseModel distributor) { .map((PdRdResponseModel distributor) {
return DropdownMenuItem<PdRdResponseModel>( return DropdownMenuItem<PdRdResponseModel>(
value: distributor, value: distributor,
child: Text(distributor.name!), child: Text(distributor.name!.capitalize()),
); );
}).toList(), }).toList(),
onChanged: (value) { onChanged: (value) {

View File

@ -1,5 +1,5 @@
import 'package:cheminova/screens/collect_kyc_screen.dart'; import 'package:cheminova/screens/collect_kyc_screen.dart';
import 'package:cheminova/screens/update_inventory_screen.dart'; import 'package:cheminova/screens/select_distributer_screen.dart';
import 'package:cheminova/screens/display_sales_screen.dart'; import 'package:cheminova/screens/display_sales_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cheminova/screens/visit_Dealers_screen.dart'; import 'package:cheminova/screens/visit_Dealers_screen.dart';
@ -61,18 +61,41 @@ class DailyTasksScreen extends StatelessWidget {
'Update Sales Data', 'Update Sales Data',
'', '',
onTap: () { onTap: () {
Navigator.push(context,MaterialPageRoute(builder: (context) => const DisplaySalesScreen(),)); Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const DisplaySalesScreen(),
));
}, },
), ),
const SizedBox(height: 5), const SizedBox(height: 5),
_buildCustomCard('Update Inventory Data', '',onTap: () { _buildCustomCard(
Navigator.push(context, MaterialPageRoute(builder: (context) => const UpdateInventoryScreen(),)); 'Update Inventory Data',
},), '',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const SelectDistributerScreen(
task: "Add Products",
),
));
},
),
const SizedBox(height: 5), const SizedBox(height: 5),
_buildCustomCard('Collect KYC Documents', '',onTap:() { _buildCustomCard(
Navigator.push(context, MaterialPageRoute( 'Collect KYC Documents',
builder: (context) => const CollectKycScreen(),)); '',
}, ), onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CollectKycScreen(),
));
},
),
], ],
), ),
), ),
@ -84,7 +107,8 @@ class DailyTasksScreen extends StatelessWidget {
); );
} }
Widget _buildCustomCard(String title, String subtitle, {void Function()? onTap}) { Widget _buildCustomCard(String title, String subtitle,
{void Function()? onTap}) {
return Container( return Container(
margin: const EdgeInsets.only(bottom: 10), margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -103,9 +127,9 @@ class DailyTasksScreen extends StatelessWidget {
), ),
subtitle: subtitle.isNotEmpty subtitle: subtitle.isNotEmpty
? Text( ? Text(
subtitle, subtitle,
style: const TextStyle(color: Colors.white70, fontSize: 13), style: const TextStyle(color: Colors.white70, fontSize: 13),
) )
: null, : null,
onTap: onTap, onTap: onTap,
), ),

View File

@ -8,8 +8,7 @@ import 'package:cheminova/screens/mark_attendence_screen.dart';
import 'package:cheminova/screens/notification_screen.dart'; import 'package:cheminova/screens/notification_screen.dart';
import 'package:cheminova/screens/products_manual_screen.dart'; import 'package:cheminova/screens/products_manual_screen.dart';
import 'package:cheminova/screens/rejected_application_screen.dart'; import 'package:cheminova/screens/rejected_application_screen.dart';
import 'package:cheminova/screens/product_sales_data.dart'; import 'package:cheminova/screens/select_distributer_screen.dart';
import 'package:cheminova/screens/update_inventory_screen.dart';
import 'package:cheminova/screens/display_sales_screen.dart'; import 'package:cheminova/screens/display_sales_screen.dart';
import 'package:cheminova/widgets/common_drawer.dart'; import 'package:cheminova/widgets/common_drawer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -119,13 +118,13 @@ class _HomePageState extends State<HomePage> {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: _buildCustomCard('Display\nSales data', child: _buildCustomCard('Collect \nKYC Data',
'Quickly display Sales\n', onTap: () { 'Scan and upload KYC Documents', onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) =>
const DisplaySalesScreen(), const CollectKycScreen(),
)); ));
}), }),
), ),
@ -139,7 +138,9 @@ class _HomePageState extends State<HomePage> {
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) =>
const UpdateInventoryScreen(), const SelectDistributerScreen(
task: "Update Inventory",
),
)); ));
}), }),
), ),
@ -152,8 +153,8 @@ class _HomePageState extends State<HomePage> {
children: [ children: [
Expanded( Expanded(
child: _buildCustomCard( child: _buildCustomCard(
'Visit RD/PD', 'Visit RD/PD\n\n',
'\n\n', '',
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
@ -169,33 +170,17 @@ class _HomePageState extends State<HomePage> {
width: 12, width: 12,
), ),
Expanded( Expanded(
child: _buildCustomCard( child: _buildCustomCard('Update\nSales Data\n', '',
'Product\nSales Data Visibility', '',
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) =>
const ProductSalesData(), const SelectDistributerScreen(
)); task: "Update Sales",
}), ),
), ),
], );
),
const SizedBox(
height: 5,
),
Row(
children: [
Expanded(
child: _buildCustomCard('Collect \nKYC Data',
'Scan and upload KYC Documents', onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const CollectKycScreen(),
));
}), }),
), ),
], ],
@ -271,10 +256,6 @@ class _HomePageState extends State<HomePage> {
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
TextButton(
onPressed: () => throw Exception(),
child: const Text("Throw Test Exception"),
),
], ],
), ),
), ),

View File

@ -94,81 +94,83 @@ class MyListView extends StatelessWidget {
RejectedApplicationResponse item = value.rejectedApplicationList[index]; RejectedApplicationResponse item = value.rejectedApplicationList[index];
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 10, left: 10, right: 10), padding: const EdgeInsets.only(bottom: 10, left: 10, right: 10),
child: ExpansionTile( child: ClipRRect(
collapsedBackgroundColor: Colors.white, borderRadius: BorderRadius.circular(15), // Rounded corner
backgroundColor: Colors.white, child: ExpansionTile(
title: Text( collapsedBackgroundColor: Colors.white,
item.tradeName ?? '', backgroundColor: Colors.white,
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500), title: Text(
), item.tradeName ?? '',
subtitle: Column( style:
crossAxisAlignment: CrossAxisAlignment.start, const TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
children: [ ),
Text((DateFormat("dd MMMM yyyy") subtitle: Column(
.format(DateTime.parse(item.createdAt ?? '')))), crossAxisAlignment: CrossAxisAlignment.start,
Text(item.sId ?? ''), children: [
for (var note in item.notes!) Text(note.message ?? ''), Text((DateFormat("dd MMMM yyyy")
.format(DateTime.parse(item.createdAt ?? '')))),
Text("ID:${item.sId ?? ''}"),
for (var note in item.notes!) Text(note.message ?? ''),
],
),
children: <Widget>[
ListTile(
title: Text('Address: ${item.address ?? ''}'),
),
ListTile(
title: Text('City: ${item.city ?? ''}'),
),
ListTile(
title: Text('State: ${item.state ?? ''}'),
),
ListTile(
title: Text('Pincode: ${item.pincode ?? ''}'),
),
ListTile(
title: Text('Mobile: ${item.mobileNumber ?? ''}'),
),
ListTile(
title: Text('Status: ${item.status ?? ''}'),
),
ListTile(
title: Text(
'Principal Distributor: ${item.principalDistributer!.name ?? ''}'),
),
ListTile(
title: Text('PAN Number: ${item.panNumber ?? ''}'),
),
Image.network(item.panImg!.url ?? '', height: 250, width: 250),
ListTile(
title: Text('Aadhar Number: ${item.aadharNumber ?? ''}'),
),
Image.network(item.aadharImg?.url ?? '',
height: 250, width: 250),
ListTile(
title: Text('GST Number: ${item.gstNumber ?? ''}'),
),
Image.network(item.gstImg!.url ?? '', height: 250, width: 250),
const ListTile(
title: Text('Pesticide License: '),
),
if (item.pesticideLicenseImg != null)
Image.network(item.pesticideLicenseImg!.url ?? '',
height: 250, width: 250),
const ListTile(
title: Text('selfieEntranceImg: '),
),
Image.network(item.selfieEntranceImg!.url ?? '',
height: 250, width: 250),
const ListTile(
title: Text('Notes:'),
),
if (item.notes != null)
for (var note in item.notes!)
ListTile(
contentPadding: const EdgeInsets.only(left: 20),
title: Text(note.message ?? ''),
),
], ],
), ),
children: <Widget>[
ListTile(
title: Text('Address: ${item.address ?? ''}'),
),
ListTile(
title: Text('City: ${item.city ?? ''}'),
),
ListTile(
title: Text('State: ${item.state ?? ''}'),
),
ListTile(
title: Text('Pincode: ${item.pincode ?? ''}'),
),
ListTile(
title: Text('Mobile: ${item.mobileNumber ?? ''}'),
),
ListTile(
title: Text('Status: ${item.status ?? ''}'),
),
ListTile(
title: Text(
'Principal Distributor: ${item.principalDistributer!.name ?? ''}'),
),
ListTile(
title: Text('PAN Number: ${item.panNumber ?? ''}'),
),
Image.network(item.panImg!.url ?? '', height: 250, width: 250),
ListTile(
title: Text('Aadhar Number: ${item.aadharNumber ?? ''}'),
),
Image.network(item.aadharImg?.url ?? '', height: 250, width: 250),
ListTile(
title: Text('GST Number: ${item.gstNumber ?? ''}'),
),
Image.network(item.gstImg!.url ?? '', height: 250, width: 250),
const ListTile(
title: Text('Pesticide License: '),
),
if (item.pesticideLicenseImg != null)
Image.network(item.pesticideLicenseImg!.url ?? '',
height: 250, width: 250),
// if (item['fertilizer_license_img'] != null)
// Image.network(item['fertilizer_license_img']['url'] ?? ''),
const ListTile(
title: Text('selfieEntranceImg: '),
),
Image.network(item.selfieEntranceImg!.url ?? '',
height: 250, width: 250),
const ListTile(
title: Text('Notes:'),
),
if (item.notes != null)
for (var note in item.notes!)
ListTile(
contentPadding: const EdgeInsets.only(left: 20),
title: Text(note.message ?? ''),
),
],
), ),
); );
}, },

View File

@ -45,6 +45,7 @@ class RetailerDetailsScreenState extends State<RetailerDetailsScreen> {
children: <Widget>[ children: <Widget>[
CommonTextFormField( CommonTextFormField(
title: 'Trade Name', title: 'Trade Name',
textCapitalization: TextCapitalization.words,
fillColor: Colors.white, fillColor: Colors.white,
validator: (String? value) { validator: (String? value) {
if (value!.isEmpty) { if (value!.isEmpty) {
@ -56,6 +57,7 @@ class RetailerDetailsScreenState extends State<RetailerDetailsScreen> {
const SizedBox(height: 15), const SizedBox(height: 15),
CommonTextFormField( CommonTextFormField(
title: 'Name', title: 'Name',
textCapitalization: TextCapitalization.words,
fillColor: Colors.white, fillColor: Colors.white,
validator: (String? value) { validator: (String? value) {
if (value!.isEmpty) { if (value!.isEmpty) {
@ -65,6 +67,19 @@ class RetailerDetailsScreenState extends State<RetailerDetailsScreen> {
}, },
controller: value.nameController), controller: value.nameController),
const SizedBox(height: 15), const SizedBox(height: 15),
CommonTextFormField(
title: 'Email',
textCapitalization: TextCapitalization.none,
keyboardType: TextInputType.emailAddress,
fillColor: Colors.white,
validator: (String? value) {
if (value!.isEmpty) {
return 'Email cannot be empty';
}
return null;
},
controller: value.emailController),
const SizedBox(height: 15),
CommonTextFormField( CommonTextFormField(
title: 'Address', title: 'Address',
fillColor: Colors.white, fillColor: Colors.white,
@ -110,6 +125,7 @@ class RetailerDetailsScreenState extends State<RetailerDetailsScreen> {
CommonTextFormField( CommonTextFormField(
maxLength: 6, maxLength: 6,
title: 'Pincode', title: 'Pincode',
keyboardType: TextInputType.number,
fillColor: Colors.white, fillColor: Colors.white,
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.digitsOnly FilteringTextInputFormatter.digitsOnly
@ -125,6 +141,7 @@ class RetailerDetailsScreenState extends State<RetailerDetailsScreen> {
CommonTextFormField( CommonTextFormField(
maxLength: 10, maxLength: 10,
title: 'Mobile Number', title: 'Mobile Number',
keyboardType: TextInputType.number,
fillColor: Colors.white, fillColor: Colors.white,
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.digitsOnly FilteringTextInputFormatter.digitsOnly
@ -140,6 +157,7 @@ class RetailerDetailsScreenState extends State<RetailerDetailsScreen> {
CommonTextFormField( CommonTextFormField(
maxLength: 12, maxLength: 12,
title: 'Aadhar Number', title: 'Aadhar Number',
keyboardType: TextInputType.number,
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.digitsOnly FilteringTextInputFormatter.digitsOnly
], ],

View File

@ -1,6 +1,8 @@
import 'package:cheminova/models/pd_rd_response_model.dart'; import 'package:cheminova/models/pd_rd_response_model.dart';
import 'package:cheminova/provider/pd_rd_provider.dart'; import 'package:cheminova/provider/pd_rd_provider.dart';
import 'package:cheminova/screens/add_products_screen.dart'; import 'package:cheminova/screens/add_products_screen.dart';
import 'package:cheminova/screens/add_sales_products_screen.dart';
import 'package:cheminova/utils/string_extension.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';
@ -8,14 +10,16 @@ import 'package:cheminova/widgets/common_elevated_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class UpdateInventoryScreen extends StatefulWidget { class SelectDistributerScreen extends StatefulWidget {
const UpdateInventoryScreen({super.key}); final String task;
const SelectDistributerScreen({super.key, required this.task});
@override @override
State<UpdateInventoryScreen> createState() => _UpdateInventoryScreenState(); State<SelectDistributerScreen> createState() =>
_SelectDistributerScreenState();
} }
class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> { class _SelectDistributerScreenState extends State<SelectDistributerScreen> {
String? selectedDistributorType; String? selectedDistributorType;
PdRdResponseModel? selectedDistributor; PdRdResponseModel? selectedDistributor;
@ -45,7 +49,7 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
), ),
], ],
title: const Text( title: const Text(
'Update Inventory Data', 'Select Distributor',
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
color: Colors.black, color: Colors.black,
@ -69,18 +73,35 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
selectedDistributorType == null) { selectedDistributorType == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( const SnackBar(
content: Text( content:
'Please select distributor type and distributor')), Text('Please select distributor type and distributor'),
),
); );
} else { } else {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(builder: (context) {
builder: (context) => AddProductsScreen( if (widget.task == 'Update Inventory') {
distributor: selectedDistributor!, return AddProductsScreen(
distributorType: selectedDistributorType!, distributor: selectedDistributor!,
), distributorType: selectedDistributorType!,
), );
} else if (widget.task == 'Update Sales') {
return AddSalesProductScreen(
distributorType:
selectedDistributorType == 'Principal Distributor'
? 'PrincipalDistributor'
: 'RetailDistributor',
tradeName: selectedDistributorType ==
'Principal Distributor'
? selectedDistributor!.shippingAddress!.tradeName
: selectedDistributor!.kyc!.tradeName,
pdRdId: selectedDistributor!.id!,
);
} else {
return Container();
}
}),
); );
} }
}, },
@ -143,7 +164,7 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
.map((PdRdResponseModel distributor) { .map((PdRdResponseModel distributor) {
return DropdownMenuItem<PdRdResponseModel>( return DropdownMenuItem<PdRdResponseModel>(
value: distributor, value: distributor,
child: Text(distributor.name!), child: Text(distributor.name!.capitalize()),
); );
}).toList(), }).toList(),
onChanged: (value) { onChanged: (value) {

View File

@ -198,7 +198,7 @@ class _TaskManagementScreenState extends State<TaskManagementScreen> {
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: Colors.white), border: Border.all(color: Colors.white),
color: const Color(0xffB4D1E5).withOpacity(0.6), color: const Color(0xffB4D1E5).withOpacity(0.8),
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16.0),
), ),
child: child, child: child,
@ -220,21 +220,38 @@ class _TaskManagementScreenState extends State<TaskManagementScreen> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 5),
Text( Text(
"Task: ${task.task}", "Task: ${task.task}",
style: const TextStyle( style: const TextStyle(
fontFamily: 'Anek', fontFamily: 'Anek',
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 5),
if (task.addedFor != null) ...{
task.addedFor == 'PrincipalDistributor'
? Text(
"PD: ${task.tradename}",
)
: Text("RD: ${task.tradename}"),
const SizedBox(height: 5),
},
Text( Text(
'Status: ${task.taskStatus}', 'Status: ${task.taskStatus}',
style: const TextStyle( style: const TextStyle(
fontFamily: 'Anek', fontFamily: 'Anek',
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 5),
if (task.note != null) ...{
Text(
'Note: ${task.note}',
style: const TextStyle(
fontFamily: 'Anek',
),
),
const SizedBox(height: 5),
},
Text( Text(
'Deadline:$formatedDate', 'Deadline:$formatedDate',
style: const TextStyle( style: const TextStyle(

View File

@ -28,6 +28,7 @@ class VerifyDocumentsScreen extends StatelessWidget {
{ {
'Trade Name': value.tradeNameController.text, 'Trade Name': value.tradeNameController.text,
'Name': value.nameController.text, 'Name': value.nameController.text,
'Email': value.emailController.text,
'Address': value.addressController.text, 'Address': value.addressController.text,
'Town/City': value.city.text, 'Town/City': value.city.text,
'District': value.districtController.text, 'District': value.districtController.text,

View File

@ -1,5 +1,6 @@
class ApiUrls { class ApiUrls {
static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/'; // static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/';
static const String baseUrl = 'https://api.cnapp.co.in/api/';
static const String loginUrl = 'territorymanager/login'; static const String loginUrl = 'territorymanager/login';
static const String profileUrl = 'territorymanager/my-profile'; static const String profileUrl = 'territorymanager/my-profile';
static const String markAttendanceUrl = 'v1/markattendance/territorymanager'; static const String markAttendanceUrl = 'v1/markattendance/territorymanager';
@ -19,5 +20,7 @@ class ApiUrls {
static const String assignTask = 'task/assign-task'; static const String assignTask = 'task/assign-task';
static const String getProductsManual = 'productmanual/getall'; static const String getProductsManual = 'productmanual/getall';
static const String getAllTasks = 'task/alltasks/'; static const String getAllTasks = 'task/alltasks/';
static const String salesTaskUrl = '${baseUrl}product/getAll/user/';
static const String postSalesTaskUrl = '${baseUrl}sales/add-TM';
static const String updateTaskInventoryUrl = ''; static const String updateTaskInventoryUrl = '';
} }

View File

@ -0,0 +1,5 @@
extension StringExtension on String {
String capitalize() {
return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
}
}

View File

@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
class CommonTextFormField extends StatelessWidget { class CommonTextFormField extends StatelessWidget {
final String title; final String title;
final TextEditingController? controller; final TextEditingController? controller;
final TextCapitalization textCapitalization;
final String? Function(String?)? validator; final String? Function(String?)? validator;
final Color? fillColor; final Color? fillColor;
final bool? readOnly; final bool? readOnly;
@ -28,6 +29,7 @@ class CommonTextFormField extends StatelessWidget {
this.inputFormatters, this.inputFormatters,
this.maxLength, this.maxLength,
this.onChanged, this.onChanged,
this.textCapitalization = TextCapitalization.sentences,
this.obscureText = false, this.obscureText = false,
}); });
@ -44,6 +46,7 @@ class CommonTextFormField extends StatelessWidget {
// fontFamily: 'Anek')), // fontFamily: 'Anek')),
TextFormField( TextFormField(
controller: controller, controller: controller,
textCapitalization: textCapitalization,
readOnly: readOnly ?? false, readOnly: readOnly ?? false,
maxLines: maxLines, maxLines: maxLines,
maxLength: maxLength, maxLength: maxLength,