diff --git a/lib/main.dart b/lib/main.dart index d6b9315..6f42cbe 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'dart:io'; import 'package:cheminova/constants/constant.dart'; +import 'package:cheminova/provider/add_sales_product_provider.dart'; import 'package:cheminova/provider/home_provider.dart'; import 'package:cheminova/provider/products_provider.dart'; import 'package:cheminova/screens/splash_screen.dart'; @@ -92,6 +93,7 @@ Future main() async { runApp(MultiProvider(providers: [ ChangeNotifierProvider(create: (context) => HomeProvider()), ChangeNotifierProvider(create: (context) => ProductProvider()), + ChangeNotifierProvider(create: (context) => AddSalesProvider()), ], child: const MyApp())); } diff --git a/lib/models/SalesTaskResponse.dart b/lib/models/SalesTaskResponse.dart new file mode 100644 index 0000000..6f62f76 --- /dev/null +++ b/lib/models/SalesTaskResponse.dart @@ -0,0 +1,173 @@ +class SalesTaskResponse { + bool? success; + int? totalData; + int? totalPages; + List? products; + + SalesTaskResponse( + {this.success, this.totalData, this.totalPages, this.products}); + + SalesTaskResponse.fromJson(Map json) { + success = json['success']; + totalData = json['total_data']; + totalPages = json['total_pages']; + if (json['products'] != null) { + products = []; + json['products'].forEach((v) { + products!.add(SalesProduct.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + 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? image; + String? createdAt; + String? updatedAt; + int? SalesAmount; + int? QuantitySold; + 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.SalesAmount, + this.iV}); + + SalesProduct.fromJson(Map 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 toJson() { + final Map data = {}; + 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 json) { + sId = json['_id']; + categoryName = json['categoryName']; + } + + Map toJson() { + final Map data = {}; + data['_id'] = sId; + data['categoryName'] = categoryName; + return data; + } +} + +class Brand { + String? sId; + String? brandName; + + Brand({this.sId, this.brandName}); + + Brand.fromJson(Map json) { + sId = json['_id']; + brandName = json['brandName']; + } + + Map toJson() { + final Map data = {}; + data['_id'] = sId; + data['brandName'] = brandName; + return data; + } +} + +class AddedBy { + String? sId; + String? name; + + AddedBy({this.sId, this.name}); + + AddedBy.fromJson(Map json) { + sId = json['_id']; + name = json['name']; + } + + Map toJson() { + final Map data = {}; + data['_id'] = sId; + data['name'] = name; + return data; + } +} diff --git a/lib/provider/add_sales_product_provider.dart b/lib/provider/add_sales_product_provider.dart new file mode 100644 index 0000000..986483e --- /dev/null +++ b/lib/provider/add_sales_product_provider.dart @@ -0,0 +1,126 @@ +import 'dart:convert'; + +import 'package:cheminova/constants/constant.dart'; +import 'package:cheminova/models/SalesTaskResponse.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 tasksList = []; + List searchList = []; + + bool _isLoading = false; + + bool get isLoading => _isLoading; + + List selectedProducts = []; + + void setLoading(bool loading) { + _isLoading = loading; + notifyListeners(); + } + + Future 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 submitProducts( + {required String distributorType, + required String pdRdId, + required String date, + required String comments, + 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, + "comments": comments, + "products": selectedProducts.map((product) { + return { + "SKU": product.SKU, + "ProductName": product.ProductName, + "QuantitySold": product.QuantitySold, + "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 DataSubmitSuccessFullScreen())); + } else { + ScaffoldMessenger.of( + navigatorKey.currentContext!, + ).showSnackBar( + const SnackBar(content: Text('Task not updated')), + ); + } + }); + } else { + resetProducts(); + Navigator.push( + navigatorKey.currentContext!, + MaterialPageRoute( + builder: (context) => const DataSubmitSuccessFullScreen())); + } + } + } catch (e) { + setLoading(false); + debugPrint("Error: $e"); + } + } + + void resetProducts() { + selectedProducts.clear(); + tasksList.clear(); + notifyListeners(); + } +} diff --git a/lib/provider/products_provider.dart b/lib/provider/products_provider.dart index 44f10fa..eba1dba 100644 --- a/lib/provider/products_provider.dart +++ b/lib/provider/products_provider.dart @@ -127,6 +127,8 @@ class ProductModel { inventory: json['Inventory']); } + get comments => null; + Map toJson() { return { 'SKU': sku, diff --git a/lib/provider/select_task_provider.dart b/lib/provider/select_task_provider.dart index c0f9dac..e4f80db 100644 --- a/lib/provider/select_task_provider.dart +++ b/lib/provider/select_task_provider.dart @@ -29,8 +29,8 @@ class SelectTaskProvider extends ChangeNotifier { Response response = await _apiClient.get(ApiUrls.kycSelectTaskUrl); setLoading(false); if (response.statusCode == 200) { - final data = SelectTaskKycResponse.fromJson(response.data); - tasksList = data.tasks ?? []; + final data = SelectTaskKycResponse.fromJson(response.data); + tasksList = data.tasks ?? []; notifyListeners(); } } catch (e) { diff --git a/lib/screens/Add_products_screen.dart b/lib/screens/Add_products_screen.dart index c89bccd..983d3eb 100644 --- a/lib/screens/Add_products_screen.dart +++ b/lib/screens/Add_products_screen.dart @@ -40,7 +40,7 @@ class _AddProductsScreenState extends State { @override void dispose() { - if (mounted) { + if (context.mounted) { productProvider.resetProducts(); } super.dispose(); diff --git a/lib/screens/add_sales_product_screen.dart b/lib/screens/add_sales_product_screen.dart new file mode 100644 index 0000000..87fc116 --- /dev/null +++ b/lib/screens/add_sales_product_screen.dart @@ -0,0 +1,428 @@ +import 'package:cheminova/models/SalesTaskResponse.dart'; +import 'package:cheminova/provider/add_sales_product_provider.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 createState() => _AddSalesProductScreenState(); +} + +class _AddSalesProductScreenState extends State { + final searchController = TextEditingController(); + late AddSalesProvider salesTaskProvider; + final dateController = TextEditingController(); + final commentController = TextEditingController(); + final formKey = GlobalKey(); + + @override + void initState() { + salesTaskProvider = Provider.of(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}', + 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( + 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( + 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 ?? '', 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( + 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(), + comments: + commentController + .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(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), + ), + ), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + controller: commentController, + decoration: const InputDecoration( + fillColor: Colors.white, + filled: true, + border: InputBorder.none, + labelText: 'Comments'), + maxLines: 1), + ), + 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 onUpdate; + final VoidCallback onRemove; + + const ProductBlock({ + super.key, + required this.product, + required this.onUpdate, + required this.onRemove, + }); + + @override + State createState() => _ProductBlockState(); +} + +class _ProductBlockState extends State { + final saleAmountController = TextEditingController(); + final quantitySoldController = TextEditingController(); + String? errorMessage; + + @override + void initState() { + super.initState(); + saleAmountController.text = (widget.product.SalesAmount ?? '').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); + + widget.onUpdate(SalesProduct( + SKU: widget.product.SKU, + ProductName: widget.product.ProductName, + QuantitySold: quantitySold, + SalesAmount: salesAmount, + )); + } 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}', + 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()) + ]), + ]), + ), + 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, + }); +} diff --git a/lib/screens/daily_tasks_screen.dart b/lib/screens/daily_tasks_screen.dart index 67891a0..c14a332 100644 --- a/lib/screens/daily_tasks_screen.dart +++ b/lib/screens/daily_tasks_screen.dart @@ -1,8 +1,9 @@ import 'package:cheminova/models/Daily_Task_Response.dart'; import 'package:cheminova/screens/Add_products_screen.dart'; +import 'package:cheminova/screens/sales_task_screen.dart'; import 'package:flutter/material.dart'; import 'package:cheminova/screens/visit_rd_pd_screen.dart'; -import 'package:cheminova/screens/display_sales_screen.dart'; +import 'package:cheminova/screens/update_sales_screen.dart'; import 'package:cheminova/screens/update_inventory_screen.dart'; import 'package:cheminova/screens/collect_kyc_screen.dart'; import 'package:cheminova/widgets/common_app_bar.dart'; @@ -211,7 +212,7 @@ class _DailyTasksScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => const DisplaySalesScreen())); + builder: (context) => UpdateSalesScreen(String: null,))); } else if (tasksList.task == 'Visit RD/PD') { Navigator.push( context, diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 6448861..57d9f1c 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -6,13 +6,13 @@ import 'package:cheminova/screens/rejected_application_screen.dart'; import 'package:cheminova/screens/calendar_screen.dart'; import 'package:cheminova/screens/collect_kyc_screen.dart'; import 'package:cheminova/screens/daily_tasks_screen.dart'; -import 'package:cheminova/screens/display_sales_screen.dart'; +import 'package:cheminova/screens/sales_task_screen.dart'; +import 'package:cheminova/screens/update_sales_screen.dart'; import 'package:cheminova/screens/mark_attendence_screen.dart'; import 'package:cheminova/screens/notification_screen.dart'; import 'package:cheminova/screens/product_sales_data.dart'; import 'package:cheminova/screens/products_manual_screen.dart'; import 'package:cheminova/screens/select_taskkyc_screen.dart'; -import 'package:cheminova/screens/summary_screen.dart'; import 'package:cheminova/screens/update_inventory_screen.dart'; import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_background.dart'; @@ -124,7 +124,7 @@ class _HomePageState extends State { context, MaterialPageRoute( builder: (context) => - const DisplaySalesScreen(), + SalesTaskScreen() ), ); }, diff --git a/lib/screens/sales_task_screen.dart b/lib/screens/sales_task_screen.dart new file mode 100644 index 0000000..92239c3 --- /dev/null +++ b/lib/screens/sales_task_screen.dart @@ -0,0 +1,141 @@ +import 'package:cheminova/screens/add_sales_product_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:cheminova/models/Daily_Task_Response.dart'; +import 'package:cheminova/widgets/common_app_bar.dart'; +import 'package:cheminova/widgets/common_background.dart'; +import 'package:cheminova/widgets/common_drawer.dart'; +import '../constants/constant.dart'; +import '../provider/daily_task_provider.dart'; + +class SalesTaskScreen extends StatefulWidget { + const SalesTaskScreen({super.key}); + + @override + _SalesTaskScreenState createState() => _SalesTaskScreenState(); +} + +class _SalesTaskScreenState extends State { + late DailyTaskProvider _dailyTaskProvider; + + @override + void initState() { + super.initState(); + _dailyTaskProvider = DailyTaskProvider(); + _dailyTaskProvider.getTask(type: 'New'); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => _dailyTaskProvider, + child: Scaffold( + extendBodyBehindAppBar: true, + appBar: _buildAppBar(), + drawer: const CommonDrawer(), + body: CommonBackground( + child: SafeArea( + child: _buildTaskList(), + ), + ), + ), + ); + } + + CommonAppBar _buildAppBar() { + return CommonAppBar( + backgroundColor: Colors.transparent, + elevation: 0, + actions: [ + IconButton( + onPressed: () => Navigator.pop(context), + icon: Image.asset('assets/Back_attendance.png'), + padding: const EdgeInsets.only(right: 20), + ), + ], + title: const Text( + 'Sales Tasks', + style: TextStyle(color: Colors.black87, fontSize: 20), + ), + ); + } + + Widget _buildTaskList() { + return Consumer( + builder: (context, value, child) { + if (value.isLoading) { + return const Center(child: CircularProgressIndicator()); + } + + final salesTasks = value.newTasksList + .where((task) => task.task?.toLowerCase() == 'Update Sales Data'.toLowerCase()) + .toList(); + + if (salesTasks.isEmpty) { + return const Center( + child: Text( + 'NO TASK', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ); + } + + return ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: salesTasks.length, + separatorBuilder: (context, index) => const SizedBox(height: 8), + itemBuilder: (context, index) => _buildTaskCard(salesTasks[index]), + ); + }, + ); + } + + Widget _buildTaskCard(Tasks tasksList) { + return InkWell( + onTap: () { + if (tasksList.sId != null && tasksList.addedFor != null) { + Navigator.push( + navigatorKey.currentContext!, + MaterialPageRoute( + builder: (context) => AddSalesProductScreen( + distributorType: tasksList.addedFor!, + inventoryId: tasksList.sId, + tradeName: tasksList.tradeName ?? '', + pdRdId: tasksList.addedForId!))); + } + }, + child: Card( + color: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + child: ListTile( + leading: const Icon(Icons.attach_money, color: Colors.greenAccent), + title: Text( + tasksList.task ?? '', + style: const TextStyle( + color: Colors.black87, + fontWeight: FontWeight.w700, + fontSize: 16, + fontFamily: 'Anek', + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Distributor: ${tasksList.addedFor ?? ""}'), + Text('Trader Name: ${tasksList.tradeName ?? ''}'), + if (tasksList.taskDueDate != null) + Text('Due Date: ${DateFormat('dd/MM/yyyy').format(DateTime.parse(tasksList.taskDueDate!))}'), + Text('Priority: ${tasksList.taskPriority}'), + ], + ), + trailing: const Icon(Icons.arrow_forward_ios, color: Colors.black87), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/display_sales_screen.dart b/lib/screens/update_sales_screen.dart similarity index 95% rename from lib/screens/display_sales_screen.dart rename to lib/screens/update_sales_screen.dart index 8167bab..42d6ce6 100644 --- a/lib/screens/display_sales_screen.dart +++ b/lib/screens/update_sales_screen.dart @@ -6,14 +6,15 @@ import 'package:intl/intl.dart'; import '../widgets/common_app_bar.dart'; import '../widgets/common_elevated_button.dart'; import '../widgets/common_text_form_field.dart'; -class DisplaySalesScreen extends StatefulWidget { - const DisplaySalesScreen({super.key}); +class UpdateSalesScreen extends StatefulWidget { + const UpdateSalesScreen({super.key, required String}); @override - State createState() => DisplaySalesScreenState(); + State createState() => UpdateSalesScreenState(); + } -class DisplaySalesScreenState extends State { +class UpdateSalesScreenState extends State { final dateController = TextEditingController( text: DateFormat('dd/MM/yyyy').format(DateTime.now())); diff --git a/lib/services/api_urls.dart b/lib/services/api_urls.dart index 4d11778..ad27bd7 100644 --- a/lib/services/api_urls.dart +++ b/lib/services/api_urls.dart @@ -21,4 +21,6 @@ class ApiUrls { static const String kycSelectTaskUrl = '${baseUrl}task/task/type/Collect KYC'; static const String updateTaskInventoryUrl = '${baseUrl}task/update-task-status/'; static const String getProductsManual = '${baseUrl}productmanual/getall'; + static const String salesTaskUrl = '${baseUrl}product/getAll/user/?category=Bottle'; + static const String postSalesTaskUrl = '${baseUrl}sales/add-SC'; }