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:provider/provider.dart'; import '../provider/products_provider.dart'; class AddProductsScreen extends StatefulWidget { final String distributorType; final String tradeName; final String pdRdId; final String? inventoryId; const AddProductsScreen({ super.key, required this.distributorType, required this.tradeName, required this.pdRdId, this.inventoryId }); @override State createState() => _AddProductsScreenState(); } class _AddProductsScreenState extends State { final searchController = TextEditingController(); late ProductProvider productProvider; @override void initState() { productProvider = Provider.of(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { productProvider.getProducts(); }); super.initState(); } @override void dispose() { if (mounted) { productProvider.resetProducts(); } super.dispose(); } @override Widget build(BuildContext context) { return 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.selectedProducts.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.productList.length : value.searchList.length, itemBuilder: (context, index) { bool isAlreadySelected = value.selectedProducts.any( (selectedProduct) => selectedProduct.sku == value.productList[index].sku ); final data = searchController.text.isEmpty ? value.productList[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 (value.selectedProducts.isNotEmpty && value.selectedProducts.every((product) => product.sku.isNotEmpty && product.productName.isNotEmpty && product.sale != null && product.inventory != null)) { value.submitProducts( distributorType: widget.distributorType, pdRdId: widget.pdRdId, inventoryId: widget.inventoryId! ); } 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: [ if (value.selectedProducts.isNotEmpty) Expanded( child: ListView.builder( itemCount: value.selectedProducts.length, itemBuilder: (context, index) { return ProductBlock( onUpdate: (updatedProduct) { debugPrint('selected productt le ${value.selectedProducts.length}'); 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 ProductModel 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 saleController = TextEditingController(); final inventoryController = TextEditingController(); String? errorMessage; @override void initState() { super.initState(); saleController.text = (widget.product.sale ?? '').toString(); inventoryController.text = (widget.product.inventory ?? '').toString(); } void validateInput() { setState(() { String? saleError; String? inventoryError; if (saleController.text.isEmpty) { saleError = 'Sale cannot be empty.'; } if (inventoryController.text.isEmpty) { inventoryError = 'Inventory cannot be empty.'; } errorMessage = null; if (saleError == null && inventoryError == null) { int sale = int.parse(saleController.text); int inventory = int.parse(inventoryController.text); widget.onUpdate(ProductModel( sku: widget.product.sku, productName: widget.product.productName, sale: sale, inventory: inventory, )); } else { errorMessage = saleError ?? inventoryError; } }); } @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: saleController, onTapOutside: (event) => FocusScope.of(context).unfocus(), inputFormatters: [FilteringTextInputFormatter.digitsOnly], decoration: InputDecoration( labelText: 'Sale', errorText: saleController.text.isEmpty ? 'Sale cannot be empty.' : null ), keyboardType: TextInputType.number, enabled: true, onChanged: (_) => validateInput() ), TextField( controller: inventoryController, onTapOutside: (event) => FocusScope.of(context).unfocus(), inputFormatters: [FilteringTextInputFormatter.digitsOnly], decoration: InputDecoration( labelText: 'Inventory', errorText: inventoryController.text.isEmpty ? 'Inventory cannot be empty.' : null ), keyboardType: TextInputType.number, enabled: true, onChanged: (_) => validateInput() ) ] ) ] ), ), Positioned( top: 4, right: 4, child: IconButton( icon: const Icon(Icons.delete_outline, color: Colors.red), onPressed: widget.onRemove, ), ), ], ) ); } }