diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 4b07884..249356b 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -326,6 +326,9 @@ "box.package_size":"Package", "box.select.cartion":"Select cartons", "box.no_carton":"There is no cartons in this shipment.", + "box.crete.carton":"Create carton", + "box.carton.type":"Carton Type", + "box.select.delivery":"Select delivery type", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index e623fa8..ae37fa0 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -325,6 +325,9 @@ "box.package_size":"Package", "box.select.cartion":"Select cartons", "box.no_carton":"There is no cartons in this shipment.", + "box.crete.carton":"Create carton", + "box.carton.type":"Carton Type", + "box.select.delivery":"Select delivery type", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/lib/domain/entities/cargo_type.dart b/lib/domain/entities/cargo_type.dart index 0e165ea..fe34be9 100644 --- a/lib/domain/entities/cargo_type.dart +++ b/lib/domain/entities/cargo_type.dart @@ -5,7 +5,7 @@ class CargoType { double weight; bool isChecked; int qty; - bool? isCutomDuty; + bool isCutomDuty; double customDutyFee; double calRate; double calWeight; @@ -21,7 +21,7 @@ class CargoType { this.calRate = 0, this.isChecked = false, this.qty = 0, - this.isCutomDuty, + this.isCutomDuty = false, this.customDutyFee = 0}); factory CargoType.fromMap(Map map, String id) { diff --git a/lib/pages/carton/carton_editor.dart b/lib/pages/carton/carton_editor.dart index 8998c6e..22b178a 100644 --- a/lib/pages/carton/carton_editor.dart +++ b/lib/pages/carton/carton_editor.dart @@ -14,7 +14,9 @@ import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; -import 'mix_cation/mix_cartion_editor.dart'; +import '../main/util.dart'; +import 'carton_editor_for_package.dart'; +import 'mix_carton/mix_carton_editor.dart'; import 'carton_row.dart'; class CartonEditor extends StatefulWidget { @@ -26,7 +28,7 @@ class CartonEditor extends StatefulWidget { } class _CartonEditorState extends State { - List cartonTypes = [carton_from_packages, carton_mix_carton]; + List _cartonTypes = [carton_from_packages, carton_mix_carton]; List _cartons = []; bool _isLoading = false; @@ -34,23 +36,26 @@ class _CartonEditorState extends State { int _billToValue = 1; String? _selectedCartonType; - User? consignee; - User? sender; + User? _consignee; + User? _sender; Carton? _carton; @override void initState() { + _init(); super.initState(); + } + _init() { if (widget.carton != null) { _carton = widget.carton; _selectedCartonType = _carton!.cartonType; _isNew = false; - consignee = User( + _consignee = User( id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); - sender = User( + _sender = User( id: _carton!.senderID, fcsID: _carton!.senderFCSID, name: _carton!.senderName); @@ -62,6 +67,20 @@ class _CartonEditorState extends State { Carton(cartonNumber: "A177(A)-3#2", cartonWeight: 35.5), Carton(cartonNumber: "A177(A)-3#1", cartonWeight: 25.5) ]; + _sender = User( + name: "ptd-phyo44 kaelone", + fcsID: "FCS-8X6V", + phoneNumber: "+959444444444", + id: "48u_4s-HiQeW-HwSqeRd9TSMWh3mLZfSk5rpaUEh_zw"); + + _consignee = User( + id: "HsIwG88K-0_HSazgEy5QR27kcjkOvfv7_Sr1JP18Q1A", + name: "One One", + phoneNumber: "+959111111111", + fcsID: "FCS-EFRF"); + } + if (mounted) { + setState(() {}); } } @@ -107,7 +126,7 @@ class _CartonEditorState extends State { final cartonTypeBox = LocalRadioButtons( readOnly: !_isNew, - values: cartonTypes, + values: _cartonTypes, selectedValue: _selectedCartonType, callback: (String? v) { setState(() { @@ -125,6 +144,22 @@ class _CartonEditorState extends State { onTap: () { //for packages if (isFromPackages) { + if (_sender == null) { + showMsgDialog( + context, "Error", "Please select sender's FCS ID"); + return; + } + if (_consignee == null) { + showMsgDialog( + context, "Error", "Please select consignee's FCS ID"); + return; + } + + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CartonEditorForPackage( + sender: _sender!, consignee: _consignee!))); } // for mix cartion else { @@ -153,25 +188,25 @@ class _CartonEditorState extends State { icon: Icon(Icons.search, color: Colors.black), onPressed: () => searchUser(context, onUserSelect: (u) { setState(() { - this.consignee = u; + this._consignee = u; }); }, popPage: true)), ], ); final consigneefcsIDBox = DisplayText( - text: consignee != null ? consignee!.fcsID : "", + text: _consignee != null ? _consignee!.fcsID : "", labelTextKey: "processing.fcs.id", icon: FcsIDIcon(), ); final consigneePhoneBox = DisplayText( - text: consignee != null ? consignee!.phoneNumber : "", + text: _consignee != null ? _consignee!.phoneNumber : "", labelTextKey: "processing.phone", iconData: MaterialCommunityIcons.phone); final consigneeNameBox = DisplayText( - text: consignee != null ? consignee!.name : "", + text: _consignee != null ? _consignee!.name : "", labelTextKey: "processing.consignee.name", maxLines: 2, iconData: MaterialCommunityIcons.account_arrow_left); @@ -199,25 +234,25 @@ class _CartonEditorState extends State { icon: Icon(Icons.search, color: Colors.black), onPressed: () => searchUser(context, onUserSelect: (u) { setState(() { - this.sender = u; + this._sender = u; }); }, popPage: true)), ], ); final senderIDBox = DisplayText( - text: sender != null ? sender!.fcsID : "", + text: _sender != null ? _sender!.fcsID : "", labelTextKey: "processing.fcs.id", icon: FcsIDIcon()); final senderPhoneBox = DisplayText( - text: sender != null ? sender!.phoneNumber : "", + text: _sender != null ? _sender!.phoneNumber : "", labelTextKey: "processing.phone", iconData: MaterialCommunityIcons.phone, ); final senderNameBox = DisplayText( - text: sender != null ? sender!.name : "", + text: _sender != null ? _sender!.name : "", labelTextKey: "processing.shipper.name", maxLines: 2, iconData: MaterialCommunityIcons.account_arrow_right); diff --git a/lib/pages/carton/carton_editor_for_package.dart b/lib/pages/carton/carton_editor_for_package.dart new file mode 100644 index 0000000..553a89f --- /dev/null +++ b/lib/pages/carton/carton_editor_for_package.dart @@ -0,0 +1,217 @@ +// ignore_for_file: deprecated_member_use + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +import '../../../domain/constants.dart'; +import '../../../domain/entities/carton.dart'; +import '../../../domain/entities/carton_size.dart'; +import '../../../domain/entities/fcs_shipment.dart'; +import '../../../domain/vo/local_step.dart'; +import '../../../helpers/theme.dart'; +import '../../domain/entities/user.dart'; +import '../main/util.dart'; +import '../widgets/local_text.dart'; +import '../widgets/progress.dart'; +import '../widgets/step_widget.dart'; +import 'carton_size_widget.dart'; +import 'mix_carton/mix_carton_submit.dart'; + +class CartonEditorForPackage extends StatefulWidget { + final User sender; + final User consignee; + const CartonEditorForPackage({Key? key, required this.sender, required this.consignee}) : super(key: key); + + @override + State createState() => _CartonEditorForPackageState(); +} + +class _CartonEditorForPackageState extends State { + var dateFormatter = DateFormat('dd MMM yyyy'); + final NumberFormat numberFormatter = NumberFormat("#,###"); + List steps = [ + LocalStep(lable: 'Size', stepType: StepType.SIZE), + LocalStep(lable: 'Packages', stepType: StepType.PACKAGES), + LocalStep(lable: 'Cargos', stepType: StepType.CARGOS), + LocalStep(lable: 'Submit', stepType: StepType.SUBMIT) + ]; + List _cartions = []; + + int currentStep = 0; + double _length = 0; + double _width = 0; + double _height = 0; + + FcsShipment? _shipment; + String _cartonSizeType = standardCarton; + CartonSize? _standardSize; + bool _isLoading = false; + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () { + if (currentStep == 0) { + Navigator.of(context).pop(); + } + if (currentStep > 0) { + setState(() { + currentStep -= 1; + }); + } + + return Future.value(false); + }, + child: LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + elevation: 0, + centerTitle: true, + leading: IconButton( + icon: const Icon(CupertinoIcons.back, + color: primaryColor, size: 25), + onPressed: () { + if (currentStep == 0) { + Navigator.of(context).pop(); + } + if (currentStep > 0) { + setState(() { + currentStep -= 1; + }); + } + }, + ), + backgroundColor: Colors.white, + title: LocalText(context, 'boxes.new', + color: primaryColor, fontSize: 20), + ), + body: Column( + children: [ + StepperWidget( + labels: steps.map((e) => e.lable).toList(), + currentStep: currentStep, + eachStepWidth: MediaQuery.of(context).size.width / 4, + onChange: (index) { + if (index > currentStep) { + return; + } + setState(() { + currentStep = index; + }); + }, + ), + getContent(currentStep) + ], + ))), + ); + } + + Widget getContent(int index) { + var step = steps[index]; + if (step.stepType == StepType.SIZE) { + return Expanded( + child: CartonSizeWidget( + sender: widget.sender, + consignee: widget.consignee, + shipment: _shipment, + cartonSizeType: _cartonSizeType, + standardSize: _standardSize, + length: _length, + width: _width, + height: _height, + onPrevious: () { + Navigator.pop(context); + }, + onContinue: (shipment, cartonSizeType, + {standardSize, length, width, height}) { + setState(() { + _shipment = shipment; + _cartonSizeType = cartonSizeType; + _standardSize = standardSize; + _length = length ?? 0; + _width = width ?? 0; + _height = height ?? 0; + currentStep += 1; + }); + }, + )); + } else if (step.stepType == StepType.PACKAGES) { + return Expanded( + child: Text("PACKAGES"), + // child: CartonSelectionWidget( + // shipment: _shipment!, + // cartons: _cartions, + // onContinue: (cartons) { + // setState(() { + // _cartions = List.from(cartons); + // currentStep += 1; + // }); + // }, + // onPrevious: (cartons) { + // setState(() { + // _cartions = List.from(cartons); + // currentStep -= 1; + // }); + // }, + // ), + ); + } else if (step.stepType == StepType.CARGOS) { + return Expanded( + child: Text("cargos"), + // child: CartonSelectionWidget( + // shipment: _shipment!, + // cartons: _cartions, + // onContinue: (cartons) { + // setState(() { + // _cartions = List.from(cartons); + // currentStep += 1; + // }); + // }, + // onPrevious: (cartons) { + // setState(() { + // _cartions = List.from(cartons); + // currentStep -= 1; + // }); + // }, + // ), + ); + } else { + return Expanded( + child: MixCartonSubmit( + cartonSizeType: _cartonSizeType, + standardSize: _standardSize, + length: _length, + width: _width, + height: _height, + shipment: _shipment!, + cartons: _cartions, + onCreate: () { + _create(); + }, + onPrevious: () { + setState(() { + currentStep -= 1; + }); + }, + ), + ); + } + } + + _create() async { + setState(() { + _isLoading = true; + }); + try { + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/carton/carton_info.dart b/lib/pages/carton/carton_info.dart index 9812ecb..b302b1f 100644 --- a/lib/pages/carton/carton_info.dart +++ b/lib/pages/carton/carton_info.dart @@ -176,14 +176,14 @@ class _CartonInfoState extends State { //iconData: Ionicons.ios_airplane, ); final cartonQrBox = DisplayText( - // text: _box!., + // text: _box!., //labelTextKey: "box.number", iconData: AntDesign.qrcode, ); final shipmentBox = DisplayText( text: _box!.fcsShipmentNumber, labelTextKey: "box.fcs_shipment_num", - // iconData: Ionicons.ios_airplane, + // iconData: Ionicons.ios_airplane, ); final deliveryBox = DisplayText( text: "Delivery Carton", @@ -199,8 +199,9 @@ class _CartonInfoState extends State { final customerNameBox = DisplayText( text: _box!.userName == null ? "" : _box!.userName, - text1: _box!.fcsID == null ? "" : _box!.fcsID, + subText: Text(_box!.fcsID ?? "", style: textStyle), labelTextKey: "box.name", + //iconData: Icons.person, ); @@ -212,7 +213,8 @@ class _CartonInfoState extends State { final consigneeNameBox = DisplayText( text: _box!.userName != null ? _box!.userName : "", - text1: _box!.fcsID != null ? _box!.fcsID : "", + subText: Text(_box!.fcsID ?? "", style: textStyle), + labelTextKey: "processing.consignee.name", //maxLines: 2, //iconData: Ionicons.document_text_outline, @@ -282,7 +284,7 @@ class _CartonInfoState extends State { SizedBox(child: heightBox, width: 80), ], ); - final packageBox = DisplayText( + final packageBox = DisplayText( text: "203FVH", labelTextKey: "box.package", //iconData: AntDesign.CodeSandbox, @@ -362,54 +364,58 @@ class _CartonInfoState extends State { // Align( // alignment: Alignment(-0.1,0.1), // child: getCartonNumberStatus(context, _box!)), - + // ],) // ]),), - Padding(padding: EdgeInsets.only(left: 30), - child: - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [Expanded(child: cartonTypeBox, - flex: 1, - ), - Flexible( - child: cartonQrBox, - ), - ],)), - - - Padding(padding: EdgeInsets.only(left: 30), - child: - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [Expanded(child: shipmentBox, - flex: 1, - ), - Flexible( - child: deliveryBox, - ), - ],)), - Padding(padding: EdgeInsets.only(left: 30), - child: - Row( - children: [ - Flexible(child: customerNameBox, - ), - - Flexible( - child: consigneeNameBox, - ), - Flexible(child: - Column( + Padding( + padding: EdgeInsets.only(left: 30), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, children: [ - Icon(Ionicons.document_text_outline), - Text("Bill to",style:TextStyle(color:Colors.blue)) - ] + Expanded( + child: cartonTypeBox, + flex: 1, + ), + Flexible( + child: cartonQrBox, + ), + ], )), - ],)), - + + Padding( + padding: EdgeInsets.only(left: 30), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: shipmentBox, + flex: 1, + ), + Flexible( + child: deliveryBox, + ), + ], + )), + Padding( + padding: EdgeInsets.only(left: 30), + child: Row( + children: [ + Flexible( + child: customerNameBox, + ), + Flexible( + child: consigneeNameBox, + ), + Flexible( + child: Column(children: [ + Icon(Ionicons.document_text_outline), + Text("Bill to", style: TextStyle(color: Colors.blue)) + ])), + ], + )), + //LocalTitle(textKey: "box.shipment_info"), - // shipmentBox, + // shipmentBox, // isSmallBag ? mixCartonNumberBox : Container(), // isMixBox // ? Container() @@ -429,9 +435,7 @@ class _CartonInfoState extends State { // ], // ) // : Container(), - Padding(padding: EdgeInsets.only(left: 30), - child: - packageBox), + Padding(padding: EdgeInsets.only(left: 30), child: packageBox), isMixBox ? mixTypeBox : Container(), isMixBox ? LocalTitle(textKey: "box.mix_caton_title") : Container(), isMixBox @@ -442,7 +446,7 @@ class _CartonInfoState extends State { packages: _box!.packages, ) : Container(), - // isMixBox ? Container() : LocalTitle(textKey: "box.cargo.type"), + // isMixBox ? Container() : LocalTitle(textKey: "box.cargo.type"), isMixBox ? Container() : cargoTableBox, ...(isFromPackages || isFromCartons ? [ diff --git a/lib/pages/carton/carton_size_widget.dart b/lib/pages/carton/carton_size_widget.dart new file mode 100644 index 0000000..8f035a1 --- /dev/null +++ b/lib/pages/carton/carton_size_widget.dart @@ -0,0 +1,375 @@ +import 'package:fcs/pages/widgets/local_radio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import 'package:provider/provider.dart'; +import '../../../domain/constants.dart'; +import '../../../domain/entities/carton_size.dart'; +import '../../../domain/entities/fcs_shipment.dart'; +import '../../../helpers/theme.dart'; +import '../../domain/entities/user.dart'; +import '../carton_size/model/carton_size_model.dart'; +import '../fcs_shipment/model/fcs_shipment_model.dart'; +import '../main/util.dart'; +import '../widgets/box_size_picker.dart'; +import '../widgets/continue_button.dart'; +import '../widgets/display_text.dart'; +import '../widgets/local_dropdown.dart'; +import '../widgets/local_text.dart'; +import '../widgets/local_title.dart'; +import '../widgets/previous_button.dart'; + +typedef OnPrevious = Function(); + +typedef OnContinue = Function(FcsShipment shipment, String cartonSizeType, + {CartonSize? standardSize, double? length, double? width, double? height}); + +class CartonSizeWidget extends StatefulWidget { + final OnPrevious? onPrevious; + final OnContinue? onContinue; + final User sender; + final User consignee; + final FcsShipment? shipment; + final String cartonSizeType; + final CartonSize? standardSize; + final double? length; + final double? width; + final double? height; + + const CartonSizeWidget( + {Key? key, + this.onPrevious, + this.onContinue, + this.shipment, + required this.cartonSizeType, + this.standardSize, + this.length, + this.width, + this.height, + required this.sender, + required this.consignee}) + : super(key: key); + + @override + State createState() => _CartonSizeWidgetState(); +} + +class _CartonSizeWidgetState extends State { + FcsShipment? _shipment; + String _cartionSizeType = standardCarton; + + List _shipments = []; + CartonSize? _selectStandardSize; + + TextEditingController _widthController = new TextEditingController(); + TextEditingController _heightController = new TextEditingController(); + TextEditingController _lengthController = new TextEditingController(); + + @override + void initState() { + _init(); + super.initState(); + } + + _init() async { + _shipment = widget.shipment; + _cartionSizeType = widget.cartonSizeType; + + List cartonSizes = context.read().cartonSizes; + _selectStandardSize = widget.standardSize ?? cartonSizes.first; + + _lengthController.text = + widget.length == null ? "0" : widget.length.toString(); + _widthController.text = + widget.width == null ? "0" : widget.width.toString(); + _heightController.text = + widget.height == null ? "0" : widget.height.toString(); + + var fcsShipments = + await context.read().getActiveFcsShipments(); + _shipments = fcsShipments; + + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + List cartonSizes = context.watch().cartonSizes; + bool isStandardSize = _cartionSizeType == standardCarton; + bool isCustomSize = _cartionSizeType == customCarton; + bool isNoneDefinedSize = _cartionSizeType == packageCartion; + + final senderBox = DisplayText( + text: widget.sender.name, + labelTextKey: "box.sender.title", + iconData: MaterialCommunityIcons.account_arrow_right, + ); + + final consigneeBox = DisplayText( + text: widget.consignee.name, + labelTextKey: "box.consignee.title", + iconData: MaterialCommunityIcons.account_arrow_left, + ); + + final userRow = Row( + children: [ + Flexible( + child: senderBox, + flex: 2, + ), + Flexible(child: consigneeBox) + ], + ); + + final continueBtn = ContinueButton(onTap: () { + double l = double.tryParse(_lengthController.text) ?? 0; + double w = double.tryParse(_widthController.text) ?? 0; + double h = double.tryParse(_heightController.text) ?? 0; + + if (_shipment == null) { + showMsgDialog(context, "Error", "Please select shipment"); + return; + } + + if (isStandardSize && + _selectStandardSize == null && + !isCustomSize && + !isNoneDefinedSize) { + showMsgDialog( + context, "Error", "Please select the standard cartion size"); + return; + } + + if (isCustomSize && + !isStandardSize && + !isNoneDefinedSize && + (l == 0 || w == 0 || h == 0)) { + showMsgDialog(context, "Error", "Please add the cartion size"); + return; + } + + if (widget.onContinue != null) { + widget.onContinue!(_shipment!, _cartionSizeType, + standardSize: _selectStandardSize, length: l, width: w, height: h); + } + }); + + final previousBtn = PreviousButton(onTap: () { + if (widget.onPrevious != null) { + widget.onPrevious!(); + } + }); + + final standardSizeBox = Padding( + padding: const EdgeInsets.only(left: 34.0, top: 8), + child: IgnorePointer( + ignoring: !isStandardSize, + child: DropdownButton( + isDense: true, + value: _selectStandardSize, + style: TextStyle(color: Colors.black, fontSize: 14), + underline: Container(height: 1, color: Colors.grey), + onChanged: (newValue) { + setState(() { + _selectStandardSize = newValue!; + }); + }, + isExpanded: true, + items: + cartonSizes.map>((CartonSize value) { + return DropdownMenuItem( + value: value, + child: Row( + children: [ + Text("${value.name} - ", + style: TextStyle( + color: isStandardSize ? Colors.black : labelColor)), + Text( + "${value.length.toInt()}”x${value.width.toInt()}”x${value.height.toInt()}”", + style: TextStyle(color: labelColor)), + ], + ), + ); + }).toList(), + ), + ), + ); + + final lengthBox = BoxSizePicker( + lableKey: 'box.length', + controller: _lengthController, + enable: isCustomSize); + + final widthBox = BoxSizePicker( + lableKey: 'box.width', + controller: _widthController, + enable: isCustomSize); + + final heightBox = BoxSizePicker( + lableKey: 'box.height', + controller: _heightController, + enable: isCustomSize); + + final customSizeBox = Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Row( + children: [ + Flexible(child: lengthBox), + Flexible(child: widthBox), + Flexible(child: heightBox) + ], + ), + ); + + final cartonSizedBox = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // standard carton size + InkWell( + onTap: () { + setState(() { + _cartionSizeType = standardCarton; + }); + }, + child: Row(children: [ + LocalRadio( + value: standardCarton, + groupValue: _cartionSizeType, + onChanged: (p0) { + setState(() { + _cartionSizeType = standardCarton; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.standard_carton_size', + fontSize: 15, + color: isStandardSize ? primaryColor : labelColor), + ), + ) + ]), + ), + standardSizeBox, + const SizedBox(height: 20), + // custom size + InkWell( + onTap: () { + setState(() { + _cartionSizeType = customCarton; + }); + }, + child: Row(children: [ + LocalRadio( + value: customCarton, + groupValue: _cartionSizeType, + onChanged: (p0) { + setState(() { + _cartionSizeType = customCarton; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.custom_size', + fontSize: 15, + color: isCustomSize ? primaryColor : Colors.black54), + ), + ) + ]), + ), + customSizeBox, + const SizedBox(height: 10), + // not defined size + InkWell( + onTap: () { + setState(() { + _cartionSizeType = packageCartion; + }); + }, + child: Row(children: [ + LocalRadio( + value: packageCartion, + groupValue: _cartionSizeType, + onChanged: (p0) { + setState(() { + _cartionSizeType = packageCartion; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.package_size', + fontSize: 15, + color: isNoneDefinedSize ? primaryColor : Colors.black54), + ), + ) + ]), + ), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text( + "No defined size", + style: TextStyle( + fontSize: 14, + color: isNoneDefinedSize ? Colors.black : labelColor), + ), + ) + ], + ); + + final fcsShipmentsBox = Container( + padding: EdgeInsets.only(top: 10), + child: LocalDropdown( + callback: (v) { + setState(() { + _shipment = v; + }); + }, + labelKey: "box.shipment", + iconData: Ionicons.ios_airplane, + display: (u) => u.shipmentNumber, + selectedValue: _shipment, + values: _shipments, + )); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView( + padding: EdgeInsets.only(left: 10, right: 10), + children: [ + const SizedBox(height: 8), + userRow, + LocalTitle(textKey: "box.select_carton_size"), + const SizedBox(height: 8), + cartonSizedBox, + const SizedBox(height: 8), + LocalTitle(textKey: "box.select_shipment"), + const SizedBox(height: 5), + fcsShipmentsBox + ], + )), + Padding( + padding: const EdgeInsets.only(left: 15, right: 15), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + widget.onPrevious == null ? const SizedBox() : previousBtn, + continueBtn + // warehouse != null ? continueBtn : const SizedBox(), + ], + ), + ), + const SizedBox( + height: 20, + ), + ], + ); + } +} diff --git a/lib/pages/carton/mix_cation/carton_selection_result.dart b/lib/pages/carton/mix_carton/carton_selection_result.dart similarity index 98% rename from lib/pages/carton/mix_cation/carton_selection_result.dart rename to lib/pages/carton/mix_carton/carton_selection_result.dart index 356e4fa..6681949 100644 --- a/lib/pages/carton/mix_cation/carton_selection_result.dart +++ b/lib/pages/carton/mix_carton/carton_selection_result.dart @@ -36,7 +36,7 @@ class CartonSelectionResult extends StatelessWidget { var model = context.watch(); List searchResults = model.cartons; - return searchResults.isEmpty + return searchResults.isEmpty && !model.isLoading ? Center( child: LocalText(context, 'box.no_carton', color: Colors.black, fontSize: 15)) diff --git a/lib/pages/carton/mix_cation/carton_selection_widget.dart b/lib/pages/carton/mix_carton/carton_selection_widget.dart similarity index 99% rename from lib/pages/carton/mix_cation/carton_selection_widget.dart rename to lib/pages/carton/mix_carton/carton_selection_widget.dart index 1e71644..6e7c9d8 100644 --- a/lib/pages/carton/mix_cation/carton_selection_widget.dart +++ b/lib/pages/carton/mix_carton/carton_selection_widget.dart @@ -1,6 +1,6 @@ import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/carton/mix_cation/carton_selection_result.dart'; +import 'package:fcs/pages/carton/mix_carton/carton_selection_result.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/pages/carton/mix_cation/mix_cartion_editor.dart b/lib/pages/carton/mix_carton/mix_carton_editor.dart similarity index 82% rename from lib/pages/carton/mix_cation/mix_cartion_editor.dart rename to lib/pages/carton/mix_carton/mix_carton_editor.dart index ce3b03d..319ea2f 100644 --- a/lib/pages/carton/mix_cation/mix_cartion_editor.dart +++ b/lib/pages/carton/mix_carton/mix_carton_editor.dart @@ -11,11 +11,13 @@ import '../../../domain/entities/carton_size.dart'; import '../../../domain/entities/fcs_shipment.dart'; import '../../../domain/vo/local_step.dart'; import '../../../helpers/theme.dart'; +import '../../main/util.dart'; import '../../widgets/local_text.dart'; import '../../widgets/progress.dart'; import '../../widgets/step_widget.dart'; import '../model/carton_selection_model.dart'; import 'carton_selection_widget.dart'; +import 'mix_carton_submit.dart'; import 'type_widget.dart'; class MixCartonEditor extends StatefulWidget { @@ -43,7 +45,7 @@ class _MixCartonEditorState extends State { double _height = 0; FcsShipment? _shipment; - String _cartionSizeType = standardCarton; + String _cartonSizeType = standardCarton; CartonSize? _standardSize; bool _isLoading = false; @@ -97,7 +99,7 @@ class _MixCartonEditorState extends State { StepperWidget( labels: steps.map((e) => e.lable).toList(), currentStep: currentStep, - eachStepWidth: 120, + eachStepWidth: MediaQuery.of(context).size.width / 3, onChange: (index) { if (index > currentStep) { return; @@ -119,7 +121,7 @@ class _MixCartonEditorState extends State { return Expanded( child: TypeWidget( shipment: _shipment, - cartonSizeType: _cartionSizeType, + cartonSizeType: _cartonSizeType, standardSize: _standardSize, length: _length, width: _width, @@ -131,7 +133,7 @@ class _MixCartonEditorState extends State { {standardSize, length, width, height}) { setState(() { _shipment = shipment; - _cartionSizeType = cartonSizeType; + _cartonSizeType = cartonSizeType; _standardSize = standardSize; _length = length ?? 0; _width = width ?? 0; @@ -161,27 +163,39 @@ class _MixCartonEditorState extends State { ); } else { return Expanded( - child: Text("Submit"), - // child: StockAdjustmentSubmit( - // warehouse: _warehouse?.name, - // products: products, - // onCreate: () { - // if (user != null && user.hasInventoryCreate()) { - // showConfirmDialog(context, 'stock_adjustment_confirm', _create); - // } else { - // showDialog( - // context: context, - // builder: (BuildContext context) => const AuthorizedDialog( - // uiFunction: funcInventoriesCreate)); - // } - // }, - // onPrevious: () { - // setState(() { - // currentStep -= 1; - // }); - // }, - // ), + child: MixCartonSubmit( + cartonSizeType: _cartonSizeType, + standardSize: _standardSize, + length: _length, + width: _width, + height: _height, + shipment: _shipment!, + cartons: _cartions, + onCreate: () { + _create(); + }, + onPrevious: () { + setState(() { + currentStep -= 1; + }); + }, + ), ); } } + + _create() async { + setState(() { + _isLoading = true; + }); + try { + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/carton/mix_carton/mix_carton_submit.dart b/lib/pages/carton/mix_carton/mix_carton_submit.dart new file mode 100644 index 0000000..7f386ab --- /dev/null +++ b/lib/pages/carton/mix_carton/mix_carton_submit.dart @@ -0,0 +1,289 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import 'package:intl/intl.dart'; + +import '../../../domain/constants.dart'; +import '../../../domain/entities/cargo_type.dart'; +import '../../../domain/entities/carton.dart'; +import '../../../domain/entities/carton_size.dart'; +import '../../../domain/entities/fcs_shipment.dart'; +import '../../../helpers/theme.dart'; +import '../../widgets/local_text.dart'; +import '../../widgets/previous_button.dart'; +import '../../widgets/submit_text_widget.dart'; +import "package:collection/collection.dart"; + +typedef OnCreateMixCarton = Function(); +typedef OnPrevious = Function(); + +class MixCartonSubmit extends StatefulWidget { + final FcsShipment shipment; + final List cartons; + final String cartonSizeType; + final CartonSize? standardSize; + final double length; + final double width; + final double height; + final OnCreateMixCarton? onCreate; + final OnPrevious? onPrevious; + const MixCartonSubmit( + {Key? key, + this.onCreate, + this.onPrevious, + required this.shipment, + this.cartons = const [], + this.standardSize, + required this.cartonSizeType, + this.length = 0, + this.width = 0, + this.height = 0}) + : super(key: key); + + @override + State createState() => _MixCartonSubmitState(); +} + +class _MixCartonSubmitState extends State { + final NumberFormat numberFormatter = NumberFormat("#,###"); + Map _mapCargosByWeight = {}; + Map _mapCargosByCustomDutyFee = {}; + + @override + void initState() { + _init(); + super.initState(); + } + + _init() { + List _cargoTypes = []; + for (var c in widget.cartons) { + _cargoTypes.addAll(c.cargoTypes); + } + + // get cargos by weight + Map> _cargosByWeight = + groupCargos(_cargoTypes.where((e) => !e.isCutomDuty).toList()); + + _cargosByWeight.forEach((key, value) { + double total = value.fold(0, (sum, item) => sum + item.weight); + _mapCargosByWeight[key] = total; + }); + + // get cargos by custom duty fee + Map> _cargosByCustomDutyFee = + groupCargos(_cargoTypes.where((e) => e.isCutomDuty).toList()); + + _cargosByCustomDutyFee.forEach((key, value) { + double total = value.fold(0, (sum, item) => sum + item.qty); + _mapCargosByCustomDutyFee[key] = total; + }); + + if (mounted) { + setState(() {}); + } + } + + Map> groupCargos(List cargos) { + var groups = groupBy(cargos, (CargoType e) { + String? _categoryName = e.name; + return _categoryName; + }); + + return groups; + } + + @override + Widget build(BuildContext context) { + String? boxDimension = widget.cartonSizeType == standardCarton + ? "${widget.standardSize?.name} - ${widget.standardSize?.length.toInt()}”x${widget.standardSize?.width.toInt()}”x${widget.standardSize?.height.toInt()}”" + : widget.cartonSizeType == customCarton + ? "${widget.length.toInt()}”x${widget.width.toInt()}”x${widget.height.toInt()}”" + : null; + + final cartonType = Padding( + padding: const EdgeInsets.only(top: 10), + child: SubmitTextWidget( + labelKey: 'box.carton.type', + text: 'Mix Carton', + subText: boxDimension, + ), + ); + + final shipmentBox = Padding( + padding: const EdgeInsets.only(top: 10), + child: SubmitTextWidget( + labelKey: 'box.shipment', + text: widget.shipment.shipmentNumber ?? '', + subText: widget.shipment.status ?? "", + ), + ); + + final cartonsBox = Padding( + padding: const EdgeInsets.only(top: 10), + child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + Padding( + padding: const EdgeInsets.only(left: 5, bottom: 5), + child: LocalText(context, 'box.cartion.count', + translationVariables: [widget.cartons.length.toString()], + color: primaryColor, + fontSize: 16, + fontWeight: FontWeight.normal), + ), + Container( + decoration: BoxDecoration( + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.circular(5), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 15, + children: widget.cartons.map((e) { + return SizedBox( + width: MediaQuery.of(context).size.width / 2.5, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 3), + child: Text( + e.cartonNumber ?? "", + style: TextStyle(color: Colors.black, fontSize: 15), + ), + ), + ); + }).toList()), + ), + ), + ]), + ); + + final cargosBox = Padding( + padding: const EdgeInsets.only(top: 10), + child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + Padding( + padding: const EdgeInsets.only(left: 5, bottom: 5), + child: LocalText(context, 'box.cargo.type', + color: primaryColor, fontSize: 16, fontWeight: FontWeight.normal), + ), + Container( + decoration: BoxDecoration( + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.circular(5), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _mapCargosByWeight.entries.map((e) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 3), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e.key ?? "", + style: + TextStyle(color: Colors.black, fontSize: 15), + ), + Text("${numberFormatter.format(e.value)} lb", + style: TextStyle( + color: Colors.black, fontSize: 15)) + ], + ), + ); + }).toList()), + const SizedBox(height: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _mapCargosByCustomDutyFee.entries.map((e) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 3), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e.key ?? "", + style: TextStyle(color: labelColor, fontSize: 15), + ), + Text("${numberFormatter.format(e.value)} pc", + style: + TextStyle(color: labelColor, fontSize: 15)) + ], + ), + ); + }).toList()), + ], + ), + ), + ), + ]), + ); + + final createBtn = InkWell( + onTap: () { + if (widget.onCreate != null) { + widget.onCreate!(); + } + }, + child: Container( + alignment: Alignment.bottomRight, + height: 45, + width: 150, + decoration: BoxDecoration( + color: primaryColor, + borderRadius: BorderRadius.circular(5), + ), + child: TextButton( + onPressed: null, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: LocalText(context, 'box.crete.carton', + color: Colors.white, fontSize: 15), + ), + const SizedBox(width: 5), + const Icon( + MaterialCommunityIcons.check_circle_outline, + color: Colors.white, + ), + ], + ), + ), + )); + + final previousBtn = PreviousButton(onTap: () { + if (widget.onPrevious != null) { + widget.onPrevious!(); + } + }); + + return Column( + children: [ + Expanded( + child: ListView( + padding: const EdgeInsets.all(20), + children: [ + cartonType, + const SizedBox(height: 10), + shipmentBox, + const SizedBox(height: 10), + widget.cartons.isNotEmpty ? cartonsBox : const SizedBox(), + const SizedBox(height: 10), + cargosBox, + const SizedBox(height: 20), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(left: 15, right: 15), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [previousBtn, createBtn], + ), + ), + const SizedBox(height: 20) + ], + ); + } +} diff --git a/lib/pages/carton/mix_cation/type_widget.dart b/lib/pages/carton/mix_carton/type_widget.dart similarity index 100% rename from lib/pages/carton/mix_cation/type_widget.dart rename to lib/pages/carton/mix_carton/type_widget.dart diff --git a/lib/pages/carton/model/carton_selection_model.dart b/lib/pages/carton/model/carton_selection_model.dart index 78e364c..b91ef7b 100644 --- a/lib/pages/carton/model/carton_selection_model.dart +++ b/lib/pages/carton/model/carton_selection_model.dart @@ -15,6 +15,8 @@ class CartonSelectionModel extends BaseModel { bool reachEnd = false; List cartons = []; + bool isLoading= false; + // for default carton DocumentSnapshot? _lastDocument; bool ended = false; @@ -96,6 +98,7 @@ class CartonSelectionModel extends BaseModel { int rowPerPage = 20; try { + isLoading = true; String path = "/$cartons_collection"; Query query = FirebaseFirestore.instance .collection(path) @@ -131,6 +134,8 @@ class CartonSelectionModel extends BaseModel { notifyListeners(); } catch (e) { log.warning("error:$e"); + }finally{ + isLoading = false; } } diff --git a/lib/pages/fcs_shipment/fcs_shipment_list.dart b/lib/pages/fcs_shipment/fcs_shipment_list.dart index 513d400..15fe6cd 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_list.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_list.dart @@ -1,7 +1,6 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; -import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; diff --git a/lib/pages/widgets/display_text.dart b/lib/pages/widgets/display_text.dart index 8963ff6..e027e99 100644 --- a/lib/pages/widgets/display_text.dart +++ b/lib/pages/widgets/display_text.dart @@ -6,7 +6,7 @@ import 'package:provider/provider.dart'; class DisplayText extends StatelessWidget { final String? text; - final String? text1; + final Widget? subText; final String? labelTextKey; final IconData? iconData; final int? maxLines; @@ -14,11 +14,10 @@ class DisplayText extends StatelessWidget { final Color? borderColor; final Widget? icon; - const DisplayText({ Key? key, this.text, - this.text1, + this.subText, this.labelTextKey, this.iconData, this.maxLines = 1, @@ -72,12 +71,9 @@ class DisplayText extends StatelessWidget { text!, style: textStyle, ), - text1 == null + subText == null ? Container() - : Text( - text1!, - style: textStyle, - ), + : subText!, ], ), ), diff --git a/lib/pages/widgets/submit_text_widget.dart b/lib/pages/widgets/submit_text_widget.dart new file mode 100644 index 0000000..db9f4a7 --- /dev/null +++ b/lib/pages/widgets/submit_text_widget.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import '../../helpers/theme.dart'; +import 'local_text.dart'; + +class SubmitTextWidget extends StatelessWidget { + final String labelKey; + final String text; + final String? subText; + + const SubmitTextWidget( + {Key? key, required this.labelKey, required this.text, this.subText}) + : super(key: key); + @override + Widget build(BuildContext context) { + return Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + Padding( + padding: const EdgeInsets.only(left: 5, bottom: 5), + child: LocalText(context, labelKey, + color: primaryColor, fontSize: 16, fontWeight: FontWeight.normal), + ), + Container( + decoration: BoxDecoration( + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.circular(5), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(text, + style: const TextStyle( + fontSize: 16.0, fontWeight: FontWeight.w500)), + subText == null + ? const SizedBox() + : Text(subText!, + style: + const TextStyle(fontSize: 14.0, color: Colors.grey)), + ], + ), + ), + ) + ]); + } +}