From 450dfff6e8425f880230f41a873708f7e0efd0d2 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Mon, 21 Oct 2024 16:20:24 +0300 Subject: [PATCH] Added Shipping Management --- lib/classes/consts.dart | 8 +- lib/config/dependency_injection.dart | 2 + lib/config/routes.dart | 10 +- lib/extensions/string_extensions.dart | 35 +++ .../general_models/generic_resp_model.dart | 21 +- lib/models/requests_models/request_model.dart | 6 + lib/models/services_models/item_model.dart | 2 +- .../shipping_status_model.dart | 27 +++ lib/repositories/ads_repo.dart | 6 +- lib/repositories/common_repo.dart | 20 +- lib/repositories/shipping_repo.dart | 73 +++++++ lib/utils/enums.dart | 9 + lib/utils/utils.dart | 44 +++- lib/view_models/ad_view_model.dart | 77 ++++++- lib/view_models/service_view_model.dart | 16 +- .../shipping_management_view_model.dart | 110 ++++++++++ .../ads_detail_view/ads_detail_view.dart | 1 + .../ads_detail_view/components.dart | 160 ++++++++++---- lib/views/chat/chat_view.dart | 34 ++- .../common_fragments/requests_fragment.dart | 2 +- lib/views/requests/offer_list_page.dart | 2 +- lib/views/requests/widget/request_item.dart | 2 +- .../setting_options_language.dart | 17 +- .../shipping_management_view.dart | 199 ++++++++++++++++++ 24 files changed, 792 insertions(+), 91 deletions(-) create mode 100644 lib/models/shipping_models/shipping_status_model.dart create mode 100644 lib/repositories/shipping_repo.dart create mode 100644 lib/view_models/shipping_management_view_model.dart create mode 100644 lib/views/shipping_management/shipping_management_view.dart diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 872f394..9e3e565 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -145,8 +145,6 @@ class ApiConsts { //Branch Users static String getAllProviderDealers = "${baseUrlServices}api/ServiceProviders/DealershipUserBranchWise_Get"; - // /api/ServiceProviders/BranchUser_Get - //DealershipUserBranchWise_Get static String getBranchUser = "${baseUrlServices}api/ServiceProviders/BranchUser_Get"; static String assignDealerToBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Create"; static String removeDealerFromBranch = "${baseUrlServices}api/ServiceProviders/BranchUser_Update"; @@ -164,6 +162,10 @@ class ApiConsts { static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get"; static String getServiceRequestsForProvider = "${baseUrlServices}api/RequestManagement/Request_ServiceProvider"; + //Shipping + static String shippingRequestStatusUpdate = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Update"; + static String shippingRequestStatusGet = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Get"; + //Chat static String chatHubUrl = "$baseUrlServices/McHub"; static String messageIsReadUpdateForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChatIsRead_Update"; @@ -294,8 +296,6 @@ class MyAssets { static String whatsAppIcon = "${assetPath}icons/whatsapp_icon.svg"; static const String arrowRight = "${assetPath}icons/ic_arrow_right.svg"; static const String brokenImage = "${assetPath}images/broken_image.png"; - - } RegExp numReg = RegExp(r".*[0-9].*"); diff --git a/lib/config/dependency_injection.dart b/lib/config/dependency_injection.dart index aea3bcc..f3c8745 100644 --- a/lib/config/dependency_injection.dart +++ b/lib/config/dependency_injection.dart @@ -12,6 +12,7 @@ import 'package:mc_common_app/repositories/branch_repo.dart'; import 'package:mc_common_app/repositories/chat_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/payments_repo.dart'; +import 'package:mc_common_app/repositories/shipping_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/firebase_service.dart'; @@ -42,6 +43,7 @@ class AppDependencies { injector.registerSingleton(() => AppointmentRepoImp()); injector.registerSingleton(() => ChatRepoImp()); injector.registerSingleton(() => BranchRepoImp()); + injector.registerSingleton(() => ShippingRepoImp()); // } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 333a2a4..515974b 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -23,6 +23,7 @@ import 'package:mc_common_app/views/setting_options/setting_option_help.dart'; import 'package:mc_common_app/views/setting_options/setting_options_faqs.dart'; import 'package:mc_common_app/views/setting_options/setting_options_invite_friends.dart'; import 'package:mc_common_app/views/setting_options/setting_options_language.dart'; +import 'package:mc_common_app/views/shipping_management/shipping_management_view.dart'; import 'package:mc_common_app/views/user/change_email_page.dart'; import 'package:mc_common_app/views/user/change_mobile_page.dart'; import 'package:mc_common_app/views/user/change_password_page.dart'; @@ -69,7 +70,7 @@ class AppRoutes { static const String dashboard = "/dashboard"; static const String bookProviderAppView = "/bookProviderAppView"; - // Appoinments + // Appointments static const String appointmentDetailView = "/appointmentDetailView"; static const String bookAppointmenServicesView = "/bookAppointmenServicesView"; static const String bookAppointmenSchedulesView = "/bookAppointmenSchedulesView"; @@ -87,6 +88,10 @@ class AppRoutes { // Payments static const String paymentMethodsView = "/paymentMethodsView"; + //Shipping + + static const shippingManagementView = "/shippingManagementView"; + //Customer APP: Provider & Services static const String branchDetailView = "/branchDetailPage"; static const String branchSearchFilterPage = "/branchSearchFilterPage"; @@ -171,6 +176,9 @@ class AppRoutes { //MediaViewer AppRoutes.mediaViewerScreen: (context) => MediaViewerScreen(images: ModalRoute.of(context)!.settings.arguments as List), + + //Shipping + AppRoutes.shippingManagementView: (context) => const ShippingManagementView(), }; } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 7dc07d5..71c00f0 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -907,3 +907,38 @@ extension SubscriptionTypeEnumToString on SubscriptionTypeEnum { } } } + +extension ShippingStatusEnumExt on int { + ShippingRequestStatusEnum toShippingStatusEnum() { + if (this == 0) { + return ShippingRequestStatusEnum.allRequests; + } else if (this == 1) { + return ShippingRequestStatusEnum.initiated; + } else if (this == 2) { + return ShippingRequestStatusEnum.inTransit; + } else if (this == 3) { + return ShippingRequestStatusEnum.outForDelivery; + } else if (this == 4) { + return ShippingRequestStatusEnum.delivered; + } + return ShippingRequestStatusEnum.initiated; + } +} + +extension ShippingStatusEnumToInt on ShippingRequestStatusEnum { + int getIdFromShippingStatusEnum() { + switch (this) { + case ShippingRequestStatusEnum.initiated: + return 1; + case ShippingRequestStatusEnum.inTransit: + return 2; + case ShippingRequestStatusEnum.outForDelivery: + return 3; + case ShippingRequestStatusEnum.delivered: + return 4; + + default: + return 0; + } + } +} diff --git a/lib/models/general_models/generic_resp_model.dart b/lib/models/general_models/generic_resp_model.dart index 557d725..0f036e3 100644 --- a/lib/models/general_models/generic_resp_model.dart +++ b/lib/models/general_models/generic_resp_model.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:mc_common_app/utils/utils.dart'; + class GenericRespModel { GenericRespModel({ this.data, @@ -13,12 +15,19 @@ class GenericRespModel { int? totalItemsCount; String? message; - factory GenericRespModel.fromJson(Map json) => GenericRespModel( - data: json["data"], - messageStatus: json["messageStatus"], - totalItemsCount: json["totalItemsCount"], - message: json["message"], - ); + factory GenericRespModel.fromJson(Map json) { + if (json.containsKey('StatusMessage')) { + if ((json['StatusMessage'] as String).contains('Internal server error')) { + Utils.showToast("${json['StatusMessage']}"); + } + } + return GenericRespModel( + data: json["data"], + messageStatus: json["messageStatus"], + totalItemsCount: json["totalItemsCount"], + message: json["message"], + ); + } Map toJson() => { "data": data, diff --git a/lib/models/requests_models/request_model.dart b/lib/models/requests_models/request_model.dart index 95eb502..8f4bd01 100644 --- a/lib/models/requests_models/request_model.dart +++ b/lib/models/requests_models/request_model.dart @@ -8,6 +8,8 @@ class RequestModel { String requestTypeName; String requestStatusName; RequestStatusEnum requestStatus; + int? shippingStatus; + ShippingRequestStatusEnum? shippingStatusEnum; String cityName; String vehicleTypeName; String countryName; @@ -46,6 +48,8 @@ class RequestModel { required this.requestTypeName, required this.requestStatusName, required this.requestStatus, + required this.shippingStatus, + required this.shippingStatusEnum, required this.cityName, required this.vehicleTypeName, required this.countryName, @@ -96,6 +100,8 @@ class RequestModel { requestTypeName: json["requestTypeName"], requestStatusName: json["requestStatusName"], requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(), + shippingStatus: json['shippingRequestStatus'], + shippingStatusEnum: json['shippingRequestStatus'] != null ? (json['shippingRequestStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated, cityName: json["cityName"], vehicleTypeName: json["vehicleTypeName"], countryName: json["countryName"], diff --git a/lib/models/services_models/item_model.dart b/lib/models/services_models/item_model.dart index 3141a89..322e077 100644 --- a/lib/models/services_models/item_model.dart +++ b/lib/models/services_models/item_model.dart @@ -42,7 +42,7 @@ class ItemData { final String? price; final String? manufactureDate; final String? description; - final dynamic pictureUrl; + final String? pictureUrl; final int? companyId; final int? serviceProviderServiceId; final String? serviceProviderServiceDescription; diff --git a/lib/models/shipping_models/shipping_status_model.dart b/lib/models/shipping_models/shipping_status_model.dart new file mode 100644 index 0000000..c68f73c --- /dev/null +++ b/lib/models/shipping_models/shipping_status_model.dart @@ -0,0 +1,27 @@ +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/requests_models/request_model.dart'; +import 'package:mc_common_app/utils/enums.dart'; + +class ShippingRequestModel { + int? id; + int? requestID; + RequestModel? request; + int? shippingStatus; + ShippingRequestStatusEnum? shippingStatusEnum; + String? deliveredOn; + String? comment; + String? createdOn; + + ShippingRequestModel({this.id, this.requestID, this.request, this.shippingStatus, this.deliveredOn, this.comment, this.createdOn}); + + ShippingRequestModel.fromJson(Map json) { + id = json['id']; + requestID = json['requestID']; + request = json['request']; + shippingStatus = json['shippingStatus']; + shippingStatusEnum = json['shippingStatus'] != null ? (json['shippingStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated; + deliveredOn = json['deliveredOn']; + comment = json['comment']; + createdOn = json['createdOn']; + } +} diff --git a/lib/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index 37a20e6..5cd5769 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -30,7 +30,7 @@ abstract class AdsRepo { Future getAdBankingAccountInfo({required int adId}); - Future updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}); + Future updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment}); Future createAppointmentForAdSpecialService({required int adId, required int photoOfficeID, required int photoOfficeSlotID, required int adsSpecialServiceID}); @@ -263,11 +263,11 @@ class AdsRepoImp implements AdsRepo { } @override - Future updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}) async { + Future updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate, String? comment}) async { var postParams = { "id": adId, "status": adStatusToUpdate.getIdFromAdPostStatusEnum().toString(), - "comment": "", + "comment": comment ?? "", }; String token = appState.getUser.data!.accessToken ?? ""; diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart index 79358fe..df6275b 100644 --- a/lib/repositories/common_repo.dart +++ b/lib/repositories/common_repo.dart @@ -131,11 +131,21 @@ class CommonRepoImp implements CommonRepo { ], }; - if (json.containsKey('StatusMessage')) { - if ((json['StatusMessage'] as String).contains('Internal server error')) { - Utils.showToast("${json['StatusMessage']}"); - } - } + List enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index])); + return enums; + } + + if (enumTypeID == -2) { + // This is for the ShippingRequestStatus which will be added to API later + final Map json = { + "data": [ + {"id": 1, "enumTypeID": 0, "enumValueStr": "Initiated", "enumValue": 1, "isActive": true}, + {"id": 2, "enumTypeID": 0, "enumValueStr": "In Transit", "enumValue": 2, "isActive": true}, + {"id": 3, "enumTypeID": 0, "enumValueStr": "Out for Delivery", "enumValue": 3, "isActive": true}, + {"id": 4, "enumTypeID": 0, "enumValueStr": "Delivered", "enumValue": 4, "isActive": true}, + ], + }; + List enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index])); return enums; } diff --git a/lib/repositories/shipping_repo.dart b/lib/repositories/shipping_repo.dart new file mode 100644 index 0000000..6b99c6f --- /dev/null +++ b/lib/repositories/shipping_repo.dart @@ -0,0 +1,73 @@ +import 'dart:developer'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:mc_common_app/api/api_client.dart'; +import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/dependency_injection.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; +import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart'; + +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; + +abstract class ShippingRepo { + Future> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId}); + + Future updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment}); +} + +class ShippingRepoImp extends ShippingRepo { + ApiClient apiClient = injector.get(); + AppState appState = injector.get(); + + @override + Future> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId}) async { + String token = appState.getUser.data!.accessToken ?? ""; + Map queryParameters = { + "requestID": "${requestId ?? 0}", + "shippingStatus": "${shippingStatusEnum != null ? shippingStatusEnum.getIdFromShippingStatusEnum() : 0}", + }; + + GenericRespModel genericRespModel = await injector.get().postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.shippingRequestStatusGet, + queryParameters, + token: token, + ); + + if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) { + Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr()); + return []; + } + + List list = List.generate(genericRespModel.data.length, (index) => ShippingRequestModel.fromJson(genericRespModel.data[index])); + + return list; + } + + @override + Future updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment}) async { + String token = appState.getUser.data!.accessToken ?? ""; + Map queryParameters = { + "id": "$shippingRequestId", + "shippingStatus": "${shippingStatusEnum.getIdFromShippingStatusEnum()}", + "comment": comment ?? "", + }; + + GenericRespModel genericRespModel = await injector.get().postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.shippingRequestStatusUpdate, + queryParameters, + token: token, + ); + + if (genericRespModel.messageStatus != 1 || genericRespModel.data == null) { + Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr()); + } + + return genericRespModel; + } +} diff --git a/lib/utils/enums.dart b/lib/utils/enums.dart index 2549b6e..8717e22 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -16,6 +16,7 @@ class AppEnums { static const int appointmentsFilterEnumId = 13; // Appointments Filter Enums static const int requestStatusesFilterEnumId = 15; // Appointments Filter Enums static const int conditionEnumId = -1; // to get the Condition Filter Enums + static const int shippingStatusEnumId = -2; // to get the Shipping Filter Enums } enum VehicleType { @@ -210,3 +211,11 @@ enum SubscriptionActionTypeEnum { users, branches, } + +enum ShippingRequestStatusEnum { + allRequests, + initiated, + inTransit, + outForDelivery, + delivered, +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index c6a7ca3..3412f22 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -209,7 +209,7 @@ class Utils { return MyColors.inProgressColor; case AdPostStatus.active: - return MyColors.adActiveStatusColor; + return MyColors.greenColor; case AdPostStatus.expired: return MyColors.adCancelledStatusColor; @@ -286,6 +286,44 @@ class Utils { } } + static String getNameByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) { + switch (shippingRequestStatusEnum) { + case ShippingRequestStatusEnum.allRequests: + return "All Requests"; + + case ShippingRequestStatusEnum.initiated: + return "Initiated"; + + case ShippingRequestStatusEnum.inTransit: + return "In Transit"; + + case ShippingRequestStatusEnum.outForDelivery: + return "Out For Delivery"; + + case ShippingRequestStatusEnum.delivered: + return "Delivered"; + } + } + + static Color getChipColorByShippingRequestStatusEnum(ShippingRequestStatusEnum shippingRequestStatusEnum) { + switch (shippingRequestStatusEnum) { + case ShippingRequestStatusEnum.allRequests: + return MyColors.submittedColor; + + case ShippingRequestStatusEnum.initiated: + return MyColors.submittedColor; + + case ShippingRequestStatusEnum.inTransit: + return MyColors.shippingColor; + + case ShippingRequestStatusEnum.outForDelivery: + return MyColors.deliveryColor; + + case ShippingRequestStatusEnum.delivered: + return MyColors.greenColor; + } + } + static Color getChipColorByBranchStatus(BranchStatusEnum branchStatusEnum) { switch (branchStatusEnum) { case BranchStatusEnum.pending: @@ -538,9 +576,7 @@ class Utils { static Widget buildStatusContainer(String text) { return Center( - child: text.toText(color: MyColors.lightTextColor, fontSize: 14 - // isItalic: true, - ), + child: text.toText(color: MyColors.lightTextColor, fontSize: 14), ).toContainer( marginAll: 8, paddingAll: 15, diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index 10382f2..7efff83 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -361,9 +361,9 @@ class AdVM extends BaseVM { navigateReplaceWithName(context, AppRoutes.dashboard); } - Future deactivateTheAd(BuildContext context, {required int adId}) async { + Future deactivateTheAd(BuildContext context, {required int adId, String? comment}) async { Utils.showLoading(context); - GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled); + GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled, comment: comment); if (respModel.messageStatus != 1) { Utils.hideLoading(context); @@ -372,8 +372,9 @@ class AdVM extends BaseVM { } Utils.hideLoading(context); Utils.showToast(LocaleKeys.adDeactivatedSuccessfully.tr()); + updateDeactivateAdReasonDescription(''); updateIsExploreAds(false); - applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //pending for review + applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.cancelled); //Cacncelled navigateReplaceWithName(context, AppRoutes.dashboard); } @@ -580,6 +581,76 @@ class AdVM extends BaseVM { reservationCancelReason = value; } + List deActivateAdModelList = [ + OfferRequestCommentModel( + index: 0, + isSelected: true, + title: LocaleKeys.changedMind.tr(), + ), + OfferRequestCommentModel( + index: 1, + isSelected: false, + title: LocaleKeys.veryHighPrice.tr(), + ), + OfferRequestCommentModel( + index: 2, + isSelected: false, + title: LocaleKeys.alreadySold.tr(), + ), + OfferRequestCommentModel( + index: 3, + isSelected: false, + title: LocaleKeys.customerNotResponding.tr(), + ), + OfferRequestCommentModel( + index: 4, + isSelected: false, + title: LocaleKeys.otherVar.tr(), + ), + ]; + + OfferRequestCommentModel selectedDeActivateAdCommentModel = OfferRequestCommentModel( + index: 0, + isSelected: true, + title: LocaleKeys.changedMind.tr(), + ); + + void updateSelectionInDeActivateAdModelList(int index) { + for (var value in deActivateAdModelList) { + value.isSelected = false; + } + selectedDeActivateAdCommentModel = deActivateAdModelList[index]; + deActivateAdModelList[index].isSelected = true; + notifyListeners(); + } + + String deactivateAdReasonDescription = ""; + String deactivateAdReasonDescriptionError = ""; + + void updateDeactivateAdReasonDescription(String value) { + deactivateAdReasonDescription = value; + if (value.isNotEmpty) { + deactivateAdReasonDescriptionError = ""; + } + } + + bool isDeActivateReasonSubmitValidated() { + if (selectedDeActivateAdCommentModel.index != deActivateAdModelList.length - 1) { + return true; + } + bool isValidated = true; + if (deactivateAdReasonDescription.isEmpty) { + deactivateAdReasonDescriptionError = GlobalConsts.descriptionError; + isValidated = false; + } else { + deactivateAdReasonDescriptionError = ""; + } + + notifyListeners(); + + return isValidated; + } + String completeDealNotesForAdmin = ""; void updateCompleteDealNotesForAdmin(String value) { diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index ad800a4..eef76a4 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -218,8 +218,8 @@ class ServiceVM extends BaseVM { documentID == 1 ? commerceCertificates.addAll(imageModels) : documentID == 2 - ? commercialCertificates.addAll(imageModels) - : vatCertificates.addAll(imageModels); + ? commercialCertificates.addAll(imageModels) + : vatCertificates.addAll(imageModels); document!.data![index].document = Utils.convertFileToBase64(files.first); document!.data![index].fileExt = Utils.checkFileExt(files.first.path); document!.data![index].documentUrl = files.first.path; @@ -400,10 +400,10 @@ class ServiceVM extends BaseVM { DropValue( element.id ?? 0, ((element.categoryName!.isEmpty - ? "N/A" - : countryCode == "SA" - ? element.categoryNameN - : element.categoryName) ?? + ? "N/A" + : countryCode == "SA" + ? element.categoryNameN + : element.categoryName) ?? "N/A"), "", ), @@ -586,7 +586,9 @@ class ServiceVM extends BaseVM { File file = File(imageModel.filePath!); List imageBytes = await file.readAsBytes(); String image = base64Encode(imageBytes); - String fileName = file.path.split('/').last; + String fileName = file.path + .split('/') + .last; branchPostingImages = BranchPostingImages( imageName: fileName, imageStr: image, diff --git a/lib/view_models/shipping_management_view_model.dart b/lib/view_models/shipping_management_view_model.dart new file mode 100644 index 0000000..ca5a672 --- /dev/null +++ b/lib/view_models/shipping_management_view_model.dart @@ -0,0 +1,110 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/main.dart'; +import 'package:mc_common_app/models/general_models/enums_model.dart'; +import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; +import 'package:mc_common_app/models/general_models/widgets_models.dart'; +import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart'; +import 'package:mc_common_app/repositories/common_repo.dart'; +import 'package:mc_common_app/repositories/shipping_repo.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; + +class ShippingManagementVM extends BaseVM { + final ShippingRepo shippingRepo; + final CommonRepo commonRepo; + + ShippingManagementVM({required this.shippingRepo, required this.commonRepo}); + + List shippingRequestsList = []; + + List shippingStatusEnums = []; + + List shippingRequestFilterOptions = []; + List shippingRequestStatusesList = []; + + String requestStatusComments = ""; + + void updateRequestStatusComments(var value) { + requestStatusComments = value; + } + + resetFilters() { + if (shippingRequestFilterOptions.isEmpty) return; + for (var value in shippingRequestFilterOptions) { + value.isSelected = false; + } + shippingRequestFilterOptions[0].isSelected = true; + requestStatusComments = ""; + } + + Future populateShippingRequestFilterList() async { + if (shippingRequestFilterOptions.isNotEmpty && shippingRequestStatusesList.isNotEmpty) return; + + shippingStatusEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.shippingStatusEnumId); + shippingRequestFilterOptions.clear(); + shippingRequestStatusesList.clear(); + for (int i = 0; i < shippingStatusEnums.length; i++) { + shippingRequestFilterOptions.add(FilterListModel(title: shippingStatusEnums[i].enumValueStr, isSelected: false, id: shippingStatusEnums[i].enumValue)); + shippingRequestStatusesList.add(FilterListModel(title: shippingStatusEnums[i].enumValueStr, isSelected: false, id: shippingStatusEnums[i].enumValue)); + } + + shippingRequestFilterOptions.insert(0, FilterListModel(title: Utils.getNameByShippingRequestStatusEnum(0.toShippingStatusEnum()), isSelected: true, id: 0)); + notifyListeners(); + } + + Future applyFiltersOnShippingRequests({required ShippingRequestStatusEnum shippingRequestStatusEnum}) async { + for (var value in shippingRequestFilterOptions) { + value.isSelected = false; + } + if (shippingRequestStatusEnum == ShippingRequestStatusEnum.allRequests) { + shippingRequestFilterOptions[0].isSelected = true; + await getShippingRequestsListByFilters(); + notifyListeners(); + return; + } + shippingRequestFilterOptions[shippingRequestStatusEnum.getIdFromShippingStatusEnum()].isSelected = true; // -1 to match with the index + await getShippingRequestsListByFilters(shippingStatusEnum: shippingRequestStatusEnum); + notifyListeners(); + } + + void updateSelectionInShippingRequestStatuses(int index) { + for (var value in shippingRequestStatusesList) { + value.isSelected = false; + } + shippingRequestStatusesList[index].isSelected = true; + notifyListeners(); + } + + Future getShippingRequestsListByFilters({ShippingRequestStatusEnum? shippingStatusEnum}) async { + setState(ViewState.busy); + try { + shippingRequestsList = await shippingRepo.getShippingRequestListByStatus(shippingStatusEnum: shippingStatusEnum); + setState(ViewState.idle); + notifyListeners(); + } catch (e) { + logger.i(e.toString()); + Utils.showToast(e.toString()); + setState(ViewState.idle); + } + } + + Future onUpdateShippingStatusTapped({required BuildContext context, required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId}) async { + + Utils.showLoading(context); + try { + GenericRespModel? genericRespModel = await shippingRepo.updateShippingRequestStatus(shippingStatusEnum: shippingStatusEnum, shippingRequestId: shippingRequestId); + Utils.showToast(genericRespModel.message.toString()); + Utils.hideLoading(context); + return genericRespModel.messageStatus == 1; + } catch (e) { + logger.i(e.toString()); + Utils.showToast(e.toString()); + Utils.hideLoading(context); + return false; + } + } +} diff --git a/lib/views/advertisement/ads_detail_view/ads_detail_view.dart b/lib/views/advertisement/ads_detail_view/ads_detail_view.dart index 2ea8546..5b1564c 100644 --- a/lib/views/advertisement/ads_detail_view/ads_detail_view.dart +++ b/lib/views/advertisement/ads_detail_view/ads_detail_view.dart @@ -364,6 +364,7 @@ class _AdsDetailViewState extends State { child: Column( children: [ if (!(widget.adDetails.isMyAd ?? false)) ...[ + const Divider(thickness: 1, height: 1), const Divider(thickness: 1, height: 1), 18.height, Row( diff --git a/lib/views/advertisement/ads_detail_view/components.dart b/lib/views/advertisement/ads_detail_view/components.dart index dc21cfe..913e345 100644 --- a/lib/views/advertisement/ads_detail_view/components.dart +++ b/lib/views/advertisement/ads_detail_view/components.dart @@ -7,6 +7,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; +import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; @@ -19,6 +20,7 @@ import 'package:mc_common_app/views/advertisement/components/picked_images_conta import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart'; import 'package:mc_common_app/widgets/bottom_sheet.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart'; import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart'; import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; @@ -512,22 +514,6 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { ); } - Widget buildStatusContainer(String text, {bool isForShippingOrDelivery = true}) { - return Center( - child: text.toText( - color: isForShippingOrDelivery ? MyColors.lightTextColor : MyColors.adPendingStatusColor, - fontSize: isForShippingOrDelivery ? 14 : 16, - // isItalic: true, - ), - ).toContainer( - marginAll: 12, - paddingAll: 12, - borderRadius: 8, - width: double.infinity, - backgroundColor: isForShippingOrDelivery ? MyColors.grey98Color.withOpacity(0.1) : MyColors.adPendingStatusColor.withOpacity(0.16), - ); - } - Widget pendingForPaymentAction(BuildContext context, {required AdDetailsModel ad}) { SpecialServiceModelForAds? photoSpecialServiceModel; for (var element in ad.specialservice!) { @@ -610,35 +596,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { title: LocaleKeys.deactivateAd.tr(), txtColor: MyColors.redColor, onPressed: () { - return actionConfirmationBottomSheet( - context: context, - title: LocaleKeys.doWantDeactivateAd.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), - subtitle: LocaleKeys.stoptheBuyers.tr(), - actionButtonYes: Expanded( - child: ShowFillButton( - maxHeight: 55, - title: LocaleKeys.yes.tr(), - fontSize: 15, - onPressed: () { - Navigator.pop(context); - adVM.deactivateTheAd(context, adId: adDetailsModel.id!); - }, - ), - ), - actionButtonNo: Expanded( - child: ShowFillButton( - maxHeight: 55, - isFilled: false, - borderColor: MyColors.darkPrimaryColor, - title: LocaleKeys.no.tr(), - txtColor: MyColors.darkPrimaryColor, - fontSize: 15, - onPressed: () { - Navigator.pop(context); - }, - ), - ), - ); + buildAdDeactivateReasonsBottomSheet(context, adDetails: adDetailsModel); }, ), ), @@ -648,6 +606,118 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { ); } + Future buildAdDeactivateReasonsBottomSheet(BuildContext context, {required AdDetailsModel adDetails}) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + return Consumer(builder: (BuildContext context, AdVM adVM, Widget? child) { + return InfoBottomSheet( + title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), + description: Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + ListView.separated( + shrinkWrap: true, + itemCount: adVM.deActivateAdModelList.length, + separatorBuilder: (BuildContext context, int index) { + if (adVM.deActivateAdModelList[index].index == 3) { + return const SizedBox(); + } + return const Divider(thickness: 0.5); + }, + itemBuilder: (BuildContext context, int index) { + if (adVM.deActivateAdModelList[index].index == 3) { + return const SizedBox(); + } + OfferRequestCommentModel offerRequestCommentModel = adVM.deActivateAdModelList[index]; + return CircleCheckBoxWithTitle( + isChecked: offerRequestCommentModel.isSelected ?? false, + title: '${offerRequestCommentModel.title}', + onSelected: () { + adVM.updateSelectionInDeActivateAdModelList(index); + }, + selectedColor: MyColors.darkPrimaryColor, + ); + }, + ), + if (adVM.selectedDeActivateAdCommentModel.index == adVM.deActivateAdModelList.length - 1) ...[ + // comparing if the "other" is selected + 12.height, + TxtField( + maxLines: 5, + value: adVM.deactivateAdReasonDescription, + errorValue: adVM.deactivateAdReasonDescriptionError, + keyboardType: TextInputType.text, + hint: LocaleKeys.reason.tr(), + onChanged: (v) => adVM.updateDeactivateAdReasonDescription(v), + ), + ], + ], + ), + 25.height, + ShowFillButton( + title: LocaleKeys.submit.tr(), + onPressed: () { + String comments = ""; + if (adVM.selectedDeActivateAdCommentModel.index == adVM.deActivateAdModelList.length - 1) //Other + { + comments = adVM.deactivateAdReasonDescription; + } else { + comments = adVM.selectedDeActivateAdCommentModel.title ?? ""; + } + + if (!adVM.isDeActivateReasonSubmitValidated()) { + return; + } + + return actionConfirmationBottomSheet( + context: context, + title: LocaleKeys.doWantDeactivateAd.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), + subtitle: LocaleKeys.stoptheBuyers.tr(), + actionButtonYes: Expanded( + child: ShowFillButton( + maxHeight: 55, + title: LocaleKeys.yes.tr(), + fontSize: 15, + onPressed: () { + adVM.deactivateTheAd(context, adId: adDetailsModel.id!, comment: comments); + }, + ), + ), + actionButtonNo: Expanded( + child: ShowFillButton( + maxHeight: 55, + isFilled: false, + borderColor: MyColors.darkPrimaryColor, + title: LocaleKeys.no.tr(), + txtColor: MyColors.darkPrimaryColor, + fontSize: 15, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ); + }, + maxWidth: double.infinity, + ), + 19.height, + ], + ), + )); + }); + }, + ); + } + Future buildCancelReservationBottomSheet(BuildContext context, {required AdDetailsModel adDetails}) { return showModalBottomSheet( context: context, diff --git a/lib/views/chat/chat_view.dart b/lib/views/chat/chat_view.dart index 25288f5..f50967b 100644 --- a/lib/views/chat/chat_view.dart +++ b/lib/views/chat/chat_view.dart @@ -23,6 +23,7 @@ import 'package:mc_common_app/views/requests/request_bottomsheets.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:mc_common_app/widgets/row_with_arrow.dart'; import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:provider/provider.dart'; import 'package:easy_localization/easy_localization.dart' as lcl; @@ -93,8 +94,35 @@ class _ChatViewState extends State { @override Widget build(BuildContext context) { + Widget? appBarHeadlines; + final requestVM = context.read(); + if (chatTypeEnum == ChatTypeEnum.requestOffer && + requestVM.currentSelectedRequest != null && + (requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.shipping || requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.delivery)) { + appBarHeadlines = Container( + width: double.infinity, + color: MyColors.darkIconColor, + padding: const EdgeInsets.symmetric(horizontal: 21, vertical: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + "Your Delivery / Shipping Status is: ".toText( + fontSize: 12, + color: Colors.white, + decorationColor: MyColors.white, + ), + Utils.getNameByShippingRequestStatusEnum(requestVM.currentSelectedRequest?.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated).toText( + fontSize: 16, + color: Colors.white, + ), + ], + ), + ); + } return Scaffold( - appBar: CustomAppBar(title: LocaleKeys.chat.tr()), + appBar: CustomAppBar( + title: LocaleKeys.chat.tr(), + ), body: Consumer2(builder: (BuildContext context, ChatVM chatVM, RequestsVM requestVM, Widget? child) { List chatMessages = []; if (chatTypeEnum == ChatTypeEnum.ads) { @@ -108,6 +136,10 @@ class _ChatViewState extends State { } return Column( children: [ + if (appBarHeadlines != null) ...[ + appBarHeadlines, + 5.height, + ], Expanded( child: chatMessages.isEmpty ? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor, textAlign: TextAlign.center)).paddingAll(22) diff --git a/lib/views/common_fragments/requests_fragment.dart b/lib/views/common_fragments/requests_fragment.dart index 608d373..0c0f924 100644 --- a/lib/views/common_fragments/requests_fragment.dart +++ b/lib/views/common_fragments/requests_fragment.dart @@ -110,7 +110,7 @@ class MyRequestsFragment extends StatelessWidget { 8.height, Expanded( child: RefreshIndicator( - onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true), + onRefresh: () async => await requestsVM.getRequestsBasedOnFilters(), child: requestsVM.state == ViewState.busy ? const Center(child: CircularProgressIndicator()) : requestsVM.myFilteredRequests.isEmpty diff --git a/lib/views/requests/offer_list_page.dart b/lib/views/requests/offer_list_page.dart index ea1dac7..0cb44d0 100644 --- a/lib/views/requests/offer_list_page.dart +++ b/lib/views/requests/offer_list_page.dart @@ -37,7 +37,7 @@ class OfferListPage extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.statusContainerChip(text: Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!), chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)), + Utils.statusContainerChip(text: "Offer ${Utils.getNameByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)}", chipColor: Utils.getChipColorByRequestOfferStatusEnum(offersModel.requestOfferStatusEnum!)), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/views/requests/widget/request_item.dart b/lib/views/requests/widget/request_item.dart index 5c88a12..e09ef63 100644 --- a/lib/views/requests/widget/request_item.dart +++ b/lib/views/requests/widget/request_item.dart @@ -43,7 +43,7 @@ class RequestItem extends StatelessWidget { children: [ Utils.statusContainerChip(text: request.requestStatusName, chipColor: Utils.getChipColorByRequestStatus(request.requestStatus)), 6.height, - "${request.brand} ${request.model}".toText(fontSize: 16, letterSpacing: -0.64), + "${request.brand} ${request.model} | ${request.id}".toText(fontSize: 16, letterSpacing: -0.64), showItem("${LocaleKeys.model.tr()}:", "${request.year}"), if (request.customerName.isNotEmpty) ...[ showItem("${LocaleKeys.customerName.tr()}:", request.customerName), diff --git a/lib/views/setting_options/setting_options_language.dart b/lib/views/setting_options/setting_options_language.dart index e501d1d..ea3da5a 100644 --- a/lib/views/setting_options/setting_options_language.dart +++ b/lib/views/setting_options/setting_options_language.dart @@ -52,15 +52,16 @@ class _SettingOptionsLanguageState extends State { needBorderBelow: true, onTap: () => navigateWithName(context, AppRoutes.favoriteListView), ), + ] else ...[ + CustomSettingOptionsTile( + leadingWidget: const Icon(Icons.local_shipping, size: 20), + titleText: LocaleKeys.shippingManagement.tr(), + needBorderBelow: true, + onTap: () { + navigateWithName(context, AppRoutes.shippingManagementView); + }, + ), ], - // else ...[ - // CustomSettingOptionsTile( - // leadingWidget: const Icon(Icons.local_shipping, size: 20), - // titleText: LocaleKeys.shippingManagement.tr(), - // needBorderBelow: true, - // onTap: () {}, - // ), - // ], CustomSettingOptionsTile( leadingWidget: const Icon(Icons.settings, size: 20), titleText: LocaleKeys.settings.tr(), diff --git a/lib/views/shipping_management/shipping_management_view.dart b/lib/views/shipping_management/shipping_management_view.dart new file mode 100644 index 0000000..8f54e8e --- /dev/null +++ b/lib/views/shipping_management/shipping_management_view.dart @@ -0,0 +1,199 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/general_models/widgets_models.dart'; +import 'package:mc_common_app/models/shipping_models/shipping_status_model.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/shipping_management_view_model.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/common_widgets/categories_list.dart'; +import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; +import 'package:provider/provider.dart'; +import 'package:easy_localization/easy_localization.dart'; + +class ShippingManagementView extends StatefulWidget { + const ShippingManagementView({super.key}); + + @override + State createState() => _ShippingManagementViewState(); +} + +class _ShippingManagementViewState extends State { + late ShippingManagementVM shippingViewModel; + + @override + void initState() { + shippingViewModel = context.read(); + scheduleMicrotask(() async { + if (shippingViewModel.shippingRequestFilterOptions.isNotEmpty) { + await shippingViewModel.populateShippingRequestFilterList(); + } + await shippingViewModel.getShippingRequestsListByFilters(); + }); + super.initState(); + } + + Future buildUpdateShippingStatusBottomSheet({required int shippingRequestId}) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + return Consumer(builder: (BuildContext context, ShippingManagementVM shippingManagementVM, Widget? child) { + return InfoBottomSheet( + title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), + description: Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + ListView.separated( + shrinkWrap: true, + itemCount: shippingManagementVM.shippingRequestStatusesList.length, + separatorBuilder: (BuildContext context, int index) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 3.0), + child: Divider(thickness: 0.5), + ); + }, + itemBuilder: (BuildContext context, int index) { + List list = shippingManagementVM.shippingRequestStatusesList; + FilterListModel shippingFilterListModel = list[index]; + return CircleCheckBoxWithTitle( + isChecked: shippingFilterListModel.isSelected, + title: shippingFilterListModel.title, + onSelected: () { + shippingManagementVM.updateSelectionInShippingRequestStatuses(index); + }, + selectedColor: MyColors.darkPrimaryColor, + ); + }, + ), + 12.height, + TxtField( + maxLines: 4, + value: shippingManagementVM.requestStatusComments, + errorValue: "", + keyboardType: TextInputType.text, + hint: LocaleKeys.comment.tr(), + onChanged: (v) => shippingManagementVM.updateRequestStatusComments(v), + ), + ], + ), + 25.height, + ShowFillButton( + title: LocaleKeys.submit.tr(), + onPressed: () async { + FilterListModel value = shippingManagementVM.shippingRequestStatusesList.firstWhere((element) => element.isSelected); + ShippingRequestStatusEnum shippingStatusEnum = value.id.toShippingStatusEnum(); + bool status = await shippingManagementVM.onUpdateShippingStatusTapped(shippingStatusEnum: shippingStatusEnum, shippingRequestId: shippingRequestId, context: context); + if (status) { + pop(context); + await shippingManagementVM.getShippingRequestsListByFilters(); + } + }, + maxWidth: double.infinity, + ), + 19.height, + ], + ), + )); + }); + }, + ); + } + + @override + void dispose() { + shippingViewModel.resetFilters(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (BuildContext context, ShippingManagementVM shippingVm, Widget? child) { + return Scaffold( + appBar: CustomAppBar(title: LocaleKeys.shippingManagement.tr()), + body: Container( + color: MyColors.backgroundColor, + width: double.infinity, + height: double.infinity, + child: Column( + children: [ + 16.height, + FiltersList( + filterList: shippingVm.shippingRequestFilterOptions, + onFilterTapped: (index, selectedFilterId) { + shippingVm.applyFiltersOnShippingRequests(shippingRequestStatusEnum: selectedFilterId.toShippingStatusEnum()); + }, + ), + 8.height, + Expanded( + child: RefreshIndicator( + onRefresh: () async { + int index = shippingVm.shippingRequestFilterOptions.indexWhere((element) => element.isSelected); + await shippingVm.getShippingRequestsListByFilters(shippingStatusEnum: index.toShippingStatusEnum()); + }, + child: (shippingVm.state == ViewState.busy) + ? const Center( + child: CircularProgressIndicator(), + ) + : shippingVm.shippingRequestsList.isEmpty + ? Center(child: LocaleKeys.noRequeststoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor)) + : ListView.separated( + itemCount: shippingVm.shippingRequestsList.length, + padding: const EdgeInsets.all(16), + itemBuilder: (context, index) { + ShippingRequestModel shippingRequest = shippingVm.shippingRequestsList[index]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Utils.statusContainerChip( + text: Utils.getNameByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated), + chipColor: Utils.getChipColorByShippingRequestStatusEnum(shippingRequest.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated), + ), + ("Request Name | ${shippingRequest.id.toString()}").toText(fontSize: 16), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + "customer name".toText(color: MyColors.lightTextColor, fontSize: 14), + if (shippingRequest.createdOn != null && shippingRequest.createdOn!.isNotEmpty) ...[ + " | ${DateTime.parse(shippingRequest.createdOn!).getTimeAgo()}".toText(color: MyColors.lightTextColor, fontSize: 14), + ], + ], + ), + const Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18), + ], + ), + ], + ).onPress(() { + buildUpdateShippingStatusBottomSheet(shippingRequestId: shippingRequest.id!); + }).toContainer(isShadowEnabled: true); + }, + separatorBuilder: (context, index) => 16.height, + ), + )), + ], + ), + )); + }); + } +}