From 3bfbca35fca3802c30d2000ab3a7f2c0eb04396c Mon Sep 17 00:00:00 2001 From: tzw Date: Fri, 21 Mar 2025 18:19:52 +0630 Subject: [PATCH] add fcs shipment in processing,update cargo types for carton --- assets/local/localization_en.json | 19 +- assets/local/localization_mu.json | 11 +- lib/data/provider/package_data_provider.dart | 12 +- lib/data/provider/user_data_provider.dart | 2 +- lib/data/services/package_imp.dart | 4 - lib/data/services/package_service.dart | 1 - lib/domain/entities/cargo_type.dart | 28 +- lib/domain/entities/carton.dart | 2 +- lib/domain/entities/package.dart | 27 +- lib/domain/entities/user.dart | 5 +- lib/main_dev.dart | 4 +- lib/pages/carton/cargo_type_addition.dart | 4 +- .../carton/cargo_type_addition_dialog.dart | 131 +++++ lib/pages/carton/cargo_widget.dart | 461 +++++++++++++----- lib/pages/carton/carton_info.dart | 44 +- lib/pages/carton/carton_package_form.dart | 1 + .../mix_cargo_type_addition_dialog.dart | 134 +++++ .../carton/model/package_selection_model.dart | 2 +- lib/pages/carton/packages_widget.dart | 40 +- lib/pages/chat/message_detail.dart | 2 +- lib/pages/customer/customer_detail.dart | 160 ++++++ lib/pages/customer/model/customer_model.dart | 19 +- lib/pages/main/home_page.dart | 6 +- lib/pages/main/util.dart | 46 +- lib/pages/package/model/package_model.dart | 12 +- lib/pages/package/package_info.dart | 26 +- lib/pages/package/package_new.dart | 208 -------- lib/pages/processing/package_editor.dart | 1 + .../processing/processing_edit_editor.dart | 9 +- lib/pages/processing/processing_info.dart | 34 +- lib/pages/profile/add_recovery_email.dart | 2 +- lib/pages/profile/confirm_phone_number.dart | 2 +- lib/pages/profile/confirm_recovery_email.dart | 2 +- lib/pages/profile/profile_page.dart | 431 ++++++++-------- 34 files changed, 1227 insertions(+), 665 deletions(-) create mode 100644 lib/pages/carton/cargo_type_addition_dialog.dart create mode 100644 lib/pages/carton/mix_cargo_type_addition_dialog.dart create mode 100644 lib/pages/customer/customer_detail.dart delete mode 100644 lib/pages/package/package_new.dart diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 22b7b3c..348f83f 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -20,6 +20,7 @@ "btn.filter":"Filter", "btn.exit_confirm":"Are you sure you want to exit?", "btn.confirm":"Confirm", + "btn.add":"Add", "Buttons End ================================================================":"", "Offline Start ================================================================":"", @@ -143,6 +144,7 @@ "customer.disable.btn":"Disable", "customer.enable.btn":"Enable", "customer.chat.btn":"Chat", + "customer.detail.title":"Account", "Customer End ================================================================":"", "Invitation Start ================================================================":"", @@ -188,21 +190,25 @@ "profile.email":"Email", "profile.privileges":"Privileges", "profile.default.delivery.address":"Default delivery address", - "profile.recovery.email":"Recovery Email", - "profile.change_phone.title":"Change Phone Number", - "profile.current_phone":"Current Phone Number", - "profile.new_phone":"New Phone Number", + "profile.recovery.email":"Recovery email", + "profile.change.phone":"Change my phone number", + "profile.change_phone.title":"Change My Phone Number", + "profile.current_phone":"Current phone number", + "profile.new_phone":"New phone number", "profile.new_phone_empty":"Enter new phone number", "profile.send_sms":"Send SMS Code", "profile.confirm_new_phone.title":"Confirm New Phone Number", + "profile.confirm.instruction":"Enter SMS code sent to your phone number", "profile.change_phone.btn":"Change", "profile.recovery_email.title":"Recovery Email", "profile.email.empty":"Enter recovery email", "profile.email.mismatch_message":"Email format is incorrect", "profile.email_instruction":"Your recovery email is used to help you get back into your account when you can’t sign in.", "profile.comfirm_email.title":"Confirm Your Email", - "profile.confirm_email.send_to":"Sent email to", - "profile.confirm_email.insruction":"Please open the email to confirm recovery email", + "profile.confirm_email.send_to":"Verification code sent email to your email", + "profile.confirm_email.insruction":"Please open your email to get verification code and confirm recovery email", + "profile.confirm_email_code":"Verification code", + "Profile End ================================================================":"", "Package Start ================================================================":"", @@ -395,6 +401,7 @@ "box.delivery":"Delivery", "box.pickup":"Pick-up", "box.add.cargo_type":"Add cargo type", + "box.mix_cargo.title":"Mix cargo", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 10b6e41..03a16c8 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -19,6 +19,7 @@ "btn.filter":"Filter", "btn.exit_confirm":"Are you sure you want to exit?", "btn.confirm":"အတည်ပြုမည်", + "btn.add":"ထည့်မည်", "Buttons End ================================================================":"", "Offline Start ================================================================":"", @@ -143,7 +144,7 @@ "customer.disable.btn":"ပိတ်ပါ", "customer.enable.btn":"ဖွင့်ပါ", "customer.chat.btn":"Chat", - + "customer.detail.title":"အကောင့်", "Customer End ================================================================":"", "Invitation Start ================================================================":"", @@ -190,20 +191,23 @@ "profile.privileges":"လုပ်ပိုင်ခွင့်များ", "profile.default.delivery.address":"အမြဲတမ်း ပို့ဆောင်ရမည့်လိပ်စာ", "profile.recovery.email":"အီးမေးလ်", + "profile.change.phone":"ဖုန်းနံပါတ်ပြောင်းခြင်း", "profile.change_phone.title":"ဖုန်းနံပါတ်ပြောင်းခြင်း", "profile.current_phone":"လက်ရှိဖုန်းနံပါတ်", "profile.new_phone":"ဖုန်းနံပါတ်အသစ်", "profile.new_phone_empty":"ဖုန်းနံပါတ်အသစ်ထည့်ပါ", "profile.send_sms":"SMS ကုဒ်ပို့မည်", "profile.confirm_new_phone.title":"ဖုန်းနံပါတ်အသစ်ကို အတည်ပြုခြင်း", + "profile.confirm.instruction":"သင့်ဖုန်းနံပါတ်သို့ ပေးပို့ထားသော SMS ကုဒ်ကိုရိုက်ထည့်ပါ", "profile.change_phone.btn":"ပြောင်းမည်", "profile.recovery_email.title":"အီးမေးလ်ထည့်ခြင်း", "profile.email.empty":"အီးမေးလ်ထည့်ပါ", "profile.email.mismatch_message":"အီးမေးလ်မမှန်ပါ", "profile.email_instruction":"အကောင့်ဝင်လို့မရသောအခါတွင် သင့်အကောင့်ထဲသို့ ပြန်လည်ရောက်ရှိစေရန်အတွက် သင်၏အီးမေးလ်ကို အသုံးပြုပါသည်။", "profile.comfirm_email.title":"သင့်အီးမေးလ်ကိုအတည်ပြုခြင်း", - "profile.confirm_email.send_to":"သင့်အီးမေးလ်သို့ ပေးပို့ခဲ့သည်", - "profile.confirm_email.insruction":"အီးမေးလ်ကို အတည်ပြုရန် သင့်အီးမေးလ်ကိုဖွင့်ပါ", + "profile.confirm_email.send_to":"အတည်ပြုကုဒ်ကို သင့်အီးမေးလ်သို့ ပေးပို့ခဲ့သည်", + "profile.confirm_email.insruction":"အတည်ပြုကုဒ်ရယူရန်နှင့် အီးမေးလ်ကို အတည်ပြုရန် သင့်အီးမေးလ်ကိုဖွင့်ပါ", + "profile.confirm_email_code":"အတည်ပြုကုဒ်", "Profile End ================================================================":"", "Package Start ================================================================":"", @@ -395,6 +399,7 @@ "box.delivery":"Delivery", "box.pickup":"Pick-up", "box.add.cargo_type":"Add cargo type", + "box.mix_cargo.title":"Mix cargo", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/lib/data/provider/package_data_provider.dart b/lib/data/provider/package_data_provider.dart index a8fbc75..ed8a8cb 100644 --- a/lib/data/provider/package_data_provider.dart +++ b/lib/data/provider/package_data_provider.dart @@ -11,20 +11,14 @@ import '../services/services.dart'; class PackageDataProvider { final log = Logger('PackageDataProvider'); - Future createPackages(List packages, String fcsID) async { - List> json = packages.map((e) => e.toJson()).toList(); - return await requestAPI("/packages", "POST", - payload: {"packages": json, "fcs_id": fcsID}, token: await getToken()); - } - Future createReceiving(Package package) async { return await requestAPI("/receiving", "POST", - payload: package.toJson(), token: await getToken()); + payload: package.toJsonForReceiving(), token: await getToken()); } Future updateReceiving(Package package) async { return await requestAPI("/receiving", "PUT", - payload: package.toJson(), token: await getToken()); + payload: package.toJsonForReceiving(), token: await getToken()); } Future deleteReceiving(Package package) async { @@ -34,7 +28,7 @@ class PackageDataProvider { Future updateProcessing(Package package) async { return await requestAPI("/processing", "PUT", - payload: package.toJson(), token: await getToken()); + payload: package.toJsonForProcessing(), token: await getToken()); } Future deleteProcessing(Package package) async { diff --git a/lib/data/provider/user_data_provider.dart b/lib/data/provider/user_data_provider.dart index f7bacdb..5bc8af1 100644 --- a/lib/data/provider/user_data_provider.dart +++ b/lib/data/provider/user_data_provider.dart @@ -45,7 +45,7 @@ class UserDataProvider { .limit(1) .get(); - if (querySnap.docs.length > 0) { + if (querySnap.docs.isNotEmpty) { var snap = querySnap.docs.first; User user = User.fromMap(snap.data() as Map, snap.id); return user; diff --git a/lib/data/services/package_imp.dart b/lib/data/services/package_imp.dart index f200147..2475e68 100644 --- a/lib/data/services/package_imp.dart +++ b/lib/data/services/package_imp.dart @@ -13,10 +13,6 @@ class PackageServiceImp implements PackageService { final Connectivity? connectivity; final PackageDataProvider packageDataProvider; - @override - Future createPackages(List packages, String fcsID) { - return packageDataProvider.createPackages(packages, fcsID); - } @override Future createReceiving(Package package) { diff --git a/lib/data/services/package_service.dart b/lib/data/services/package_service.dart index 2d27585..5e17ed3 100644 --- a/lib/data/services/package_service.dart +++ b/lib/data/services/package_service.dart @@ -1,7 +1,6 @@ import 'package:fcs/domain/entities/package.dart'; abstract class PackageService { - Future createPackages(List packages, String fcsID); Future createReceiving(Package package); Future updateReceiving(Package package); Future deleteReceiving(Package package); diff --git a/lib/domain/entities/cargo_type.dart b/lib/domain/entities/cargo_type.dart index d2562a6..22cd0dd 100644 --- a/lib/domain/entities/cargo_type.dart +++ b/lib/domain/entities/cargo_type.dart @@ -13,6 +13,9 @@ class CargoType { bool isDefault; bool isMixCargo; + List mixCargoIds; + List mixCargoes; + double get calAmount => calRate * calWeight; CargoType( @@ -28,7 +31,9 @@ class CargoType { this.customDutyFee = 0, this.displayIndex = 0, this.isDefault = false, - this.isMixCargo = false}); + this.isMixCargo = false, + this.mixCargoes = const [], + this.mixCargoIds = const []}); factory CargoType.fromMap(Map map, String id) { return CargoType( @@ -45,12 +50,23 @@ class CargoType { isMixCargo: map['is_mix_cargo'] ?? false); } - factory CargoType.fromMapForCargo(Map map, String id) { + factory CargoType.fromMapForCarton(Map map, String id) { + var cargoTypesMaps = + List>.from(map['mix_cargo_types'] ?? []); + var mixCargoTypes = + cargoTypesMaps.map((e) => CargoType.fromMapForMix(e, e["id"])).toList(); + return CargoType( id: id, name: map['name'], weight: map['weight']?.toDouble() ?? 0, - displayIndex: map['display_index'] ?? 0); + displayIndex: map['display_index'] ?? 0, + isMixCargo: map['is_mix_cargo'] ?? false, + mixCargoes: mixCargoTypes); + } + + factory CargoType.fromMapForMix(Map map, String id) { + return CargoType(id: id, name: map['name']); } factory CargoType.fromMapForsurcharge(Map map, String id) { @@ -78,7 +94,11 @@ class CargoType { } Map toMapForCarton() { - return {"id": id, 'weight': weight}; + return { + "id": id, + 'weight': weight, + "mix_cargo_type_ids": mixCargoes.map((e) => e.id).toList() + }; } Map toMapForSurcharge() { diff --git a/lib/domain/entities/carton.dart b/lib/domain/entities/carton.dart index b0e21bd..5182116 100644 --- a/lib/domain/entities/carton.dart +++ b/lib/domain/entities/carton.dart @@ -213,7 +213,7 @@ class Carton { var cargoTypesMaps = List>.from(map['cargo_types'] ?? []); var cargoTypes = cargoTypesMaps - .map((e) => CargoType.fromMapForCargo(e, e["id"])) + .map((e) => CargoType.fromMapForCarton(e, e["id"])) .toList(); var surchargeItemMaps = diff --git a/lib/domain/entities/package.dart b/lib/domain/entities/package.dart index 12bb1ff..577b724 100644 --- a/lib/domain/entities/package.dart +++ b/lib/domain/entities/package.dart @@ -14,8 +14,8 @@ class Package { String? desc; String? status; - String? shipmentId; - String? shipmentNumber; + String? fcsShipmentId; + String? fcsShipmentNumber; String? userID; String? fcsID; @@ -54,8 +54,8 @@ class Package { this.userName, this.fcsID, this.phoneNumber, - this.shipmentId, - this.shipmentNumber, + this.fcsShipmentId, + this.fcsShipmentNumber, this.senderFCSID, this.senderName, this.boxNumber, @@ -111,8 +111,8 @@ class Package { senderFCSID: map['sender_fcs_id'], senderName: map['sender_name'] ?? "", senderPhoneNumber: map['sender_phone_number'] ?? "", - shipmentId: map['shipment_id'], - shipmentNumber: map['shipment_number'], + fcsShipmentId: map['fcs_shipment_id'], + fcsShipmentNumber: map['fcs_shipment_number'], deliveryAddress: da, currentStatusDate: currentStatusDate?.toDate().toLocal(), photoUrls: photoUrls, @@ -120,12 +120,21 @@ class Package { cartonIds: cartonIds); } - Map toJson() => { + Map toJsonForReceiving() => { 'id': id, 'tracking_id': trackingID, - 'market': market, + 'fcs_id': fcsID, + "remark": remark, + "photo_urls": photoUrls + }; + + Map toJsonForProcessing() => { + 'id': id, 'fcs_id': fcsID, 'sender_fcs_id': senderFCSID, + 'fcs_shipment_id' : fcsShipmentId, + 'tracking_id': trackingID, + 'market': market, "desc": desc, "remark": remark, "photo_urls": photoUrls @@ -158,7 +167,7 @@ class Package { package.desc != desc || package.remark != remark || package.photoUrls != photoUrls || - package.shipmentId != shipmentId; + package.fcsShipmentId != fcsShipmentId; } @override diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index e7933b3..c2fef5c 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -121,9 +121,10 @@ class User { userUnseenCount: map['user_unseen_count'] ?? 0, fcsUnseenCount: map['fcs_unseen_count'] ?? 0, preferCurrency: map['preferred_currency'], - lastMessageTime: _date == null ? null : _date.toDate(), + lastMessageTime: _date?.toDate(), enablePinLogin: map['enable_pin_login'] ?? false, - pinDigit: map['pin'] ?? ''); + pinDigit: map['pin'] ?? '', + recoveryEmail: map['email'] ?? ""); } bool diffPrivileges(User another) { diff --git a/lib/main_dev.dart b/lib/main_dev.dart index aecddb9..dfe3f4a 100644 --- a/lib/main_dev.dart +++ b/lib/main_dev.dart @@ -19,8 +19,8 @@ Future main() async { Config( flavor: Flavor.DEV, color: Colors.blue, - // apiURL: "http://192.168.100.150:9090", - apiURL: "https://asia-northeast1-fcs-dev1.cloudfunctions.net/API13", + apiURL: "http://192.168.100.150:9090", + // apiURL: "https://asia-northeast1-fcs-dev1.cloudfunctions.net/API13", level: Level.ALL); runApp(App(title: "FCS - Dev")); } diff --git a/lib/pages/carton/cargo_type_addition.dart b/lib/pages/carton/cargo_type_addition.dart index 9216c91..cdca245 100644 --- a/lib/pages/carton/cargo_type_addition.dart +++ b/lib/pages/carton/cargo_type_addition.dart @@ -39,11 +39,11 @@ class _CargoTypeAdditionState extends State { p.isChecked = false; } - widget.cargoTypes.forEach((vp) { + for (var vp in widget.cargoTypes) { if (p.id == vp.id) { p.qty = vp.qty; } - }); + } } if (mounted) { diff --git a/lib/pages/carton/cargo_type_addition_dialog.dart b/lib/pages/carton/cargo_type_addition_dialog.dart new file mode 100644 index 0000000..3939fff --- /dev/null +++ b/lib/pages/carton/cargo_type_addition_dialog.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../domain/entities/cargo_type.dart'; +import '../../helpers/theme.dart'; +import '../main/util.dart'; +import '../rates/model/shipment_rate_model.dart'; +import '../widgets/local_text.dart'; + +class CargoTypeAdditionDialog extends StatefulWidget { + const CargoTypeAdditionDialog({super.key}); + + @override + State createState() => + _CargoTypeAdditionDialogState(); +} + +class _CargoTypeAdditionDialogState extends State { + final _formKey = GlobalKey(); + List cargoTypes = []; + + @override + void initState() { + _init(); + super.initState(); + } + + _init() { + var shipmentRateModel = + Provider.of(context, listen: false); + cargoTypes = + shipmentRateModel.rate.cargoTypes.map((e) => e.clone()).toList(); + var defaultCargoes = cargoTypes.where((e) => e.isDefault).toList(); + for (var p in cargoTypes) { + if (defaultCargoes.any((e) => e.id == p.id)) { + p.isChecked = true; + } else { + p.isChecked = false; + } + } + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + contentPadding: EdgeInsets.zero, + title: Center( + child: LocalText(context, 'box.add.cargo_type', + fontSize: 18, color: primaryColor, fontWeight: FontWeight.bold), + ), + content: SizedBox( + width: MediaQuery.of(context).size.width, + child: SingleChildScrollView( + padding: EdgeInsets.only(top: 10), + child: Form( + key: _formKey, + child: Column( + children: cargoTypes.map((p) { + return ListTile( + minTileHeight: 50, + minVerticalPadding: 0, + onTap: () { + setState(() { + p.isChecked = !p.isChecked; + }); + }, + title: Row( + children: [ + Checkbox( + value: p.isChecked, + activeColor: primaryColor, + side: BorderSide(color: Colors.black38, width: 2), + onChanged: (bool? value) { + if (value != null) { + setState(() { + p.isChecked = value; + }); + } + }), + Expanded( + child: Text( + p.name ?? "", + style: + TextStyle(fontSize: 15.0, color: Colors.black), + ), + ), + ], + )); + }).toList(), + ), + ), + ), + ), + actions: [ + TextButton( + child: LocalText(context, 'btn.cancel', + color: labelColor, fontSize: 14), + onPressed: () { + Navigator.of(context).pop(); + }), + const SizedBox(width: 5), + TextButton( + style: TextButton.styleFrom( + minimumSize: Size(80, 35), + backgroundColor: primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + ), + child: LocalText(context, 'btn.add', + color: Colors.white, fontSize: 14), + onPressed: () async { + if (!_formKey.currentState!.validate()) return; + _save(); + }) + ], + ); + } + + _save() { + try { + var selectedCargos = cargoTypes.where((e) => e.isChecked).toList(); + Navigator.pop>(context, selectedCargos); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } + } +} diff --git a/lib/pages/carton/cargo_widget.dart b/lib/pages/carton/cargo_widget.dart index 0b4345e..bedc1d5 100644 --- a/lib/pages/carton/cargo_widget.dart +++ b/lib/pages/carton/cargo_widget.dart @@ -1,17 +1,19 @@ +// ignore_for_file: unused_local_variable + import 'package:fcs/helpers/theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart'; -import 'package:provider/provider.dart'; import '../../domain/entities/cargo_type.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; -import '../rates/model/shipment_rate_model.dart'; import '../widgets/continue_button.dart'; import '../widgets/local_title.dart'; import '../widgets/previous_button.dart'; import 'cargo_type_addition.dart'; +import 'cargo_type_addition_dialog.dart'; +import 'mix_cargo_type_addition_dialog.dart'; import 'surcharge_item_addition.dart'; typedef OnPrevious = Function( @@ -48,6 +50,12 @@ class _CargoWidgetState extends State { List cargoTypeControllers = []; List surchargeControllers = []; + List _mixCargoTypes = []; + List mixCargoTypeControllers = []; + + bool get isKnownTotalWeight => + totalCtl.text.isNotEmpty && totalCtl.text != '0'; + @override void initState() { _init(); @@ -55,38 +63,38 @@ class _CargoWidgetState extends State { } _init() { + totalCtl.addListener(totalInputChangeListener); // for cargo types if (widget.cargoTypes.isNotEmpty) { - _cargoTypes = List.from(widget.cargoTypes); + List allCargoes = List.from(widget.cargoTypes); + _cargoTypes = allCargoes.where((e) => !e.isMixCargo).toList(); for (var e in _cargoTypes) { var editor = TextEditingController(); editor.text = removeTrailingZeros(e.weight); editor.addListener(inputChangeListener); cargoTypeControllers.add(editor); } + _mixCargoTypes = allCargoes.where((e) => e.isMixCargo).toList(); + for (var e in _mixCargoTypes) { + var editor = TextEditingController(); + editor.text = removeTrailingZeros(e.weight); + editor.addListener(inputChangeListener); + mixCargoTypeControllers.add(editor); + } _calculateTotalWeght(); } else { - var model = context.read(); - var cargoes = model.rate.cargoTypes.map((e) => e.clone()).toList(); - - _cargoTypes = cargoes.where((e) => e.isDefault).toList(); - // ignore: unused_local_variable - for (var e in _cargoTypes) { - var editor = TextEditingController(); - editor.text = ''; - editor.addListener(inputChangeListener); - cargoTypeControllers.add(editor); - } + WidgetsBinding.instance.addPostFrameCallback((_) { + _openCargoTypeSelection(); + }); } //for surcharge items - if (widget.surchargeItems.isNotEmpty) { _surchareItems = List.from(widget.surchargeItems); for (var e in _surchareItems) { var editor = TextEditingController(); editor.text = e.qty.toString(); - editor.addListener(inputChangeListener); + editor.addListener(inputChangeListenerForSurchage); surchargeControllers.add(editor); } } @@ -96,38 +104,85 @@ class _CargoWidgetState extends State { } } - _calculateTotalWeght() { - double total = _cargoTypes.fold(0, (sum, value) => sum + value.weight); - totalCtl.text = removeTrailingZeros(total); + totalInputChangeListener() { + print("Listen isKnownTotalWeight:$isKnownTotalWeight"); + setState(() {}); } - bool isFieldEmpty(int index) { - return cargoTypeControllers[index].text.isEmpty; + inputChangeListenerForSurchage() { + setState(() {}); } - List getEmptyFields() { - List emptyFields = []; - for (int i = 0; i < cargoTypeControllers.length; i++) { - if (isFieldEmpty(i)) { - emptyFields.add(i); - } + _openCargoTypeSelection() async { + List? cargoes = await showDialog( + context: context, builder: (_) => const CargoTypeAdditionDialog()); + if (cargoes == null) return; + _cargoTypes = cargoes.where((e) => !e.isMixCargo).toList(); + _mixCargoTypes = cargoes.where((e) => e.isMixCargo).toList(); + + for (var e in _cargoTypes) { + var editor = TextEditingController(); + editor.text = '0'; + editor.addListener(inputChangeListener); + cargoTypeControllers.add(editor); + } + + for (var e in _mixCargoTypes) { + var editor = TextEditingController(); + editor.text = '0'; + editor.addListener(inputChangeListener); + mixCargoTypeControllers.add(editor); + } + _calculateTotalWeght(); + if (mounted) { + setState(() {}); } - return emptyFields; } + _calculateTotalWeght() { + print("_calculateTotalWeght isKnownTotalWeight:$isKnownTotalWeight"); + double notMixTotal = + _cargoTypes.fold(0, (sum, value) => sum + value.weight); + double mixTotal = + _mixCargoTypes.fold(0, (sum, value) => sum + value.weight); + double total = notMixTotal + mixTotal; + if (isKnownTotalWeight) { + } else { + totalCtl.text = removeTrailingZeros(total); + } + } + + // bool isFieldEmpty(int index) { + // return cargoTypeControllers[index].text.isEmpty; + // } + + // List getEmptyFields() { + // List emptyFields = []; + // for (int i = 0; i < cargoTypeControllers.length; i++) { + // if (isFieldEmpty(i)) { + // emptyFields.add(i); + // } + // } + // return emptyFields; + // } + inputChangeListener() { - List emptyFields = getEmptyFields(); - - if (emptyFields.isEmpty) { - _cargoTypes.asMap().entries.forEach((e) { - _cargoTypes[e.key].weight = - double.tryParse(cargoTypeControllers[e.key].text) ?? 0; - }); - double total = _cargoTypes.fold(0, (sum, value) => sum + value.weight); - setState(() { - totalCtl.text = removeTrailingZeros(total); - }); - } + _cargoTypes.asMap().entries.forEach((e) { + _cargoTypes[e.key].weight = + double.tryParse(cargoTypeControllers[e.key].text) ?? 0; + }); + _mixCargoTypes.asMap().entries.forEach((e) { + _mixCargoTypes[e.key].weight = + double.tryParse(mixCargoTypeControllers[e.key].text) ?? 0; + }); + double notMixTotal = + _cargoTypes.fold(0, (sum, value) => sum + value.weight); + double mixTotal = + _mixCargoTypes.fold(0, (sum, value) => sum + value.weight); + double total = notMixTotal + mixTotal; + setState(() { + totalCtl.text = removeTrailingZeros(total); + }); } @override @@ -163,23 +218,34 @@ class _CargoWidgetState extends State { color: primaryColor, ), onPressed: () async { + List allCargoTypes = _cargoTypes + _mixCargoTypes; CargoType? cargoType = await Navigator.push( context, CupertinoPageRoute( builder: (context) => - CargoTypeAddition(cargoTypes: _cargoTypes))); + CargoTypeAddition(cargoTypes: allCargoTypes))); if (cargoType == null) return; - _cargoTypes.add(cargoType); + if (cargoType.isMixCargo) { + _mixCargoTypes.add(cargoType); + mixCargoTypeControllers.clear(); - cargoTypeControllers.clear(); + for (var e in _mixCargoTypes) { + var editor = TextEditingController(); + editor.text = removeTrailingZeros(e.weight); + editor.addListener(inputChangeListener); + mixCargoTypeControllers.add(editor); + } + } else { + _cargoTypes.add(cargoType); + cargoTypeControllers.clear(); - for (var e in _cargoTypes) { - var editor = TextEditingController(); - editor.text = removeTrailingZeros(e.weight); - editor.addListener(inputChangeListener); - cargoTypeControllers.add(editor); + for (var e in _cargoTypes) { + var editor = TextEditingController(); + editor.text = removeTrailingZeros(e.weight); + editor.addListener(inputChangeListener); + cargoTypeControllers.add(editor); + } } - _calculateTotalWeght(); if (mounted) { setState(() {}); @@ -187,44 +253,150 @@ class _CargoWidgetState extends State { }), ); - final cargosBox = Wrap( + final cargosBox = Padding( + padding: const EdgeInsets.only(top: 10), + child: Wrap( + alignment: WrapAlignment.spaceBetween, + runSpacing: 15, + children: _cargoTypes.asMap().entries.map((e) { + var key = e.key; + var c = e.value; + return SizedBox( + width: MediaQuery.of(context).size.width / 2.3, + child: Row( + children: [ + InkResponse( + radius: 23, + onTap: () { + _cargoTypes.removeAt(key); + + double totalWeight = + double.tryParse(totalCtl.text) ?? 0; + double removeWeight = + (double.tryParse(cargoTypeControllers[key].text) ?? + 0); + + if (totalWeight >= removeWeight) { + double result = totalWeight - removeWeight; + totalCtl.text = removeTrailingZeros(result); + } + + cargoTypeControllers[key].clear(); + + if (mounted) { + setState(() {}); + } + }, + child: Icon(Feather.minus_circle, color: labelColor)), + const SizedBox(width: 10), + Flexible( + child: inputTextFieldWidget(context, + lableText: c.name ?? "", + controller: cargoTypeControllers[key], + suffixIcon: InkResponse( + radius: 23, + onTap: () {}, + child: Icon(Ionicons.md_refresh_circle, + color: labelColor))), + ), + ], + ), + ); + }).toList()), + ); + + final mixCargosBox = Wrap( alignment: WrapAlignment.spaceBetween, runSpacing: 15, - children: _cargoTypes.asMap().entries.map((e) { + children: _mixCargoTypes.asMap().entries.map((e) { var key = e.key; var c = e.value; return SizedBox( width: MediaQuery.of(context).size.width / 2.3, - child: Row( + child: Column( children: [ - InkResponse( - radius: 25, - onTap: () { - _cargoTypes.removeAt(key); + Row( + children: [ + InkResponse( + radius: 23, + onTap: () { + _mixCargoTypes.removeAt(key); - double totalWeight = double.tryParse(totalCtl.text) ?? 0; - double removeWeight = - (double.tryParse(cargoTypeControllers[key].text) ?? + double totalWeight = + double.tryParse(totalCtl.text) ?? 0; + double removeWeight = (double.tryParse( + mixCargoTypeControllers[key].text) ?? 0); - if (totalWeight >= removeWeight) { - double result = totalWeight - removeWeight; - totalCtl.text = removeTrailingZeros(result); - } + if (totalWeight >= removeWeight) { + double result = totalWeight - removeWeight; + totalCtl.text = removeTrailingZeros(result); + } - cargoTypeControllers[key].clear(); + mixCargoTypeControllers[key].clear(); - if (mounted) { - setState(() {}); - } - }, - child: Icon(Feather.minus_circle, color: labelColor)), - const SizedBox(width: 10), - Flexible( - child: inputTextFieldWidget(context, - lableText: c.name ?? "", - controller: cargoTypeControllers[key]), + if (mounted) { + setState(() {}); + } + }, + child: Icon(Feather.minus_circle, + color: labelColor, size: 20)), + const SizedBox(width: 10), + Flexible( + child: inputTextFieldWidget(context, + lableText: c.name ?? "", + controller: mixCargoTypeControllers[key], + suffixIcon: InkResponse( + radius: 23, + onTap: () {}, + child: Icon(Ionicons.md_refresh_circle, + color: labelColor, size: 22))), + ), + InkResponse( + radius: 23, + onTap: () async { + List? cargoes = await showDialog( + context: context, + builder: (_) => MixCargoTypeAdditionDialog( + cargoTypes: c.mixCargoes)); + if (cargoes == null) return; + setState(() { + c.mixCargoes = List.from(cargoes); + }); + }, + child: + Icon(Icons.add_circle, color: labelColor, size: 22)) + ], ), + c.mixCargoes.isEmpty + ? const SizedBox() + : Padding( + padding: const EdgeInsets.only(top: 5), + child: Column( + children: c.mixCargoes.map((e) { + return Padding( + padding: const EdgeInsets.only(top: 12), + child: Row( + children: [ + const SizedBox(width: 25), + InkResponse( + radius: 23, + onTap: () { + setState(() { + c.mixCargoes.remove(e); + }); + }, + child: Icon(Feather.minus_circle, + color: labelColor, size: 20)), + Padding( + padding: const EdgeInsets.only(left: 10), + child: Text(e.name ?? ""), + ), + ], + ), + ); + }).toList()), + ) ], ), ); @@ -250,28 +422,32 @@ class _CargoWidgetState extends State { child: inputTextFieldWidget(context, lableText: "Total", controller: totalCtl, - readOnly: getEmptyFields().isEmpty, onChanged: (neValue) { - List emptyFields = getEmptyFields(); - if (emptyFields.length == 1) { - double totalWeight = double.tryParse(neValue) ?? 0; + // onChanged: (neValue) { + // List emptyFields = getEmptyFields(); + // if (emptyFields.length == 1) { + // double totalWeight = double.tryParse(neValue) ?? 0; - _cargoTypes.asMap().entries.forEach((e) { - _cargoTypes[e.key].weight = - double.tryParse(cargoTypeControllers[e.key].text) ?? - 0; - }); - double result = _cargoTypes.fold( - 0, (sum, value) => sum + value.weight); + // _cargoTypes.asMap().entries.forEach((e) { + // _cargoTypes[e.key].weight = + // double.tryParse(cargoTypeControllers[e.key].text) ?? + // 0; + // }); + // double result = _cargoTypes.fold( + // 0, (sum, value) => sum + value.weight); - if (totalWeight >= result) { - double remaining = totalWeight - result; - setState(() { - cargoTypeControllers[emptyFields.first].text = - removeTrailingZeros(remaining); - }); - } - } - }), + // if (totalWeight >= result) { + // double remaining = totalWeight - result; + // setState(() { + // cargoTypeControllers[emptyFields.first].text = + // removeTrailingZeros(remaining); + // }); + // } + // } + // }, + suffixIcon: InkResponse( + radius: 23, + child: Icon(Ionicons.md_refresh_circle, + color: labelColor))), ), ], )), @@ -308,41 +484,44 @@ class _CargoWidgetState extends State { }), ); - final subChargeItemsBox = Wrap( - alignment: WrapAlignment.spaceBetween, - runSpacing: 15, - children: _surchareItems.asMap().entries.map((e) { - var key = e.key; - var c = e.value; - return SizedBox( - width: MediaQuery.of(context).size.width / 2.3, - child: Row( - children: [ - InkResponse( - radius: 25, - onTap: () { - setState(() { - _surchareItems.removeAt(key); - }); - }, - child: Icon(Feather.minus_circle, color: labelColor)), - const SizedBox(width: 10), - Flexible( - child: inputTextFieldWidget( - context, - lableText: c.name ?? "", - controller: surchargeControllers[key], - onChanged: (newValue) { - setState(() { - _surchareItems[key].qty = int.tryParse(newValue) ?? 0; - }); - }, + final subChargeItemsBox = Padding( + padding: const EdgeInsets.only(top: 10), + child: Wrap( + alignment: WrapAlignment.spaceBetween, + runSpacing: 15, + children: _surchareItems.asMap().entries.map((e) { + var key = e.key; + var c = e.value; + return SizedBox( + width: MediaQuery.of(context).size.width / 2.3, + child: Row( + children: [ + InkResponse( + radius: 25, + onTap: () { + setState(() { + _surchareItems.removeAt(key); + }); + }, + child: Icon(Feather.minus_circle, color: labelColor)), + const SizedBox(width: 10), + Flexible( + child: inputTextFieldWidget( + context, + lableText: c.name ?? "", + controller: surchargeControllers[key], + onChanged: (newValue) { + setState(() { + _surchareItems[key].qty = int.tryParse(newValue) ?? 0; + }); + }, + ), ), - ), - ], - ), - ); - }).toList()); + ], + ), + ); + }).toList()), + ); final continueBtn = ContinueButton( onTap: () { @@ -354,14 +533,17 @@ class _CargoWidgetState extends State { return; } - widget.onContinue!(_cargoTypes, _surchareItems); + var allCargoes = _cargoTypes + _mixCargoTypes; + + widget.onContinue!(allCargoes, _surchareItems); } }, ); final previousBtn = PreviousButton(onTap: () { if (widget.onPrevious != null) { - widget.onPrevious!(_cargoTypes, _surchareItems); + var allCargoes = _cargoTypes + _mixCargoTypes; + widget.onPrevious!(allCargoes, _surchareItems); } }); @@ -376,9 +558,18 @@ class _CargoWidgetState extends State { userRow, cargoTitle, cargosBox, - const SizedBox(height: 15), - Divider(), - const SizedBox(height: 5), + _mixCargoTypes.isNotEmpty && _cargoTypes.isNotEmpty + ? Padding( + padding: const EdgeInsets.symmetric( + horizontal: 100, vertical: 25), + child: Divider(color: Colors.grey.shade300), + ) + : const SizedBox(), + mixCargosBox, + Padding( + padding: const EdgeInsets.symmetric(vertical: 25), + child: Divider(color: Colors.grey.shade300), + ), totalWeightBox, subchargeItemTitleBox, subChargeItemsBox, @@ -408,7 +599,8 @@ class _CargoWidgetState extends State { {required String lableText, TextEditingController? controller, Function(String)? onChanged, - bool readOnly = false}) { + bool readOnly = false, + Widget? suffixIcon}) { return TextFormField( controller: controller, style: textStyle, @@ -417,6 +609,7 @@ class _CargoWidgetState extends State { onChanged: onChanged, readOnly: readOnly, decoration: InputDecoration( + suffixIcon: suffixIcon, contentPadding: EdgeInsets.all(0), labelText: lableText, labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17), diff --git a/lib/pages/carton/carton_info.dart b/lib/pages/carton/carton_info.dart index 356d7e4..5754636 100644 --- a/lib/pages/carton/carton_info.dart +++ b/lib/pages/carton/carton_info.dart @@ -295,18 +295,42 @@ class _CartonInfoState extends State { padding: const EdgeInsets.symmetric(vertical: 2), child: Container( color: e.key.isEven ? Colors.grey.shade300 : oddColor, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - e.value.name ?? "", - style: - TextStyle(color: Colors.black, fontSize: 15), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e.value.name ?? "", + style: TextStyle( + color: Colors.black, fontSize: 15), + ), + Text( + "${removeTrailingZeros(e.value.weight)} lb", + textAlign: TextAlign.end, + style: TextStyle( + color: Colors.black, fontSize: 15)) + ], ), - Text("${removeTrailingZeros(e.value.weight)} lb", - textAlign: TextAlign.end, - style: TextStyle( - color: Colors.black, fontSize: 15)) + e.value.isMixCargo + ? Padding( + padding: const EdgeInsets.only(left: 20), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: e.value.mixCargoes.map((c) { + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 2), + child: Text( + "- ${c.name}", + style: TextStyle(fontSize: 14), + ), + ); + }).toList()), + ) + : const SizedBox() ], ), ), diff --git a/lib/pages/carton/carton_package_form.dart b/lib/pages/carton/carton_package_form.dart index a4b1567..ce911ed 100644 --- a/lib/pages/carton/carton_package_form.dart +++ b/lib/pages/carton/carton_package_form.dart @@ -236,6 +236,7 @@ class _CartonPackageFormState extends State { } } + _create() async { setState(() { _isLoading = true; diff --git a/lib/pages/carton/mix_cargo_type_addition_dialog.dart b/lib/pages/carton/mix_cargo_type_addition_dialog.dart new file mode 100644 index 0000000..2a4523b --- /dev/null +++ b/lib/pages/carton/mix_cargo_type_addition_dialog.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../domain/entities/cargo_type.dart'; +import '../../helpers/theme.dart'; +import '../main/util.dart'; +import '../rates/model/shipment_rate_model.dart'; +import '../widgets/local_text.dart'; + +class MixCargoTypeAdditionDialog extends StatefulWidget { + final List cargoTypes; + const MixCargoTypeAdditionDialog({super.key, required this.cargoTypes}); + + @override + State createState() => + _MixCargoTypeAdditionDialogState(); +} + +class _MixCargoTypeAdditionDialogState + extends State { + final _formKey = GlobalKey(); + List cargoTypes = []; + + @override + void initState() { + _init(); + super.initState(); + } + + _init() { + var shipmentRateModel = + Provider.of(context, listen: false); + var cargoes = + shipmentRateModel.rate.cargoTypes.map((e) => e.clone()).toList(); + cargoTypes = cargoes.where((e) => !e.isMixCargo).toList(); + + for (var p in cargoTypes) { + if (widget.cargoTypes.any((e) => e.id == p.id)) { + p.isChecked = true; + } else { + p.isChecked = false; + } + } + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + contentPadding: EdgeInsets.zero, + title: Center( + child: LocalText(context, 'box.mix_cargo.title', + fontSize: 18, color: primaryColor, fontWeight: FontWeight.bold), + ), + content: SizedBox( + width: MediaQuery.of(context).size.width, + child: SingleChildScrollView( + padding: EdgeInsets.only(top: 10), + child: Form( + key: _formKey, + child: Column( + children: cargoTypes.map((p) { + return ListTile( + minTileHeight: 50, + minVerticalPadding: 0, + onTap: () { + setState(() { + p.isChecked = !p.isChecked; + }); + }, + title: Row( + children: [ + Checkbox( + value: p.isChecked, + activeColor: primaryColor, + side: BorderSide(color: Colors.black38, width: 2), + onChanged: (bool? value) { + if (value != null) { + setState(() { + p.isChecked = value; + }); + } + }), + Expanded( + child: Text( + p.name ?? "", + style: + TextStyle(fontSize: 15.0, color: Colors.black), + ), + ), + ], + )); + }).toList(), + ), + ), + ), + ), + actions: [ + TextButton( + child: LocalText(context, 'btn.cancel', + color: labelColor, fontSize: 14), + onPressed: () { + Navigator.of(context).pop(); + }), + const SizedBox(width: 5), + TextButton( + style: TextButton.styleFrom( + minimumSize: Size(80, 35), + backgroundColor: primaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + ), + child: LocalText(context, 'btn.add', + color: Colors.white, fontSize: 14), + onPressed: () async { + if (!_formKey.currentState!.validate()) return; + _save(); + }) + ], + ); + } + + _save() { + try { + var selectedCargos = cargoTypes.where((e) => e.isChecked).toList(); + Navigator.pop>(context, selectedCargos); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } + } +} diff --git a/lib/pages/carton/model/package_selection_model.dart b/lib/pages/carton/model/package_selection_model.dart index de6d77a..8e1203a 100644 --- a/lib/pages/carton/model/package_selection_model.dart +++ b/lib/pages/carton/model/package_selection_model.dart @@ -160,7 +160,7 @@ class PackageSelectionModel extends BaseModel { whereIn: [package_processed_status, package_packed_status]) .where("sender_id", isEqualTo: senderId) .where("user_id", isEqualTo: consigneeId) - // .where("fcs_shipment_id", isEqualTo: shipmentId) + .where("fcs_shipment_id", isEqualTo: shipmentId) .where("is_deleted", isEqualTo: false) .orderBy("created_date", descending: true) .get(const GetOptions(source: Source.server)); diff --git a/lib/pages/carton/packages_widget.dart b/lib/pages/carton/packages_widget.dart index a2abb2d..69933dc 100644 --- a/lib/pages/carton/packages_widget.dart +++ b/lib/pages/carton/packages_widget.dart @@ -9,6 +9,7 @@ import '../../domain/entities/package.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; import '../widgets/continue_button.dart'; +import '../widgets/local_text.dart'; import '../widgets/local_title.dart'; import '../widgets/previous_button.dart'; import 'model/package_selection_model.dart'; @@ -41,6 +42,7 @@ class _PackagesWidgetState extends State { final _scrollController = ScrollController(); bool _down = true; List _packages = []; + bool _isLoading = false; @override void initState() { @@ -56,12 +58,14 @@ class _PackagesWidgetState extends State { _init() async { _packages.clear(); + _isLoading = true; var packageModel = context.read(); var list = await packageModel.getActivePackages( shipmentId: widget.shipment.id!, senderId: widget.sender.id!, consigneeId: widget.consignee.id!); _packages = List.from(list); + _isLoading = false; if (mounted) { setState(() {}); } @@ -93,6 +97,10 @@ class _PackagesWidgetState extends State { final continueBtn = ContinueButton( onTap: () { + if (_packages.isEmpty) { + showMsgDialog(context, 'Error', "Please add the packages"); + return false; + } if (widget.onContinue != null) { widget.onContinue!(_packages); } @@ -135,21 +143,25 @@ class _PackagesWidgetState extends State { : const SizedBox(), ), Expanded( - child: RefreshIndicator( - color: primaryColor, - onRefresh: () async { - _init(); - }, - child: ListView.builder( - padding: const EdgeInsets.only(top: 10), - controller: _scrollController, - shrinkWrap: true, - physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - Package package = _packages[index]; - return packageRow(context, package); + child: _packages.isEmpty && !_isLoading + ? Center( + child: LocalText(context, 'box.no_package', + color: Colors.black, fontSize: 15)) + : RefreshIndicator( + color: primaryColor, + onRefresh: () async { + _init(); }, - itemCount: _packages.length)), + child: ListView.builder( + padding: const EdgeInsets.only(top: 10), + controller: _scrollController, + shrinkWrap: true, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + Package package = _packages[index]; + return packageRow(context, package); + }, + itemCount: _packages.length)), ), ], ), diff --git a/lib/pages/chat/message_detail.dart b/lib/pages/chat/message_detail.dart index f8df737..2f71dbc 100644 --- a/lib/pages/chat/message_detail.dart +++ b/lib/pages/chat/message_detail.dart @@ -185,7 +185,7 @@ class MessageDetail extends StatelessWidget { } else { CustomerModel customerModel = Provider.of(context, listen: false); - User user = await customerModel.getUser(message.messageID); + User? user = await customerModel.getUser(message.messageID); Navigator.of(context).push(CupertinoPageRoute( builder: (context) => CustomerEditor(customer: user))); } diff --git a/lib/pages/customer/customer_detail.dart b/lib/pages/customer/customer_detail.dart new file mode 100644 index 0000000..a401a20 --- /dev/null +++ b/lib/pages/customer/customer_detail.dart @@ -0,0 +1,160 @@ +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/customer/model/customer_model.dart'; +import 'package:fcs/pages/widgets/local_app_bar.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../../domain/entities/user.dart'; +import '../main/util.dart'; +import '../widgets/display_text.dart'; +import '../widgets/fcs_id_icon.dart'; + +class CustomerDetail extends StatefulWidget { + final String fcsId; + const CustomerDetail({super.key, required this.fcsId}); + + @override + State createState() => _CustomerDetailState(); +} + +class _CustomerDetailState extends State { + GlobalKey key = GlobalKey(); + User? user; + bool _isLoading = false; + @override + void initState() { + _loadUser(); + super.initState(); + } + + _loadUser() async { + try { + _isLoading = true; + user = await context.read().getUserByFCSId(widget.fcsId); + } finally { + _isLoading = false; + } + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + final nameBox = DisplayText( + text: user?.name ?? '', + labelTextKey: "profile.name", + iconData: Icons.person, + ); + + final fcsIDBox = Row( + children: [ + Expanded( + child: DisplayText( + text: user?.fcsID ?? "", + labelTextKey: "customer.fcs.id", + icon: FcsIDIcon(), + ), + ), + IconButton( + icon: Icon(Icons.content_copy, color: Colors.grey), + onPressed: () => _copy( + getLocalString(context, "customer.fcs.id"), user?.fcsID ?? ""), + ) + ], + ); + + final phoneBox = Row( + children: [ + Expanded( + child: DisplayText( + text: user?.phoneNumber ?? "", + labelTextKey: "contact.phone", + iconData: FontAwesome.phone), + ), + IconButton( + icon: Icon(MaterialIcons.open_in_new, color: Colors.grey), + onPressed: () { + if (user == null) return; + if (user!.phoneNumber != null && user!.phoneNumber != "") { + launch( + "tel:${user!.phoneNumber ?? "".trim().replaceAll(' ', '')}"); + } + }, + ) + ], + ); + + final emailBox = Padding( + padding: const EdgeInsets.only(top: 8), + child: Row( + children: [ + Expanded( + child: DisplayText( + text: user?.recoveryEmail ?? "", + labelTextKey: "profile.recovery.email", + iconData: Icons.email_outlined), + ), + IconButton( + icon: Icon(MaterialIcons.open_in_new, color: Colors.grey), + onPressed: () { + if (user == null) return; + if (user!.recoveryEmail != null && user!.recoveryEmail != "") { + launch("mailto:${user?.recoveryEmail ?? ""}"); + } + }, + ) + ], + ), + ); + + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + key: key, + appBar: LocalAppBar( + backgroundColor: Colors.white, + arrowColor: primaryColor, + labelColor: primaryColor, + labelKey: 'customer.detail.title'), + body: ListView( + padding: EdgeInsets.symmetric(horizontal: 10), + children: [ + nameBox, + const SizedBox(height: 8), + fcsIDBox, + const SizedBox(height: 8), + phoneBox, + (user != null && user!.recoveryEmail != null && user!.recoveryEmail != "") + ? emailBox + : const SizedBox() + ], + ), + ), + ); + } + + _copy(String title, String data) { + Clipboard.setData(ClipboardData(text: data)); + // showToast(key, 'copied "$title" data to clipboard'); + _showToast(title); + } + + _showToast(String title) { + ScaffoldMessengerState? scaffold = key.currentState; + + scaffold ??= ScaffoldMessenger.of(context); + + scaffold.showSnackBar( + SnackBar( + content: Text('copied "$title" data to clipboard'), + backgroundColor: secondaryColor, + duration: Duration(seconds: 1), + ), + ); + } +} diff --git a/lib/pages/customer/model/customer_model.dart b/lib/pages/customer/model/customer_model.dart index 40f4fed..851b798 100644 --- a/lib/pages/customer/model/customer_model.dart +++ b/lib/pages/customer/model/customer_model.dart @@ -37,7 +37,8 @@ class CustomerModel extends BaseModel { rowPerLoad: 30); } - Future getUser(String? id) async { + Future getUser(String? id) async { + if (id == null) return null; String path = "/$user_collection"; var snap = await FirebaseFirestore.instance.collection(path).doc(id).get(); return User.fromMap(snap.data() as Map, snap.id); @@ -76,4 +77,20 @@ class CustomerModel extends BaseModel { Future acceptRequest(String userID) { return Services.instance.userService.acceptRequest(userID); } + + Future getUserByFCSId(String? fcsID) async { + if (fcsID == null) return null; + String path = "/$user_collection"; + var snap = await FirebaseFirestore.instance + .collection(path) + .where('fcs_id', isEqualTo: fcsID) + .limit(1) + .get(); + + if (snap.docs.isNotEmpty) { + return User.fromMap(snap.docs.first.data(), snap.docs.first.id); + } else { + return null; + } + } } diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index 02af620..cba4d63 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -125,7 +125,11 @@ class _HomePageState extends State { if (!isCustomer) { CustomerModel customerModel = Provider.of(context, listen: false); - user = await customerModel.getUser(receiverID); + + var u = await customerModel.getUser(receiverID); + if (u != null) { + user = u; + } } Navigator.push( context, diff --git a/lib/pages/main/util.dart b/lib/pages/main/util.dart index 133c03f..98e1837 100644 --- a/lib/pages/main/util.dart +++ b/lib/pages/main/util.dart @@ -5,11 +5,14 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../customer/customer_detail.dart'; import '../widgets/label_widgets.dart'; final log = Logger('Util'); @@ -494,7 +497,15 @@ Widget userDisplayBox(BuildContext context, LocalText(context, lableKey, color: Colors.black54, fontSize: 15), InkWell( - onTap: null, + onTap: showLink + ? () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + CustomerDetail(fcsId: fcsID))); + } + : null, child: Text(name ?? '', style: showLink ? TextStyle( @@ -518,3 +529,36 @@ Widget userDisplayBox(BuildContext context, ) : const SizedBox(); } + +Widget settingRow(BuildContext context, + {required String label, + IconData? iconData, + Widget? image, + Function()? onTap, + String? text}) { + return ListTile( + minTileHeight: 50, + contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + onTap: onTap, + leading: iconData != null + ? Icon(iconData, color: primaryColor) + : image ?? const SizedBox(), + title: LocalText(context, label, fontSize: 15, color: Colors.black54), + subtitle: text != null + ? Padding( + padding: const EdgeInsets.only(right: 10), + child: Text( + text, + style: const TextStyle(color: Colors.black), + ), + ) + : const SizedBox(), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SimpleLineIcons.arrow_right, color: labelColor, size: 16), + ], + ), + ); +} + diff --git a/lib/pages/package/model/package_model.dart b/lib/pages/package/model/package_model.dart index 7f4d84b..425e985 100644 --- a/lib/pages/package/model/package_model.dart +++ b/lib/pages/package/model/package_model.dart @@ -276,11 +276,6 @@ class PackageModel extends BaseModel { return pkgs.where((e) => seen.add(e)).toList(); } - Future createPackages(User user, List packages) { - return Services.instance.packageService - .createPackages(packages, user.fcsID!); - } - Future createReceiving( User? user, Package package, List? files) async { if (user != null) { @@ -364,14 +359,15 @@ class PackageModel extends BaseModel { var count = (package.photoUrls.length) + files.length - (deletedUrls.length); - if (count > uploadPhotoLimit) + if (count > uploadPhotoLimit) { throw Exception("Exceed number of file upload"); + } package.photoUrls = package.photoUrls; String path = Path.join(pkg_files_path); uploadedURL = await uploadFiles(path, files); - uploadedURL.forEach((url) { + for (var url in uploadedURL) { package.photoUrls.add(url); - }); + } package.photoUrls.removeWhere((e) => deletedUrls.contains(e)); } try { diff --git a/lib/pages/package/package_info.dart b/lib/pages/package/package_info.dart index 111e2f9..3581b46 100644 --- a/lib/pages/package/package_info.dart +++ b/lib/pages/package/package_info.dart @@ -70,10 +70,10 @@ class _PackageInfoState extends State { } _loadShipment() async { - if (widget.package.shipmentId == null) return; + if (widget.package.fcsShipmentId == null) return; var s = await context .read() - .getFcsShipment(widget.package.shipmentId!); + .getFcsShipment(widget.package.fcsShipmentId!); _shipment = s; if (mounted) { setState(() {}); @@ -178,17 +178,17 @@ class _PackageInfoState extends State { iconData: Ionicons.ios_airplane, ), ), - Flexible( - child: DisplayText( - text: _shipment != null - ? _shipment!.processingDate != null - ? dateFormatter.format(_shipment!.processingDate!) - : "" - : "", - labelTextKey: "package.processing.date", - iconData: Icons.date_range, - ), - ), + // Flexible( + // child: DisplayText( + // text: _shipment != null + // ? _shipment!.processingDate != null + // ? dateFormatter.format(_shipment!.processingDate!) + // : "" + // : "", + // labelTextKey: "package.processing.date", + // iconData: Icons.date_range, + // ), + // ), ], ), Row( diff --git a/lib/pages/package/package_new.dart b/lib/pages/package/package_new.dart deleted file mode 100644 index 9b91118..0000000 --- a/lib/pages/package/package_new.dart +++ /dev/null @@ -1,208 +0,0 @@ -import 'package:fcs/domain/entities/package.dart'; -import 'package:fcs/domain/entities/user.dart'; -import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/package/tracking_id_page.dart'; -import 'package:fcs/pages/user_search/user_search.dart'; -import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/widgets/display_text.dart'; -import 'package:fcs/pages/widgets/fcs_id_icon.dart'; -import 'package:fcs/pages/widgets/local_text.dart'; -import 'package:fcs/pages/widgets/progress.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import 'model/package_model.dart'; - -typedef void FindCallBack(); - -class PackageNew extends StatefulWidget { - const PackageNew(); - @override - _PackageNewState createState() => _PackageNewState(); -} - -class _PackageNewState extends State { - bool _isLoading = false; - User? user; - - List packages = []; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - var fcsIDBox = Row( - children: [ - Expanded( - child: DisplayText( - text: user != null ? user!.fcsID : "", - labelTextKey: "package.create.fcs.id", - icon: FcsIDIcon(), - )), - IconButton( - icon: Icon(Icons.search, color: primaryColor), - onPressed: () => searchUser(context, onUserSelect: (u) { - setState(() { - this.user = u; - }); - })), - ], - ); - final namebox = DisplayText( - text: user != null ? user!.name : "", - labelTextKey: "package.create.name", - iconData: Icons.person, - ); - final phoneNumberBox = DisplayText( - text: user != null ? user!.phoneNumber : "", - labelTextKey: "package.create.phone", - iconData: Icons.phone, - ); - final createButton = fcsButton( - context, - getLocalString(context, 'package.create.packages'), - callack: _create, - ); - final packageList = Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: new List.generate( - this.packages.length, (index) => _packageItem(context, index)) - .toList(), - ); - - return LocalProgress( - inAsyncCall: _isLoading, - child: Scaffold( - appBar: AppBar( - centerTitle: true, - leading: new IconButton( - icon: new Icon(CupertinoIcons.back, color: primaryColor, size: 30), - onPressed: () => Navigator.of(context).pop(), - ), - shadowColor: Colors.transparent, - backgroundColor: Colors.white, - title: LocalText( - context, - "package.create.title", - fontSize: 20, - color: primaryColor, - ), - ), - body: Padding( - padding: const EdgeInsets.only(left: 12.0, right: 12), - child: ListView( - children: [ - fcsIDBox, - phoneNumberBox, - namebox, - Divider(), - Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text("Packages (${packages.length})"), - SizedBox( - width: 30, - ), - IconButton( - icon: Icon( - Icons.add, - color: primaryColor, - ), - onPressed: _addPackage, - ) - ], - )), - packageList, - Divider(), - SizedBox( - height: 20, - ), - createButton, - SizedBox( - height: 10, - ), - ], - ), - ), - )); - } - - Widget _packageItem(BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0, left: 15), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(packages[index].market!), - Text(packages[index].trackingID!), - // DisplayText( - // labelText: "Tracking ID", - // text: packages[index].trackingID, - // ), - ], - ), - ), - IconButton( - icon: Icon( - Icons.remove, - color: primaryColor, - ), - onPressed: () { - setState(() { - packages.removeAt(index); - }); - }, - ) - ], - ), - ); - } - - _addPackage() async { - Package? package = await Navigator.push( - context, - CupertinoPageRoute(builder: (context) => TrackingIDPage()), - ); - - if (package != null) { - if (packages.any((e) => e.trackingID == package.trackingID)) { - showMsgDialog(context, "Error", "Already scanned!"); - return; - } - setState(() { - packages.add(package); - }); - } - } - - _create() async { - if (user == null || packages.length == 0) { - showMsgDialog(context, "Error", "Invalid user!"); - return; - } - setState(() { - _isLoading = true; - }); - PackageModel packageModel = - Provider.of(context, listen: false); - try { - await packageModel.createPackages(user!, packages); - Navigator.pop(context); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } finally { - setState(() { - _isLoading = false; - }); - } - } -} diff --git a/lib/pages/processing/package_editor.dart b/lib/pages/processing/package_editor.dart index c3bbe08..1fbf55b 100644 --- a/lib/pages/processing/package_editor.dart +++ b/lib/pages/processing/package_editor.dart @@ -253,6 +253,7 @@ class _PackageEditorState extends State { _package!.photoFiles = multiImgController.getUpdatedFile; _package!.fcsID = widget.consignee.fcsID; _package!.senderFCSID = widget.sender.fcsID ?? ""; + _package!.fcsShipmentId = widget.shipment.id; await packageModel.updateProcessing(_package!, multiImgController.getAddedFile, multiImgController.getDeletedUrl); diff --git a/lib/pages/processing/processing_edit_editor.dart b/lib/pages/processing/processing_edit_editor.dart index e286bd2..2fbf055 100644 --- a/lib/pages/processing/processing_edit_editor.dart +++ b/lib/pages/processing/processing_edit_editor.dart @@ -72,9 +72,9 @@ class _ProcessingEditEditorState extends State { var fcsShipments = await context.read().getActiveFcsShipments(); _shipments = fcsShipments; - + var s = FcsShipment( - id: widget.package.id, shipmentNumber: widget.package.shipmentNumber); + id: widget.package.fcsShipmentId, shipmentNumber: widget.package.fcsShipmentNumber); if (_shipments.contains(s)) { _shipment = s; @@ -290,9 +290,10 @@ class _ProcessingEditEditorState extends State { _package!.desc = _descCtl.text; _package!.remark = _remarkCtl.text; _package!.market = selectedMarket ?? ""; + _package!.fcsShipmentId = _shipment?.id; await packageModel.updateProcessing(_package!, multiImgController.getAddedFile, multiImgController.getDeletedUrl); - Navigator.pop(context); + Navigator.pop(context,true); } catch (e) { showMsgDialog(context, "Error", e.toString()); } finally { @@ -310,7 +311,7 @@ class _ProcessingEditEditorState extends State { desc: _descCtl.text, remark: _remarkCtl.text, photoUrls: widget.package.photoUrls, - shipmentId: _shipment?.id); + fcsShipmentId: _shipment?.id); return widget.package.isChangedForEditProcessing(package) || multiImgController.getAddedFile.isNotEmpty || multiImgController.getDeletedUrl.isNotEmpty; diff --git a/lib/pages/processing/processing_info.dart b/lib/pages/processing/processing_info.dart index 4eedacd..5b965d3 100644 --- a/lib/pages/processing/processing_info.dart +++ b/lib/pages/processing/processing_info.dart @@ -40,10 +40,10 @@ class _ProcessingInfoState extends State { void initState() { super.initState(); _initPackage(widget.package); - _loadShipment(); } _initPackage(Package package) { + _loadShipment(); setState(() { _package = package; multiImgController.setImageUrls = package.photoUrls; @@ -51,10 +51,10 @@ class _ProcessingInfoState extends State { } _loadShipment() async { - if (widget.package.shipmentId == null) return; + if (widget.package.fcsShipmentId == null) return; var s = await context .read() - .getFcsShipment(widget.package.shipmentId!); + .getFcsShipment(widget.package.fcsShipmentId!); _shipment = s; if (mounted) { setState(() {}); @@ -123,17 +123,17 @@ class _ProcessingInfoState extends State { iconData: Ionicons.ios_airplane, ), ), - Flexible( - child: DisplayText( - text: _shipment != null - ? _shipment!.processingDate != null - ? dateFormatter.format(_shipment!.processingDate!) - : "" - : "", - labelTextKey: "package.processing.date", - iconData: Icons.date_range, - ), - ), + // Flexible( + // child: DisplayText( + // text: _shipment != null + // ? _shipment!.processingDate != null + // ? dateFormatter.format(_shipment!.processingDate!) + // : "" + // : "", + // labelTextKey: "package.processing.date", + // iconData: Icons.date_range, + // ), + // ), ], ), Row( @@ -241,13 +241,11 @@ class _ProcessingInfoState extends State { _gotoEditor() async { if (_package == null) return; - bool? deleted = await Navigator.push( + bool? updated = await Navigator.push( context, CupertinoPageRoute( builder: (context) => ProcessingEditEditor(package: _package!))); - if (deleted ?? false) { - Navigator.pop(context); - } else { + if (updated ?? false) { PackageModel packageModel = Provider.of(context, listen: false); Package? p = await packageModel.getPackage(_package!.id!); diff --git a/lib/pages/profile/add_recovery_email.dart b/lib/pages/profile/add_recovery_email.dart index a7a15b5..be69dec 100644 --- a/lib/pages/profile/add_recovery_email.dart +++ b/lib/pages/profile/add_recovery_email.dart @@ -74,7 +74,7 @@ class _AddRecoveryEmailState extends State { padding: const EdgeInsets.only(left: 15, right: 15, top: 10), children: [ LocalText(context, 'profile.email_instruction', - fontSize: 16, color: Colors.black), + fontSize: 16, color: labelColor), const SizedBox(height: 15), emailBox, const SizedBox(height: 30), diff --git a/lib/pages/profile/confirm_phone_number.dart b/lib/pages/profile/confirm_phone_number.dart index e593c5e..4a659dc 100644 --- a/lib/pages/profile/confirm_phone_number.dart +++ b/lib/pages/profile/confirm_phone_number.dart @@ -89,7 +89,7 @@ class _ConfirmPhoneNumberState extends State { child: Row( children: [ Flexible( - child: LocalText(context, "sms.six.digit", + child: LocalText(context, "profile.confirm.instruction", fontSize: 16, color: labelColor), ), ], diff --git a/lib/pages/profile/confirm_recovery_email.dart b/lib/pages/profile/confirm_recovery_email.dart index 800d7c9..0c6a97d 100644 --- a/lib/pages/profile/confirm_recovery_email.dart +++ b/lib/pages/profile/confirm_recovery_email.dart @@ -75,7 +75,7 @@ class _ConfirmRecoveryEmailState extends State { fontWeight: FontWeight.normal, ), const SizedBox(height: 40), - LocalText(context, "sms.code", + LocalText(context, "profile.confirm_email_code", color: labelColor, fontSize: 16), Container( padding: const EdgeInsets.only(top: 10), diff --git a/lib/pages/profile/profile_page.dart b/lib/pages/profile/profile_page.dart index 5c1b925..19fe3ec 100644 --- a/lib/pages/profile/profile_page.dart +++ b/lib/pages/profile/profile_page.dart @@ -2,6 +2,7 @@ import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/domain/vo/privilege.dart'; import 'package:fcs/localization/transalation.dart'; import 'package:fcs/pages/delivery_address/delivery_address_list.dart'; +import 'package:fcs/pages/delivery_address/delivery_address_row.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; @@ -9,7 +10,6 @@ import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/profile/profile_currency_edit.dart'; import 'package:fcs/pages/profile/profile_edit.dart'; import 'package:fcs/pages/staff/model/staff_model.dart'; -import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; @@ -78,112 +78,110 @@ class _ProfileState extends State { buildLanguage(languageModel); var deliveryAddressModel = Provider.of(context); - final currencyBox = Row( - children: [ - Expanded( + final currencyBox = settingRow( + context, + label: 'profile.currency', + iconData: FontAwesome5Solid.money_bill_wave, + text: user.preferCurrency ?? "", + onTap: () { + _editCurrency(); + }, + ); + + final fcsIDBox = Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Row( + children: [ + Expanded( child: DisplayText( - text: user.preferCurrency ?? "", - labelTextKey: "profile.currency", - iconData: FontAwesome5Regular.money_bill_alt, - )), - Padding( - padding: const EdgeInsets.only(right: 0), - child: IconButton( - icon: Icon(Icons.edit, color: Colors.grey), - onPressed: _editCurrency), - ) - ], - ); - - final deleteAccountBox = DisplayText( - labelTextKey: "profile.delete.title", - iconData: MaterialCommunityIcons.account_remove, - ); - - final fcsIDBox = Row( - children: [ - Expanded( - child: DisplayText( - text: user.fcsID ?? "", - labelTextKey: "customer.fcs.id", - icon: FcsIDIcon(), + text: user.fcsID ?? "", + labelTextKey: "customer.fcs.id", + icon: FcsIDIcon(), + ), ), - ), - IconButton( - icon: Icon(Icons.content_copy, color: Colors.grey), - onPressed: () => _copy( - getLocalString(context, "customer.fcs.id"), user.fcsID ?? ""), - ) - ], + IconButton( + icon: Icon(Icons.content_copy, color: Colors.grey), + onPressed: () => _copy( + getLocalString(context, "customer.fcs.id"), user.fcsID ?? ""), + ) + ], + ), ); - final usaShippingAddressBox = Row( - children: [ - Expanded( - child: DisplayText( - text: mainModel.setting!.usaAddress ?? "", - labelTextKey: "profile.usa.shipping.address", - iconData: Icons.location_on, + final usaShippingAddressBox = Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Row( + children: [ + Expanded( + child: DisplayText( + text: mainModel.setting!.usaAddress ?? "", + labelTextKey: "profile.usa.shipping.address", + iconData: Icons.location_on, + ), ), - ), - IconButton( - icon: Icon(Icons.content_copy, color: Colors.grey), - onPressed: () => _copy( - getLocalString(context, "profile.usa.shipping.address"), - mainModel.setting!.usaAddress ?? ""), - ) - ], + IconButton( + icon: Icon(Icons.content_copy, color: Colors.grey), + onPressed: () => _copy( + getLocalString(context, "profile.usa.shipping.address"), + mainModel.setting!.usaAddress ?? ""), + ) + ], + ), ); - final logoutbutton = - fcsButton(context, getLocalString(context, "profile.logout"), - callack: mainModel.isPinLogin - ? null - : () { - showConfirmDialog(context, "profile.logout.confirm", - () async { - await _logout(); - }); - }, - iconData: Icons.exit_to_app); + final logoutbutton = Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: fcsButton(context, getLocalString(context, "profile.logout"), + callack: mainModel.isPinLogin + ? null + : () { + showConfirmDialog(context, "profile.logout.confirm", + () async { + await _logout(); + }); + }, + iconData: Icons.exit_to_app), + ); - final emailBox = Row( - children: [ - Expanded( - child: DisplayText( - text: user.recoveryEmail, - labelTextKey: "profile.recovery.email", - iconData: Icons.email_outlined, - ), - ), - IconButton( - icon: Icon(Icons.edit, color: Colors.grey), - onPressed: () { - Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute( - builder: (context) => AddRecoveryEmail(user: user))); - }) - ], + final recoveryEmailBox = settingRow( + context, + label: 'profile.recovery.email', + iconData: Icons.email_outlined, + text: user.recoveryEmail, + onTap: () { + Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute( + builder: (context) => AddRecoveryEmail(user: user))); + }, + ); + + final phoneNumberBox = settingRow( + context, + label: 'profile.change.phone', + iconData: Icons.phone, + onTap: () { + Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute( + builder: (context) => ChangePhoneNumber(user: user))); + }, ); final titleBox = Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - user.name ?? "", - style: TextStyle(fontSize: 18, color: Colors.black), - ), - const SizedBox(width: 5), - InkResponse( - radius: 20, - onTap: _editName, - child: Icon(Icons.edit, color: Colors.grey, size: 23)) - ], - ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + user.name ?? "", + style: TextStyle(fontSize: 18, color: Colors.black), + ), + const SizedBox(width: 5), + InkResponse( + radius: 20, + onTap: _editName, + child: Icon(Icons.edit, color: Colors.grey, size: 23)) + ], + ), const SizedBox(height: 1), Text( user.phone, @@ -192,60 +190,79 @@ class _ProfileState extends State { ], ); + final deleteAccountBox = settingRow( + context, + label: 'profile.delete.title', + iconData: MaterialCommunityIcons.account_remove, + onTap: () { + _editDelete(); + }, + ); + + final deliverAddressBox = Padding( + padding: const EdgeInsets.only(bottom: 5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + settingRow( + context, + label: 'profile.default.delivery.address', + iconData: MaterialCommunityIcons.truck_fast, + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => DeliveryAddressList())); + }, + ), + Padding( + padding: const EdgeInsets.only(left: 35), + child: DeliveryAddressRow( + key: ValueKey(deliveryAddressModel.defalutAddress.id), + deliveryAddress: deliveryAddressModel.defalutAddress), + ), + ], + ), + ); + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( key: key, appBar: LocalAppBar( - backgroundColor: Colors.white, - labelColor: primaryColor, - arrowColor: primaryColor, - titleWidget: titleBox - ), - body: Padding( - padding: const EdgeInsets.all(8.0), - child: ListView( - children: [ - const SizedBox(height: 5), - fcsIDBox, - usaShippingAddressBox, - currencyBox, - // emailBox, - DefaultDeliveryAddress( - labelKey: "profile.default.delivery.address", - deliveryAddress: deliveryAddressModel.defalutAddress, - onTap: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => DeliveryAddressList())); - }, - ), - buildLanguageWidget( - context: context, - text: "profile.language", - iconData: Icons.language, - isEng: languageModel.isEng, - ), - Row( - children: [ - Expanded( - child: deleteAccountBox, - ), - Padding( - padding: const EdgeInsets.only(right: 0), - child: IconButton( - icon: Icon(Icons.edit, color: Colors.grey), - onPressed: _editDelete), - ) - ], - ), - getPrivilegeBox(context), - SizedBox(height: 15), - logoutbutton, - SizedBox(height: 25) - ], - ), + backgroundColor: Colors.white, + labelColor: primaryColor, + arrowColor: primaryColor, + titleWidget: titleBox), + body: ListView( + children: [ + const SizedBox(height: 5), + fcsIDBox, + usaShippingAddressBox, + currencyBox, + deliverAddressBox, + // recoveryEmailBox, + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 100,), + // child: Divider(thickness: 2), + // ), + // phoneNumberBox, + buildLanguageWidget( + context: context, + text: "profile.language", + iconData: Icons.language, + isEng: languageModel.isEng, + ), + deleteAccountBox, + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 100,), + // child: Divider(thickness: 2), + // ), + getPrivilegeBox(context), + SizedBox(height: 15), + logoutbutton, + SizedBox(height: 30) + ], ), ), ); @@ -256,53 +273,56 @@ class _ProfileState extends State { required BuildContext context, IconData? iconData, required bool isEng}) { - return Row( - children: [ - Icon(iconData, color: primaryColor), - const SizedBox(width: 15), - Expanded( - child: LocalText( - context, - text, - fontSize: 15.0, - color: Colors.black54, + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Row( + children: [ + Icon(iconData, color: primaryColor), + const SizedBox(width: 15), + Expanded( + child: LocalText( + context, + text, + fontSize: 15.0, + color: Colors.black54, + ), ), - ), - Row( - children: [ - isEng - ? Image.asset( - 'icons/flags/png100px/us.png', - package: 'country_icons', - fit: BoxFit.fitWidth, - width: 25, - ) - : Image.asset( - 'icons/flags/png100px/mm.png', - package: 'country_icons', - fit: BoxFit.fitWidth, - width: 25, - ), - Container( - width: 100, - padding: const EdgeInsets.only(left: 15), - child: DropdownButton( - value: selectedLanguage, - underline: const SizedBox(), - isExpanded: true, - items: languagesList - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text( - value, - style: const TextStyle(fontSize: 14), - )); - }).toList(), - onChanged: _selectedDropdown)), - ], - ) - ], + Row( + children: [ + isEng + ? Image.asset( + 'icons/flags/png100px/us.png', + package: 'country_icons', + fit: BoxFit.fitWidth, + width: 25, + ) + : Image.asset( + 'icons/flags/png100px/mm.png', + package: 'country_icons', + fit: BoxFit.fitWidth, + width: 25, + ), + Container( + width: 100, + padding: const EdgeInsets.only(left: 15), + child: DropdownButton( + value: selectedLanguage, + underline: const SizedBox(), + isExpanded: true, + items: languagesList + .map>((String value) { + return DropdownMenuItem( + value: value, + child: Text( + value, + style: const TextStyle(fontSize: 14), + )); + }).toList(), + onChanged: _selectedDropdown)), + ], + ) + ], + ), ); } @@ -332,19 +352,22 @@ class _ProfileState extends State { return privileges.isEmpty ? const SizedBox() - : Column( - children: [ - DisplayText( - labelTextKey: "profile.privileges", - iconData: MaterialCommunityIcons.clipboard_check_outline, - ), - Padding( - padding: const EdgeInsets.only(left: 30.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: getRowPrivilegeWidget(privileges)), - ) - ], + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Column( + children: [ + DisplayText( + labelTextKey: "profile.privileges", + iconData: MaterialCommunityIcons.clipboard_check_outline, + ), + Padding( + padding: const EdgeInsets.only(left: 30.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: getRowPrivilegeWidget(privileges)), + ) + ], + ), ); } @@ -368,9 +391,9 @@ class _ProfileState extends State { children: [ Text("${p.name}", style: TextStyle( - fontSize: 16.0, + fontSize: 15.0, fontStyle: FontStyle.normal, - color: primaryColor)), + color: Colors.black)), Text( "${p.desc}", style: TextStyle(