diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 582f61e..ac888be 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -805,5 +805,8 @@ "enterEndPrice": "أدخل سعر النهاية", "searchByVehicleType": "البحث حسب نوع المركبة", "selectVehicleType": "اختر نوع المركبة", - "specialRequestsChats": "دردشات الطلبات الخاصة" + "specialRequestsChats": "دردشات الطلبات الخاصة", + "selectDeliveryOption": "اختر خيار التوصيل", + "deliveryOptions": "خيارات التوصيل", + "selfPickup": "الالتقاط الذاتي" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 6ef6e82..2458b87 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -803,5 +803,8 @@ "enterEndPrice": "Enter end price", "searchByVehicleType": "Search by vehicle type", "selectVehicleType": "Select vehicle type", - "specialRequestsChats": "Special Requests Chats" + "specialRequestsChats": "Special Requests Chats", + "selectDeliveryOption": "Select Delivery Option", + "deliveryOptions": "Delivery Options", + "selfPickup": "Self Pickup" } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 7476bc5..041388d 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -182,6 +182,8 @@ class ApiConsts { //Shipping static String shippingRequestStatusUpdate = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Update"; static String shippingRequestStatusGet = "${baseUrlServices}api/RequestManagement/ShippingRequestStatus_Get"; + static String selfPickupRequestStatusGet = "${baseUrlServices}api/RequestManagement/SelfPickUpRequestStatus_Get"; + static String selfPickupRequestStatusUpdate = "${baseUrlServices}api/RequestManagement/SelfPickUpRequestStatus_Update"; //Chat static String chatHubUrl = "$baseUrlServices/McHub"; @@ -190,6 +192,7 @@ class ApiConsts { static String getChatMessagesForRequests = "${baseUrlServices}api/RequestManagement/ReqOfferChat_Get"; static String getChatMessagesForAds = "${baseUrlServices}api/Advertisement/AdsChat_Get"; static String getChatBuyersForAds = "${baseUrlServices}api/Advertisement/AdsChatBuyer_Get"; + static String reqChatUnreadGet = "${baseUrlServices}api/RequestManagement/Req_ChatUnread_Get"; //Settings Options static String getAllFAQs = "${baseUrlServices}api/Common/FAQ_Get"; @@ -226,6 +229,7 @@ class GlobalConsts { static String welcomeVideoUrl = "welcomeVideoUrl"; static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; static String demandAmountError = "Amount Cannot be Empty"; + static String deliveryOptionSelectionError = "At least one delivery option should be selected."; static String reservationCancelError = "Cancellation Reason Cannot be Empty"; static String descriptionError = "Description should be more than 5 letters."; static String acceptingThisOffer = "I am accepting this offer."; @@ -420,42 +424,44 @@ class SignalrConsts { } class GuestConsts { - UserInfo userInfo = UserInfo.fromJson({ - "id": -1, - "userID": null, - "firstName": "Guest", - "lastName": "User", - "companyName": null, - "accountStatus": "2", - "activityStatus": "Offline", - "accountStatusText": null, - "subscriptionDate": null, - "mobileNo": "966123456789", - "email": "mowatter@gmail.com", - "userImageUrl": "https://ms.hmg.com/api/ProfileImage?imageName=User_Default.png", - "roleID": 4, - "roleName": "Customer", - "isEmailVerified": false, - "serviceProviderBranch": [], - "isVerified": true, - "userRoles": [], - "isProviderDealership": false, - "isProviderIndividual": false, - "isProvider": false, - "providerID": null, - "isCustomer": true, - "customerID": 25, - "countryID": 1, - "countryName": "Saudi Arabia", - "cityID": 1, - "cityName": "Riyadh", - "dealershipUserID": null, - "serviceProviderBranchID": null, - "createdOn": "2024-12-24T09:20:47.6733333", - "genderID": 1, - "genderName": "Male", - "serviceProviderPayment": [], - "deviceType": "1", - "deviceToken": null, - }); + UserInfo userInfo = UserInfo.fromJson( + { + "id": -1, + "userID": null, + "firstName": "Guest", + "lastName": "User", + "companyName": null, + "accountStatus": "2", + "activityStatus": "Offline", + "accountStatusText": null, + "subscriptionDate": null, + "mobileNo": "966123456789", + "email": "mowatter@gmail.com", + "userImageUrl": "https://ms.hmg.com/api/ProfileImage?imageName=User_Default.png", + "roleID": 4, + "roleName": "Customer", + "isEmailVerified": false, + "serviceProviderBranch": [], + "isVerified": true, + "userRoles": [], + "isProviderDealership": false, + "isProviderIndividual": false, + "isProvider": false, + "providerID": null, + "isCustomer": true, + "customerID": 25, + "countryID": 1, + "countryName": "Saudi Arabia", + "cityID": 1, + "cityName": "Riyadh", + "dealershipUserID": null, + "serviceProviderBranchID": null, + "createdOn": "2024-12-24T09:20:47.6733333", + "genderID": 1, + "genderName": "Male", + "serviceProviderPayment": [], + "deviceType": "1", + "deviceToken": null, + }, + ); } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 7a07061..562a793 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -975,7 +975,7 @@ extension ShippingStatusEnumExt on int { return ShippingRequestStatusEnum.inTransit; } else if (this == 3) { return ShippingRequestStatusEnum.outForDelivery; - } else if (this == 4) { + } else if (this == 4) { return ShippingRequestStatusEnum.delivered; } return ShippingRequestStatusEnum.pending; @@ -1003,6 +1003,83 @@ extension ShippingStatusEnumToInt on ShippingRequestStatusEnum { } } +extension SelfPickupStatusEnumExt on int { + SelfPickupRequestStatusEnum toSelfPickupStatusEnum() { + if (this == -1) { + return SelfPickupRequestStatusEnum.allRequests; + } else if (this == 0) { + return SelfPickupRequestStatusEnum.allRequests; + } else if (this == 1) { + return SelfPickupRequestStatusEnum.preparingToCollect; + } else if (this == 2) { + return SelfPickupRequestStatusEnum.readyToCollect; + } else if (this == 3) { + return SelfPickupRequestStatusEnum.collected; + } + return SelfPickupRequestStatusEnum.allRequests; + } +} + +extension SelfPickupStatusEnumToInt on SelfPickupRequestStatusEnum { + int getIdFromSelfPickupStatusEnum() { + switch (this) { + case SelfPickupRequestStatusEnum.allRequests: + return 0; + case SelfPickupRequestStatusEnum.preparingToCollect: + return 1; + case SelfPickupRequestStatusEnum.readyToCollect: + return 2; + case SelfPickupRequestStatusEnum.collected: + return 3; + default: + return -1; + } + } +} + +extension RequestDeliveryOptionEnumExt on int { + RequestDeliveryOptionEnum toRequestDeliveryOptionEnum() { + if (this == 1) { + return RequestDeliveryOptionEnum.delivery; + } else if (this == 2) { + return RequestDeliveryOptionEnum.selfPickup; + } else if (this == 3) { + return RequestDeliveryOptionEnum.both; + } + return RequestDeliveryOptionEnum.none; + } +} + +extension RequestDeliveryOptionEnumToIntExt on RequestDeliveryOptionEnum { + int getIdRequestDeliveryOptionEnum() { + switch (this) { + case RequestDeliveryOptionEnum.delivery: + return 1; + case RequestDeliveryOptionEnum.selfPickup: + return 2; + case RequestDeliveryOptionEnum.both: + return 3; + default: + return 0; + } + } +} + +extension RequestDeliveryOptionEnumTosTRINGExt on RequestDeliveryOptionEnum { + String getStringFromRequestDeliveryOptionEnum() { + switch (this) { + case RequestDeliveryOptionEnum.delivery: + return "Delivery"; + case RequestDeliveryOptionEnum.selfPickup: + return "Self Pickup"; + case RequestDeliveryOptionEnum.both: + return "Delivery, Self Pickup"; + default: + return "Self Pickup"; + } + } +} + extension CapitalizeFirstLetter on String { String capitalizeFirstLetter() { if (isEmpty) { diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 45dbe4b..c6059f1 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -821,7 +821,10 @@ class CodegenLoader extends AssetLoader{ "enterEndPrice": "أدخل سعر النهاية", "searchByVehicleType": "البحث حسب نوع المركبة", "selectVehicleType": "اختر نوع المركبة", - "specialRequestsChats": "دردشات الطلبات الخاصة" + "specialRequestsChats": "دردشات الطلبات الخاصة", + "selectDeliveryOption": "اختر خيار التوصيل", + "deliveryOptions": "خيارات التوصيل", + "selfPickup": "الالتقاط الذاتي" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1628,7 +1631,10 @@ static const Map en_US = { "enterEndPrice": "Enter end price", "searchByVehicleType": "Search by vehicle type", "selectVehicleType": "Select vehicle type", - "specialRequestsChats": "Special Requests Chats" + "specialRequestsChats": "Special Requests Chats", + "selectDeliveryOption": "Select Delivery Option", + "deliveryOptions": "Delivery Options", + "selfPickup": "Self Pickup" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index cad4d35..90c5dfb 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -785,5 +785,8 @@ abstract class LocaleKeys { static const searchByVehicleType = 'searchByVehicleType'; static const selectVehicleType = 'selectVehicleType'; static const specialRequestsChats = 'specialRequestsChats'; + static const selectDeliveryOption = 'selectDeliveryOption'; + static const deliveryOptions = 'deliveryOptions'; + static const selfPickup = 'selfPickup'; } diff --git a/lib/models/chat_models/chat_message_model.dart b/lib/models/chat_models/chat_message_model.dart index 63ce43a..f5768e4 100644 --- a/lib/models/chat_models/chat_message_model.dart +++ b/lib/models/chat_models/chat_message_model.dart @@ -84,6 +84,7 @@ class ReqOffer { String? manufacturedOn; double? price; bool? isDeliveryAvailable; + RequestDeliveryOptionEnum? requestDeliveryOption; RequestsTypeEnum? requestsTypeEnum; RequestOfferStatusEnum? requestOfferStatusEnum; List? reqOfferImages; @@ -100,6 +101,7 @@ class ReqOffer { this.manufacturedOn, this.price, this.isDeliveryAvailable, + this.requestDeliveryOption, this.requestOfferStatusEnum, this.requestsTypeEnum, this.reqOfferImages, @@ -117,6 +119,7 @@ class ReqOffer { manufacturedOn = json['offeredItemCreatedOn'] ?? json["createdOn"]; price = json['price']; isDeliveryAvailable = json['isDeliveryAvailable']; + requestDeliveryOption = ((json['offerDeliveryOption'] ?? 0) as int).toRequestDeliveryOptionEnum(); requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum(); requestsTypeEnum = RequestsTypeEnum.serviceRequest; // if (isForReqOfferImagesURLs) { diff --git a/lib/models/requests_models/offers_unread_chat_model.dart b/lib/models/requests_models/offers_unread_chat_model.dart new file mode 100644 index 0000000..9cb2223 --- /dev/null +++ b/lib/models/requests_models/offers_unread_chat_model.dart @@ -0,0 +1,45 @@ +class OffersUnreadChatModel { + final int reqTotal; + final List reqChatUnread; + + OffersUnreadChatModel({ + required this.reqTotal, + required this.reqChatUnread, + }); + + factory OffersUnreadChatModel.fromJson(Map json) { + return OffersUnreadChatModel( + reqTotal: json['reqTotal'], + reqChatUnread: (json['reqChatUnread'] as List).map((e) => OffersUnreadChatDataModel.fromJson(e)).toList(), + ); + } +} + +class OffersUnreadChatDataModel { + final String senderUserID; + final int unreadMessagesCount; + final int requestId; + final String lastChatTime; + final String lastChatText; + final String customerName; + + OffersUnreadChatDataModel({ + required this.senderUserID, + required this.unreadMessagesCount, + required this.requestId, + required this.lastChatTime, + required this.lastChatText, + required this.customerName, + }); + + factory OffersUnreadChatDataModel.fromJson(Map json) { + return OffersUnreadChatDataModel( + senderUserID: json['senderUserID'], + unreadMessagesCount: json['unreadMessagesCount'], + requestId: json['requestId'] ?? 0, + lastChatTime: json['lastChatTime'], + lastChatText: json['lastChatText'], + customerName: json['customerName'], + ); + } +} diff --git a/lib/models/requests_models/provider_offers_model.dart b/lib/models/requests_models/provider_offers_model.dart index a2f6fe2..00bc433 100644 --- a/lib/models/requests_models/provider_offers_model.dart +++ b/lib/models/requests_models/provider_offers_model.dart @@ -66,6 +66,7 @@ class ServiceProvidersOffers { RequestOfferStatusEnum? requestOfferStatusEnum; int? offerCount; int? requestId; + String? providerAddress; List? chatMessages; ServiceProvidersOffers({ @@ -80,6 +81,7 @@ class ServiceProvidersOffers { this.providerUserId, this.createdOn, this.requestOfferStatusEnum, + this.providerAddress, }); ServiceProvidersOffers.fromJson(Map json, int? reqId) { @@ -93,6 +95,7 @@ class ServiceProvidersOffers { requestId = reqId; createdOn = json['createdOn']; requestOfferStatusEnum = ((json['offerStatusLast']) as int).toRequestOfferStatusEnum(); + providerAddress = "Will be in API in case of self pickup"; chatMessages = []; } diff --git a/lib/repositories/request_repo.dart b/lib/repositories/request_repo.dart index 6a72ab6..fd25242 100644 --- a/lib/repositories/request_repo.dart +++ b/lib/repositories/request_repo.dart @@ -6,6 +6,7 @@ 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/models/general_models/generic_resp_model.dart'; +import 'package:mc_common_app/models/requests_models/offers_unread_chat_model.dart'; import 'package:mc_common_app/models/requests_models/provider_offers_model.dart'; import 'package:mc_common_app/models/requests_models/providers_offers_chat_model.dart'; import 'package:mc_common_app/models/requests_models/request_model.dart'; @@ -30,6 +31,8 @@ abstract class RequestRepo { Future> getOffersChatByProvider({int requestId = 0, required int serviceProviderId}); + Future getOffersChatsUnreadList({required String userId}); + Future getOffersFromProvidersByRequest({required int requestId}); Future> getRequests({required int providerOrCustomerID}); @@ -61,6 +64,7 @@ abstract class RequestRepo { required int offerId, required String offerPrice, required bool isDeliveryAvailable, + required int offerDeliveryOption, required String serviceItemName, required String manufacturedByName, required String manufacturedOn, @@ -293,6 +297,22 @@ class RequestRepoImp implements RequestRepo { return offersList; } + @override + Future getOffersChatsUnreadList({required String userId}) async { + var queryParameters = { + "ReceiverUserID": userId.toString(), + }; + GenericRespModel genericRespModel = await apiClient.getJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.reqChatUnreadGet, + queryParameters: queryParameters, + token: appState.getUser.data!.accessToken, + ); + OffersUnreadChatModel offersUnreadChatModel = OffersUnreadChatModel.fromJson(genericRespModel.data); + + return offersUnreadChatModel; + } + @override Future getOffersFromProvidersByRequest({required int requestId}) async { final customerId = appState.getUser.data!.userInfo!.customerId; @@ -353,6 +373,7 @@ class RequestRepoImp implements RequestRepo { required int offerId, required String offerPrice, required bool isDeliveryAvailable, + required int offerDeliveryOption, required String serviceItemName, required String manufacturedByName, required String manufacturedOn, @@ -372,7 +393,8 @@ class RequestRepoImp implements RequestRepo { "offeredItemCreatedByName": manufacturedByName.toString(), "offeredItemCreatedOn": manufacturedOn.toString(), "reqOfferImages": requestImages, - "isDeliveryAvailable": isDeliveryAvailable + "isDeliveryAvailable": isDeliveryAvailable, + "offerDeliveryOption": offerDeliveryOption }; GenericRespModel genericRespModel = await apiClient.postJsonForObject( (json) => GenericRespModel.fromJson(json), diff --git a/lib/repositories/shipping_repo.dart b/lib/repositories/shipping_repo.dart index baa2a46..8812ab9 100644 --- a/lib/repositories/shipping_repo.dart +++ b/lib/repositories/shipping_repo.dart @@ -14,9 +14,13 @@ import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/utils.dart'; abstract class ShippingRepo { + Future> getSelfPickupRequestListByStatus({SelfPickupRequestStatusEnum? selfPickupRequestStatus, int? requestId}); + Future> getShippingRequestListByStatus({ShippingRequestStatusEnum? shippingStatusEnum, int? requestId}); Future updateShippingRequestStatus({required ShippingRequestStatusEnum shippingStatusEnum, required int shippingRequestId, String? comment}); + + Future updateSelfPickupRequestStatus({required SelfPickupRequestStatusEnum selfPickupStatusEnum, required int shippingRequestId, String? comment}); } class ShippingRepoImp extends ShippingRepo { @@ -48,6 +52,31 @@ class ShippingRepoImp extends ShippingRepo { return list; } + @override + Future> getSelfPickupRequestListByStatus({SelfPickupRequestStatusEnum? selfPickupRequestStatus, int? requestId}) async { + String token = appState.getUser.data!.accessToken ?? ""; + Map queryParameters = { + "requestID": "${requestId ?? 0}", + "selfPickUpStatus": "${selfPickupRequestStatus != null ? selfPickupRequestStatus.getIdFromSelfPickupStatusEnum() : -1}", // -1 to get all requests + }; + + GenericRespModel genericRespModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.selfPickupRequestStatusGet, + 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 ?? ""; @@ -70,4 +99,27 @@ class ShippingRepoImp extends ShippingRepo { return genericRespModel; } + + @override + Future updateSelfPickupRequestStatus({required SelfPickupRequestStatusEnum selfPickupStatusEnum, required int shippingRequestId, String? comment}) async { + String token = appState.getUser.data!.accessToken ?? ""; + Map queryParameters = { + "id": "$shippingRequestId", + "selfPickUpStatus": "${selfPickupStatusEnum.getIdFromSelfPickupStatusEnum()}", + "comment": comment ?? "", + }; + + GenericRespModel genericRespModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.selfPickupRequestStatusUpdate, + 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 c8d0732..b8f8c57 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -19,6 +19,8 @@ class AppEnums { static const int conditionEnumId = -1; // to get the Condition Filter Enums static const int serviceDeliveryTypeEnumId = 24; // to get the serviceDeliveryType static const int shippingStatusEnumId = 30; // to get the Shipping Filter Enums + static const int selfPickupStatusEnumId = 33; // to get the SelfPickup Status Enums + static const int deliveryOptionEnumId = 32; // to get the SelfPickup Status Enums } enum DashboardRouteEnum { @@ -223,10 +225,9 @@ enum SubscriptionActionTypeEnum { ads, users, branches, - subscription + subscription, } - enum ShippingRequestStatusEnum { allRequests, pending, @@ -236,10 +237,22 @@ enum ShippingRequestStatusEnum { delivered, } +enum SelfPickupRequestStatusEnum { + allRequests, + preparingToCollect, + readyToCollect, + collected, +} + +enum RequestDeliveryOptionEnum { + none, + delivery, + selfPickup, + both, +} enum InviteTypeEnum { whatsapp, sms, email, } - diff --git a/lib/view_models/chat_view_model.dart b/lib/view_models/chat_view_model.dart index 9f7ea92..3eeeae2 100644 --- a/lib/view_models/chat_view_model.dart +++ b/lib/view_models/chat_view_model.dart @@ -362,6 +362,7 @@ class ChatVM extends BaseVM { required int requestId, required String offerPrice, required bool isDeliveryAvailable, + required RequestDeliveryOptionEnum offerDeliveryOption, required String serviceItemName, required String manufacturedByName, required String manufacturedOn, @@ -385,10 +386,11 @@ class ChatVM extends BaseVM { "RequestID": requestId, "Price": double.parse(offerPrice), "IsDeliveryAvailable": isDeliveryAvailable, + "OfferDeliveryOption": offerDeliveryOption.getIdRequestDeliveryOptionEnum(), "ServiceItem": serviceItemName, "ReqOfferImages": offerImages, "OfferedItemCreatedByName": manufacturedByName, - "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime + // "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime "ServiceProviderID": providerId, "OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(), "Comment": message, @@ -651,6 +653,8 @@ class ChatVM extends BaseVM { required int serviceProviderID, required int requestOfferID, required String offerPrice, + required bool isDeliveryAvailable, + required RequestDeliveryOptionEnum offerDeliveryOption, required String serviceItemName, required String manufacturedByName, required String manufacturedOn, @@ -675,6 +679,9 @@ class ChatVM extends BaseVM { "Price": double.parse(offerPrice), "ServiceItem": serviceItemName, "OfferedItemCreatedByName": manufacturedByName, + "IsDeliveryAvailable": isDeliveryAvailable, + "OfferDeliveryOption": offerDeliveryOption.getIdRequestDeliveryOptionEnum(), + // We have commented this because Backend Team is using their server time for this. It was the time offer created by // "OfferedItemCreatedOn": manufacturedOn, "ServiceProviderID": serviceProviderID, "OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(), diff --git a/lib/view_models/dashboard_view_model_customer.dart b/lib/view_models/dashboard_view_model_customer.dart index 195d763..247496e 100644 --- a/lib/view_models/dashboard_view_model_customer.dart +++ b/lib/view_models/dashboard_view_model_customer.dart @@ -68,6 +68,7 @@ class DashboardVmCustomer extends BaseVM { await appointmentsVM.populateAppointmentsFilterList(); await adVM.populateAdsFilterList(); await requestsVM.populateDataForRequestsFilter(); + await requestsVM.populateDeliveryOptionEnums(); await appointmentsVM.applyFilterOnAppointmentsVMForCustomers(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, shouldPopulateUpcoming: true); await appointmentsVM.applyFilterOnBranches(index: 0); // to get all branches! await appointmentsVM.getMyRecentBranches(); // to get my recent branches diff --git a/lib/view_models/dashboard_view_model_provider.dart b/lib/view_models/dashboard_view_model_provider.dart index 6f9c38a..eeeed56 100644 --- a/lib/view_models/dashboard_view_model_provider.dart +++ b/lib/view_models/dashboard_view_model_provider.dart @@ -79,20 +79,23 @@ class DashboardVMProvider extends BaseVM { final serviceVM = context.read(); final adVM = context.read(); final subscriptionsVM = context.read(); - requestsVM.populateDataForRequestsFilter(); - appointmentVM.populateAppointmentsFilterList(); - shippingManagementVM.populateShippingRequestFilterList(); + await requestsVM.populateDataForRequestsFilter(); + await requestsVM.populateDeliveryOptionEnums(); + await appointmentVM.populateAppointmentsFilterList(); + await adVM.populateAdsFilterList(); await serviceVM.populateBranchServiceFilters(); await serviceVM.getBranchAndServices(); + await requestsVM.getRequests(); + await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); if (dashboardRouteEnum != DashboardRouteEnum.fromAdsPayment && dashboardRouteEnum != DashboardRouteEnum.fromAdsSubmit) { await adVM.getMyAds(); await adVM.getExploreAds(); } + await shippingManagementVM.populateShippingRequestFilterList(); + await shippingManagementVM.populateSelfPickupRequestFilterList(); await appointmentVM.applyFilterOnAppointmentsVMForProviders(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, shouldPopulateUpcoming: true); - adVM.populateAdsFilterList(); - await requestsVM.getRequests(); - await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); + await adVM.getVehicleTypes(); await adVM.getVehicleAdsDuration(); await chatVM.buildHubConnection(context); diff --git a/lib/view_models/payment_view_model.dart b/lib/view_models/payment_view_model.dart index 3e5d666..bcb4030 100644 --- a/lib/view_models/payment_view_model.dart +++ b/lib/view_models/payment_view_model.dart @@ -217,7 +217,7 @@ class PaymentVM extends ChangeNotifier { context.read().onNavbarTapped(1); } navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); - } + } Future onVisaCardSelected(BuildContext context, PaymentTypes paymentType) async { currentPaymentType = paymentType; diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index c773ceb..24e7bed 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -18,6 +18,7 @@ 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/requests_models/offers_model.dart'; +import 'package:mc_common_app/models/requests_models/offers_unread_chat_model.dart'; import 'package:mc_common_app/models/requests_models/provider_offers_model.dart'; import 'package:mc_common_app/models/requests_models/providers_offers_chat_model.dart'; import 'package:mc_common_app/models/requests_models/request_model.dart'; @@ -843,12 +844,12 @@ class RequestsVM extends BaseVM { return isValid; } - List providerOffersChatsList = []; + Future getOffersChatByProvider({required int providerId, required BuildContext context}) async { + List providerOffersChatsList = []; - Future getProviderOffersChatsList({required int serviceProviderId, required BuildContext context}) async { try { Utils.showLoading(context); - List respModel = await requestRepo.getOffersChatByProvider(serviceProviderId: serviceProviderId); + List respModel = await requestRepo.getOffersChatByProvider(serviceProviderId: providerId); Utils.hideLoading(context); providerOffersChatsList.clear(); providerOffersChatsList = respModel; @@ -860,7 +861,26 @@ class RequestsVM extends BaseVM { } } + OffersUnreadChatModel? offersUnreadChatModel; + + Future getOffersChatsUnreadList({required String userId, required BuildContext context}) async { + try { + Utils.showLoading(context); + OffersUnreadChatModel respModel = await requestRepo.getOffersChatsUnreadList(userId: userId); + Utils.hideLoading(context); + offersUnreadChatModel = respModel; + log("offersUnreadChatModel: ${offersUnreadChatModel!.reqChatUnread.length}"); + notifyListeners(); + } catch (e) { + logger.e(e.toString()); + Utils.showToast(e.toString()); + Utils.hideLoading(context); + return; + } + } + String offerPriceError = ""; + String offerDescriptionError = ""; String offerPrice = ""; @@ -907,6 +927,39 @@ class RequestsVM extends BaseVM { } } + String deliveryOptionSelectionError = ""; + + List myDeliveryOptionsEnum = []; + List myDeliveryOptionsFilterOptions = []; + + Future populateDeliveryOptionEnums() async { + if (myDeliveryOptionsFilterOptions.isNotEmpty) return; + + try { + notifyListeners(); + myDeliveryOptionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.deliveryOptionEnumId); + + for (int i = 0; i < myDeliveryOptionsEnum.length; i++) { + myDeliveryOptionsFilterOptions.add(FilterListModel(title: myDeliveryOptionsEnum[i].enumValueStr, isSelected: false, id: myDeliveryOptionsEnum[i].enumValue)); + } + + notifyListeners(); + } catch (e) { + logger.e(e.toString()); + } + } + + Future applyFilterOnDeliveryOption({required RequestDeliveryOptionEnum requestDeliveryOptionEnum}) async { + if (myDeliveryOptionsFilterOptions.isEmpty) return; + for (var value in myDeliveryOptionsFilterOptions) { + value.isSelected = false; + } + if (requestDeliveryOptionEnum != RequestDeliveryOptionEnum.none) { + myDeliveryOptionsFilterOptions[requestDeliveryOptionEnum.getIdRequestDeliveryOptionEnum() - 1].isSelected = true; // -1 to match with the index + } + notifyListeners(); + } + List providerDeliveryActionsList = [ OfferRequestCommentModel( index: 0, @@ -974,19 +1027,40 @@ class RequestsVM extends BaseVM { } else { offerDescriptionError = ""; } + + if (currentSelectedRequest != null && currentSelectedRequest!.requestType == RequestsTypeEnum.serviceRequest.getIdFromRequestTypeEnum()) { + int index = myDeliveryOptionsFilterOptions.indexWhere((option) => option.isSelected); + if (index == -1) { + deliveryOptionSelectionError = GlobalConsts.deliveryOptionSelectionError; + log("indexindex: ${index}"); + isValidated = false; + } + + notifyListeners(); + } else { + deliveryOptionSelectionError = ""; + } + notifyListeners(); + log("isValidatedisValidated: ${isValidated}"); + return isValidated; } void resetSendOfferBottomSheet() { offerPrice = ""; + offerPriceError = ""; offerDescription = ""; offerDescriptionError = ""; + deliveryOptionSelectionError = ""; serviceItem = ""; serviceItemCreatedOn = ""; itemManufacturer = ""; isDeliveryAvailableStatus = false; + if (myDeliveryOptionsFilterOptions.isNotEmpty) { + myDeliveryOptionsFilterOptions.forEach((option) => option.isSelected = false); + } pickedVehicleImages.clear(); notifyListeners(); } @@ -1055,6 +1129,7 @@ class RequestsVM extends BaseVM { required int offerId, required String offerPrice, required bool isDeliveryAvailable, + required RequestDeliveryOptionEnum offerDeliveryOption, required String serviceItemName, required String manufacturedByName, required String manufacturedOn, @@ -1077,6 +1152,7 @@ class RequestsVM extends BaseVM { offerId: offerId, offerPrice: offerPrice, isDeliveryAvailable: isDeliveryAvailable, + offerDeliveryOption: offerDeliveryOption.getIdRequestDeliveryOptionEnum(), serviceItemName: serviceItemName, manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, @@ -1120,6 +1196,7 @@ class RequestsVM extends BaseVM { required String manufacturedOn, required RequestModel requestModel, required bool isDeliveryAvailable, + required RequestDeliveryOptionEnum offerDeliveryOption, required int requestIndex, required bool isFromChatScreen, required int? offerId, @@ -1139,6 +1216,7 @@ class RequestsVM extends BaseVM { requestId: requestId, offerPrice: offerPrice, isDeliveryAvailable: isDeliveryAvailable, + offerDeliveryOption: offerDeliveryOption, manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, serviceItemName: serviceItemName, @@ -1173,6 +1251,7 @@ class RequestsVM extends BaseVM { requestID: requestModel.id, price: double.parse(offerPrice), isDeliveryAvailable: isDeliveryAvailable, + requestDeliveryOption: offerDeliveryOption, manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, serviceItemName: serviceItemName, @@ -1182,6 +1261,7 @@ class RequestsVM extends BaseVM { reqOfferImages: images, ), ); + context.read().onNewMessageReceivedForRequestOffer(messages: [chatMessageModel], requestsVM: this, isMyOwnOffer: true); if (!isFromChatScreen) { diff --git a/lib/view_models/shipping_management_view_model.dart b/lib/view_models/shipping_management_view_model.dart index b981134..661306d 100644 --- a/lib/view_models/shipping_management_view_model.dart +++ b/lib/view_models/shipping_management_view_model.dart @@ -21,8 +21,11 @@ class ShippingManagementVM extends BaseVM { List shippingRequestsList = []; - List shippingStatusEnums = []; + List selfPickupStatusEnums = []; + List selfPickupRequestsFilterOptions = []; + List selfPickupRequestsStatusesList = []; + List shippingStatusEnums = []; List shippingRequestFilterOptions = []; List shippingRequestStatusesList = []; @@ -32,15 +35,41 @@ class ShippingManagementVM extends BaseVM { requestStatusComments = value; } + bool isSelfPickupTapped = false; + + void updateIsSelfPickupTapped(var value) { + isSelfPickupTapped = value; + notifyListeners(); + } + resetFilters() { if (shippingRequestFilterOptions.isEmpty) return; for (var value in shippingRequestFilterOptions) { value.isSelected = false; } shippingRequestFilterOptions[0].isSelected = true; + + if (selfPickupRequestsFilterOptions.isEmpty) return; + for (var value in selfPickupRequestsFilterOptions) { + value.isSelected = false; + } + selfPickupRequestsFilterOptions[0].isSelected = true; requestStatusComments = ""; } + Future populateSelfPickupRequestFilterList() async { + selfPickupStatusEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.selfPickupStatusEnumId); + selfPickupRequestsFilterOptions.clear(); + selfPickupRequestsStatusesList.clear(); + for (int i = 0; i < selfPickupStatusEnums.length; i++) { + selfPickupRequestsFilterOptions.add(FilterListModel(title: selfPickupStatusEnums[i].enumValueStrDes, isSelected: false, id: selfPickupStatusEnums[i].enumValue)); + selfPickupRequestsStatusesList.add(FilterListModel(title: selfPickupStatusEnums[i].enumValueStrDes, isSelected: false, id: selfPickupStatusEnums[i].enumValue)); + } + + selfPickupRequestsFilterOptions.insert(0, FilterListModel(title: Utils.getNameByShippingRequestStatusEnum(ShippingRequestStatusEnum.allRequests), isSelected: true, id: -1)); + notifyListeners(); + } + Future populateShippingRequestFilterList() async { // if (shippingRequestFilterOptions.isNotEmpty && shippingRequestStatusesList.isNotEmpty) return; @@ -78,6 +107,22 @@ class ShippingManagementVM extends BaseVM { notifyListeners(); } + Future applyFiltersOnSelfPickupRequests({required SelfPickupRequestStatusEnum selfPickupRequestStatusEnum}) async { + for (var value in selfPickupRequestsFilterOptions) { + value.isSelected = false; + } + if (selfPickupRequestStatusEnum == SelfPickupRequestStatusEnum.allRequests) { + selfPickupRequestsFilterOptions[0].isSelected = true; + await getSelfPickupRequestsListByFilters(); + notifyListeners(); + return; + } + int index = selfPickupRequestsFilterOptions.indexWhere((element) => element.id == selfPickupRequestStatusEnum.getIdFromSelfPickupStatusEnum()); + selfPickupRequestsFilterOptions[index].isSelected = true; // +1 to match with the index 0 index has all requests + await getSelfPickupRequestsListByFilters(selfPickupStatusEnum: selfPickupRequestStatusEnum); + notifyListeners(); + } + void updateSelectionInShippingRequestStatuses(int index) { for (var value in shippingRequestStatusesList) { value.isSelected = false; @@ -99,6 +144,19 @@ class ShippingManagementVM extends BaseVM { } } + Future getSelfPickupRequestsListByFilters({SelfPickupRequestStatusEnum? selfPickupStatusEnum}) async { + setState(ViewState.busy); + try { + shippingRequestsList = await shippingRepo.getSelfPickupRequestListByStatus(selfPickupRequestStatus: selfPickupStatusEnum); + 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 { 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 d4e7e62..9a7c175 100644 --- a/lib/views/advertisement/ads_detail_view/ads_detail_view.dart +++ b/lib/views/advertisement/ads_detail_view/ads_detail_view.dart @@ -370,7 +370,32 @@ class _AdsDetailViewState extends State { ], ), ], - ).paddingOnly(top: 5, bottom: 2).toWhiteContainer(width: double.infinity, allPading: 12); + ).paddingOnly(top: 2, bottom: 2).toWhiteContainer(width: double.infinity, allPading: 12); + } + + Widget buildSpecialServicesContainer() { + if (widget.adDetails.specialservice == null || widget.adDetails.specialservice!.isEmpty) { + return const SizedBox(); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.specialServices.tr().toText(fontSize: 16), + 3.height, + Column( + children: List.generate( + widget.adDetails.specialservice!.length, + (index) => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: ("${widget.adDetails.specialservice![index].name}").toText(fontSize: 14, color: MyColors.lightTextColor)), + ("${widget.adDetails.specialservice![index].price} ${LocaleKeys.sar.tr()} ").toText(fontSize: 14, color: MyColors.lightTextColor), + ], + )), + ), + ], + ).paddingOnly(bottom: 2).toWhiteContainer(width: double.infinity, allPading: 12); } @override @@ -395,8 +420,12 @@ class _AdsDetailViewState extends State { width: 42, ); } else if ((widget.adDetails.adPostStatus != AdPostStatus.pendingForPost)) { - actionWidget = - IconButton(icon: const Icon(Icons.chat_outlined, color: Colors.black), onPressed: () => adVM.onMessagesButtonPressed(context: context, adDetailsModel: widget.adDetails)).toContainer( + actionWidget = IconButton( + icon: const Icon(Icons.chat_outlined, color: Colors.black), + onPressed: () => adVM.onMessagesButtonPressed( + context: context, + adDetailsModel: widget.adDetails, + )).toContainer( margin: const EdgeInsets.fromLTRB(0, 8, 21, 8), paddingAll: 0, borderRadius: 100, @@ -434,6 +463,10 @@ class _AdsDetailViewState extends State { buildPersonalInformationCard(context: context), ], if (widget.adDetails.isMyAd ?? false) ...[ + if (widget.adDetails.specialservice != null && widget.adDetails.specialservice!.isNotEmpty) ...[ + 12.height, + buildSpecialServicesContainer(), + ], 12.height, buildAdStartEndDates(), ], diff --git a/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart b/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart index 44ce445..8c621b4 100644 --- a/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart +++ b/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart @@ -2,6 +2,7 @@ import 'dart:developer'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; @@ -12,6 +13,7 @@ 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/view_models/ad_view_model.dart'; +import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -167,6 +169,7 @@ class AdDurationSelectionSheet extends StatelessWidget { if (adVM.isFetchingLists) { return; } else { + final subscriptionsVM = context.read(); if (isFromExtendAd && !isUpdateAdSelected) { List statuses = await adVM.createAdExtensionOrder(context, adId: adsID, adsDurationId: adVM.vehicleAdDurationId.selectedId); // [0] Means API response [1] means isPaymentRequired @@ -176,6 +179,7 @@ class AdDurationSelectionSheet extends StatelessWidget { pop(context); pop(context); pop(context); + await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); adVM.applyFilterOnMyAds(adPostStatusEnum: AdPostStatus.active); } } else { diff --git a/lib/views/chat/chat_view.dart b/lib/views/chat/chat_view.dart index 00eee37..7f0a3aa 100644 --- a/lib/views/chat/chat_view.dart +++ b/lib/views/chat/chat_view.dart @@ -11,6 +11,7 @@ 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/chat_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_provider.dart'; import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/views/advertisement/ads_buyer_chats_view.dart'; @@ -175,30 +176,30 @@ class _ChatViewState extends State { child: chatMessages.isEmpty ? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor, textAlign: TextAlign.center)).paddingAll(22) : ListView.separated( - controller: chatVM.scrollController, - itemCount: chatMessages.length, - separatorBuilder: (BuildContext context, int index) => 20.height, - itemBuilder: (BuildContext context, int index) { - ChatMessageModel chatMessageModel = chatMessages[index]; - return ChatMessageCustomWidget( - chatMessageModel: chatMessageModel, - requestModel: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel! : null, - requestStatusEnum: requestVM.currentSelectedRequest?.requestStatus, - chatTypeEnum: chatTypeEnum, - requestsTypeEnum: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel!.requestType.toRequestTypeEnum() : RequestsTypeEnum.specialCarRequest, - ); - }, - ).horPaddingMain(), + controller: chatVM.scrollController, + itemCount: chatMessages.length, + separatorBuilder: (BuildContext context, int index) => 20.height, + itemBuilder: (BuildContext context, int index) { + ChatMessageModel chatMessageModel = chatMessages[index]; + return ChatMessageCustomWidget( + chatMessageModel: chatMessageModel, + requestModel: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel! : null, + requestStatusEnum: requestVM.currentSelectedRequest?.requestStatus, + chatTypeEnum: chatTypeEnum, + requestsTypeEnum: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel!.requestType.toRequestTypeEnum() : RequestsTypeEnum.specialCarRequest, + ); + }, + ).horPaddingMain(), ), 10.height, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (chatTypeEnum == ChatTypeEnum.requestOffer && + if ( + AppState().currentAppType == AppType.customer && chatTypeEnum == ChatTypeEnum.requestOffer && requestVM.currentSelectedRequest!.requestType.toRequestTypeEnum() == RequestsTypeEnum.serviceRequest && requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.inProgress && - requestVM.currentSelectedOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.accepted && - AppState().currentAppType == AppType.customer) ...[ + requestVM.currentSelectedOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.accepted ) ...[ Expanded( child: ShowFillButton( maxWidth: double.infinity, @@ -233,88 +234,93 @@ class _ChatViewState extends State { // ), // ] // - else ...[ - if (AppState().currentAppType == AppType.provider && - chatTypeEnum == ChatTypeEnum.requestOffer && - requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.submitted && - chatVM.pickedImagesForMessage.isEmpty) ...[ - Expanded( - flex: 1, - child: const Icon( - Icons.local_offer_rounded, - color: MyColors.darkPrimaryColor, - size: 30, - ).onPress( - () { - requestVM.resetSendOfferBottomSheet(); - RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments( - requestIndex: chatViewArgumentsForRequest!.requestIndex, - requestModel: chatViewArgumentsForRequest!.requestModel!, - ); - buildSendOfferBottomSheet( - context: context, - requestDetailPageArguments: requestDetailArguments, - isFromChatScreen: true, - offerId: null, // null means creating new offer - ); - }, + else + ...[ + if (AppState().currentAppType == AppType.provider && + chatTypeEnum == ChatTypeEnum.requestOffer && + requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.submitted && + chatVM.pickedImagesForMessage.isEmpty) ...[ + Expanded( + flex: 1, + child: const Icon( + Icons.local_offer_rounded, + color: MyColors.darkPrimaryColor, + size: 30, + ).onPress( + () { + requestVM.resetSendOfferBottomSheet(); + RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments( + requestIndex: chatViewArgumentsForRequest!.requestIndex, + requestModel: chatViewArgumentsForRequest!.requestModel!, + ); + context.read().checkUserSubscription(SubscriptionActionTypeEnum.subscription, context, callback: () { + buildSendOfferBottomSheet( + context: context, + requestDetailPageArguments: requestDetailArguments, + isFromChatScreen: true, + offerId: null, // null means creating new offer + ); + }); + }, + ), ), - ), - ], - if (chatVM.pickedImagesForMessage.isNotEmpty) ...[ - Expanded( - flex: 8, - child: PickedFilesContainer( - pickedFiles: chatVM.pickedImagesForMessage, - onCrossPressedPrimary: chatVM.removeImageFromList, - onAddFilePressed: () => chatVM.pickMultipleImages(), + ], + if (chatVM.pickedImagesForMessage.isNotEmpty) ...[ + Expanded( + flex: 8, + child: PickedFilesContainer( + pickedFiles: chatVM.pickedImagesForMessage, + onCrossPressedPrimary: chatVM.removeImageFromList, + onAddFilePressed: () => chatVM.pickMultipleImages(), + ), ), - ), - ] else if (chatTypeEnum == ChatTypeEnum.requestOffer) ...[ + ] else + if (chatTypeEnum == ChatTypeEnum.requestOffer) ...[ + Expanded( + flex: 1, + child: const Icon( + Icons.photo_library_rounded, + color: MyColors.darkPrimaryColor, + size: 30, + ).onPress(() => chatVM.pickMultipleImages()), + ), + ], + if (chatVM.pickedImagesForMessage.isEmpty) ...[ + Expanded( + flex: 8, + child: TxtField( + isNeedLabelOnTop: false, + value: chatVM.chatMessageText, + hint: LocaleKeys.typeMessageHere.tr(), + keyboardType: TextInputType.text, + isNeedBorder: false, + onChanged: (v) => chatVM.updateChatMessageText(v), + ), + ), + ], Expanded( flex: 1, - child: const Icon( - Icons.photo_library_rounded, - color: MyColors.darkPrimaryColor, - size: 30, - ).onPress(() => chatVM.pickMultipleImages()), - ), - ], - if (chatVM.pickedImagesForMessage.isEmpty) ...[ - Expanded( - flex: 8, - child: TxtField( - value: chatVM.chatMessageText, - hint: LocaleKeys.typeMessageHere.tr(), - keyboardType: TextInputType.text, - isNeedBorder: false, - onChanged: (v) => chatVM.updateChatMessageText(v), - ), - ), - ], - Expanded( - flex: 1, - child: const Icon(Icons.send_rounded, color: MyColors.darkPrimaryColor, size: 30).onPress( - () async { - ChatMessageTypeEnum chatMessageTypeEnum = ChatMessageTypeEnum.freeText; + child: const Icon(Icons.send_rounded, color: MyColors.darkPrimaryColor, size: 30).onPress( + () async { + ChatMessageTypeEnum chatMessageTypeEnum = ChatMessageTypeEnum.freeText; - if (chatVM.pickedImagesForMessage.isNotEmpty) { - chatMessageTypeEnum = ChatMessageTypeEnum.image; - } - final status = await onMessageSend(chatMessageType: chatMessageTypeEnum); + if (chatVM.pickedImagesForMessage.isNotEmpty) { + chatMessageTypeEnum = ChatMessageTypeEnum.image; + } + final status = await onMessageSend(chatMessageType: chatMessageTypeEnum); - if (status) { - chatVM.scrollChatDown(); - if (chatMessageTypeEnum == ChatMessageTypeEnum.freeText) { - chatVM.clearChatMessageText(); - } else if (chatMessageTypeEnum == ChatMessageTypeEnum.image) { - chatVM.clearPickedImagesForMessage(); + if (status) { + chatVM.scrollChatDown(); + if (chatMessageTypeEnum == ChatMessageTypeEnum.freeText) { + chatVM.clearChatMessageText(); + } else if (chatMessageTypeEnum == ChatMessageTypeEnum.image) { + chatVM.clearPickedImagesForMessage(); + } } - } - }, + }, + ), ), - ), - ], + ], ], ).toContainer(isShadowEnabled: true) ], diff --git a/lib/views/chat/widgets/chat_message_widget.dart b/lib/views/chat/widgets/chat_message_widget.dart index 98be862..ab938bb 100644 --- a/lib/views/chat/widgets/chat_message_widget.dart +++ b/lib/views/chat/widgets/chat_message_widget.dart @@ -128,6 +128,8 @@ class _ChatMessageCustomWidgetState extends State { serviceProviderID: chatMessageModel.serviceProviderID ?? 0, requestOfferID: chatMessageModel.reqOffer!.id ?? -1, offerPrice: chatMessageModel.reqOffer!.price.toString(), + isDeliveryAvailable: chatMessageModel.reqOffer!.isDeliveryAvailable ?? false, + offerDeliveryOption: chatMessageModel.reqOffer!.requestDeliveryOption ?? RequestDeliveryOptionEnum.selfPickup, serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", @@ -227,6 +229,8 @@ class _ChatMessageCustomWidgetState extends State { serviceProviderID: chatMessageModel.serviceProviderID ?? 0, requestOfferID: chatMessageModel.reqOffer!.id ?? -1, offerPrice: chatMessageModel.reqOffer!.price.toString(), + isDeliveryAvailable: chatMessageModel.reqOffer!.isDeliveryAvailable ?? false, + offerDeliveryOption: chatMessageModel.reqOffer!.requestDeliveryOption ?? RequestDeliveryOptionEnum.selfPickup, serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", @@ -374,6 +378,8 @@ class _ChatMessageCustomWidgetState extends State { serviceProviderID: chatMessageModel.serviceProviderID ?? 0, requestOfferID: chatMessageModel.reqOffer!.id ?? -1, offerPrice: chatMessageModel.reqOffer!.price.toString(), + isDeliveryAvailable: chatMessageModel.reqOffer!.isDeliveryAvailable ?? false, + offerDeliveryOption: chatMessageModel.reqOffer!.requestDeliveryOption ?? RequestDeliveryOptionEnum.selfPickup, serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", @@ -428,6 +434,8 @@ class _ChatMessageCustomWidgetState extends State { serviceProviderID: chatMessageModel.serviceProviderID ?? 0, requestOfferID: chatMessageModel.reqOffer!.id ?? -1, offerPrice: chatMessageModel.reqOffer!.price.toString(), + isDeliveryAvailable: chatMessageModel.reqOffer!.isDeliveryAvailable ?? false, + offerDeliveryOption: chatMessageModel.reqOffer!.requestDeliveryOption ?? RequestDeliveryOptionEnum.selfPickup, serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", @@ -500,6 +508,7 @@ class _ChatMessageCustomWidgetState extends State { Widget buildOfferDetailsInChatMessage({required RequestStatusEnum requestStatusEnum, required ChatMessageModel chatMessageModel, required BuildContext context}) { final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer; + if (requestStatusEnum != RequestStatusEnum.submitted && requestOfferStatusEnum != RequestOfferStatusEnum.accepted) { return Column( children: [ @@ -744,6 +753,7 @@ class _ChatMessageCustomWidgetState extends State { requestVM.updateOfferDescription((widget.chatMessageModel.chatText ?? "").toString()); requestVM.updateIsDeliveryAvailableStatus((offer.isDeliveryAvailable ?? false)); + requestVM.applyFilterOnDeliveryOption(requestDeliveryOptionEnum: offer.requestDeliveryOption ?? RequestDeliveryOptionEnum.none); if (offer.reqOfferImages != null && offer.reqOfferImages!.isNotEmpty) { for (var element in offer.reqOfferImages!) { if (element.imageUrl != null || element.imageStr != null) { @@ -886,6 +896,27 @@ class _ChatMessageCustomWidgetState extends State { ); } + Widget buildDeliveryOptionsWidget({required RequestDeliveryOptionEnum deliveryOptionId}) { + Widget finalWidget = const SizedBox(); + + String finalText = ""; + if (deliveryOptionId == RequestDeliveryOptionEnum.none) { + finalText = RequestDeliveryOptionEnum.selfPickup.getStringFromRequestDeliveryOptionEnum(); + } else { + finalText = deliveryOptionId.getStringFromRequestDeliveryOptionEnum(); + } + + finalWidget = Directionality( + textDirection: TextDirection.ltr, + child: "${LocaleKeys.deliveryOptions.tr()} : $finalText".toText( + fontSize: 10, + color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor, + fontWeight: MyFonts.Medium, + ), + ); + return finalWidget; + } + Widget messageWidgetBasedOnType({required ChatMessageTypeEnum? chatMessageTypeEnum}) { Widget messageTypeWidget = const SizedBox(); if (chatMessageTypeEnum == null) { @@ -908,14 +939,7 @@ class _ChatMessageCustomWidgetState extends State { buildFreeTextDetailsInMessage(chatMessageTypeEnum: chatMessageTypeEnum), if (widget.requestsTypeEnum == RequestsTypeEnum.serviceRequest) ...[ 2.height, - Directionality( - textDirection: TextDirection.ltr, - child: "${LocaleKeys.deliveryAvailable.tr()} : ${(widget.chatMessageModel.reqOffer!.isDeliveryAvailable ?? false) ? LocaleKeys.yes.tr() : LocaleKeys.no.tr()}".toText( - fontSize: 10, - color: (widget.chatMessageModel.isMyMessage ?? false) ? MyColors.white : MyColors.lightTextColor, - fontWeight: MyFonts.Medium, - ), - ), + buildDeliveryOptionsWidget(deliveryOptionId: widget.chatMessageModel.reqOffer!.requestDeliveryOption ?? RequestDeliveryOptionEnum.none), ], if (widget.chatMessageModel.reqOffer!.reqOfferImages != null && widget.chatMessageModel.reqOffer!.reqOfferImages!.isNotEmpty) ...[ 5.height, diff --git a/lib/views/requests/providers_chat_list_page.dart b/lib/views/requests/providers_chat_list_page.dart index ec76d36..f215de0 100644 --- a/lib/views/requests/providers_chat_list_page.dart +++ b/lib/views/requests/providers_chat_list_page.dart @@ -8,6 +8,7 @@ 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/requests_models/offers_model.dart'; +import 'package:mc_common_app/models/requests_models/offers_unread_chat_model.dart'; import 'package:mc_common_app/models/requests_models/provider_offers_model.dart'; import 'package:mc_common_app/models/requests_models/providers_offers_chat_model.dart'; import 'package:mc_common_app/models/requests_models/request_model.dart'; @@ -39,7 +40,7 @@ class _ProvidersChatListPageState extends State { _onRefresh() async { scheduleMicrotask(() async { RequestsVM requestsVM = context.read(); - await requestsVM.getProviderOffersChatsList(serviceProviderId: AppState().getUser.data!.userInfo!.providerId ?? 0, context: context); + await requestsVM.getOffersChatsUnreadList(userId: AppState().getUser.data!.userInfo!.userId ?? "", context: context); }); } @@ -110,7 +111,7 @@ class _ProvidersChatListPageState extends State { }, child: requestsVM.state == ViewState.busy ? const Center(child: CircularProgressIndicator()) - : requestsVM.providerOffersChatsList.isEmpty + : requestsVM.offersUnreadChatModel == null || requestsVM.offersUnreadChatModel!.reqChatUnread.isEmpty ? Center( child: LocaleKeys.noOffersShow.tr().toText( fontSize: 16, @@ -118,58 +119,66 @@ class _ProvidersChatListPageState extends State { ), ) : ListView.separated( - itemCount: requestsVM.providerOffersChatsList.length, + itemCount: requestsVM.offersUnreadChatModel!.reqChatUnread.length, padding: const EdgeInsets.all(16), itemBuilder: (context, index) { - ProviderOffersChatsModel providerOffersChatsModel = requestsVM.providerOffersChatsList[index]; + OffersUnreadChatDataModel offersUnreadChatDataModel = requestsVM.offersUnreadChatModel!.reqChatUnread[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.statusContainerChip( - text: Utils.getNameByRequestOfferStatusEnum(providerOffersChatsModel.requestOfferStatusEnum!), - chipColor: Utils.getChipColorByRequestOfferStatusEnum(providerOffersChatsModel.requestOfferStatusEnum!), - ), + // Utils.statusContainerChip( + // text: Utils.getNameByRequestOfferStatusEnum(providerOffersChatsModel.requestOfferStatusEnum!), + // chipColor: Utils.getChipColorByRequestOfferStatusEnum(providerOffersChatsModel.requestOfferStatusEnum!), + // ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - (providerOffersChatsModel.customerName ?? "").toText( + (offersUnreadChatDataModel.customerName).toText( fontSize: 16, isBold: true, ), - if (providerOffersChatsModel.createdOn != null && providerOffersChatsModel.createdOn!.isNotEmpty) ...[ - DateTime.parse(providerOffersChatsModel.createdOn!).getTimeAgo().toText(color: MyColors.lightTextColor, fontSize: 14), + if (offersUnreadChatDataModel.unreadMessagesCount > 0) ...[ + Center( + child: "${offersUnreadChatDataModel.unreadMessagesCount}".toText( + color: Colors.white, + isBold: true, + fontSize: 10, + ), + ).toContainer( + backgroundColor: MyColors.cancelledColor, + borderRadius: 100, + paddingAll: 1, + width: 22, + height: 22, + ), ], - // if (providerOffersChatsModel. != null && offersModel.offerCount! > 0) ...[ - // Center( - // child: "${providerOffersChatsModel.offerCount}".toText( - // color: Colors.white, - // isBold: true, - // fontSize: 10, - // ), - // ).toContainer( - // backgroundColor: MyColors.cancelledColor, - // borderRadius: 100, - // paddingAll: 1, - // width: 22, - // height: 22, - // ), - // ], ], ), + 4.height, Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: "${providerOffersChatsModel.comment}".toText(color: MyColors.lightTextColor, fontSize: 14), + child: offersUnreadChatDataModel.lastChatText.toText(color: MyColors.lightTextColor, fontSize: 14), ), - const Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18), + 4.height, + if (offersUnreadChatDataModel.lastChatTime.isNotEmpty) ...[ + DateTime.parse(offersUnreadChatDataModel.lastChatTime).getTimeAgo().toText(color: MyColors.lightTextColor, fontSize: 12), + ], + ], + ), + 4.height, + const Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon(Icons.arrow_forward, color: MyColors.darkIconColor, size: 18), ], ), ], - ).onPress(() async => await onChatTapped(context: context, requestID: providerOffersChatsModel.requestID ?? 0)).toContainer(isShadowEnabled: true); + ).onPress(() async => await onChatTapped(context: context, requestID: offersUnreadChatDataModel.requestId ?? 0)).toContainer(isShadowEnabled: true); }, separatorBuilder: (context, index) => 16.height, ), diff --git a/lib/views/requests/request_bottomsheets.dart b/lib/views/requests/request_bottomsheets.dart index ab737c6..3f8a689 100644 --- a/lib/views/requests/request_bottomsheets.dart +++ b/lib/views/requests/request_bottomsheets.dart @@ -19,6 +19,7 @@ import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_ import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.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/filters_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'; @@ -96,7 +97,7 @@ Future buildSendOfferBottomSheet({ ], 12.height, TxtField( - maxLines: 5, + maxLines: 3, value: requestsVM.offerDescription, errorValue: requestsVM.offerDescriptionError, keyboardType: TextInputType.text, @@ -105,32 +106,49 @@ Future buildSendOfferBottomSheet({ ), 12.height, if (requestDetail.requestType == RequestsTypeEnum.serviceRequest.getIdFromRequestTypeEnum()) ...[ - LocaleKeys.deliveryAvailable.tr().toText(fontSize: 16), - 8.height, - Container( - width: 50, - height: 30, - decoration: BoxDecoration( - color: requestsVM.isDeliveryAvailableStatus ? MyColors.darkPrimaryColor : MyColors.white, - borderRadius: BorderRadius.circular(25.0), - border: Border.all(color: MyColors.black, width: 1), - ), - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - activeColor: MyColors.darkPrimaryColor, - trackColor: MyColors.white, - thumbColor: MyColors.grey98Color, - value: requestsVM.isDeliveryAvailableStatus, - onChanged: (value) { - requestsVM.updateIsDeliveryAvailableStatus(value); - }, - ), + LocaleKeys.selectDeliveryOption.tr().toText(fontSize: 16), + 10.height, + // Container( + // width: 50, + // height: 30, + // decoration: BoxDecoration( + // color: requestsVM.isDeliveryAvailableStatus ? MyColors.darkPrimaryColor : MyColors.white, + // borderRadius: BorderRadius.circular(25.0), + // border: Border.all(color: MyColors.black, width: 1), + // ), + // child: Transform.scale( + // scale: 0.8, + // child: CupertinoSwitch( + // activeTrackColor: MyColors.darkPrimaryColor, + // inactiveTrackColor: MyColors.white, + // thumbColor: MyColors.grey98Color, + // value: requestsVM.isDeliveryAvailableStatus, + // onChanged: (value) { + // requestsVM.updateIsDeliveryAvailableStatus(value); + // }, + // ), + // ), + // ), + + FiltersList( + filterList: requestsVM.myDeliveryOptionsFilterOptions, + onFilterTapped: (index, selectedFilterId) { + requestsVM.applyFilterOnDeliveryOption(requestDeliveryOptionEnum: selectedFilterId.toRequestDeliveryOptionEnum()); + }, + needLeftPadding: false, + ).paddingOnly(bottom: 21), + + if (requestsVM.deliveryOptionSelectionError.isNotEmpty) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + requestsVM.deliveryOptionSelectionError.toText(), + ], ), - ), + ] ], - 12.height, if (requestsVM.pickedVehicleImages.isEmpty) ...[ + 5.height, DottedRectContainer( onTap: () => context.read().pickMultipleImages(), text: LocaleKeys.attachImage.tr(), @@ -139,7 +157,7 @@ Future buildSendOfferBottomSheet({ ), ], if (requestsVM.pickedVehicleImages.isNotEmpty) ...[ - 16.height, + // 14.height, PickedFilesContainer( pickedFiles: requestsVM.pickedVehicleImages, onCrossPressedPrimary: requestsVM.removeImageFromList, @@ -159,6 +177,12 @@ Future buildSendOfferBottomSheet({ "${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName}", ); requestsVM.updateServiceItemCreatedOn(DateHelper.formatAsYearMonthDay(DateTime.now())); + + RequestDeliveryOptionEnum requestDeliveryOptionEnum = RequestDeliveryOptionEnum.none; + int index = requestsVM.myDeliveryOptionsFilterOptions.indexWhere((option) => option.isSelected); + if (index != -1) { + requestDeliveryOptionEnum = requestsVM.myDeliveryOptionsFilterOptions[index].id.toRequestDeliveryOptionEnum(); + } if (offerId == null) { requestsVM.onSendOfferPressed( context: context, @@ -169,6 +193,7 @@ Future buildSendOfferBottomSheet({ offerPrice: requestsVM.offerPrice, requestModel: requestDetail, isDeliveryAvailable: requestsVM.isDeliveryAvailableStatus, + offerDeliveryOption: requestDeliveryOptionEnum, requestIndex: requestDetailPageArguments.requestIndex, isFromChatScreen: isFromChatScreen, manufacturedByName: requestsVM.itemManufacturer, @@ -182,6 +207,7 @@ Future buildSendOfferBottomSheet({ offerId: offerId, offerPrice: requestsVM.offerPrice, isDeliveryAvailable: requestsVM.isDeliveryAvailableStatus, + offerDeliveryOption: requestDeliveryOptionEnum, serviceItemName: requestsVM.serviceItem, manufacturedByName: requestsVM.itemManufacturer, manufacturedOn: requestsVM.serviceItemCreatedOn, diff --git a/lib/views/requests/request_detail_page.dart b/lib/views/requests/request_detail_page.dart index eaa4d7e..942bc69 100644 --- a/lib/views/requests/request_detail_page.dart +++ b/lib/views/requests/request_detail_page.dart @@ -26,6 +26,107 @@ class RequestDetailPage extends StatelessWidget { const RequestDetailPage({super.key, required this.requestDetailPageArguments}); + Widget buildRequestDetailsContainer(BuildContext context) { + final requestDetail = requestDetailPageArguments.requestModel; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + requestDetail.vehicleTypeName.toText(fontSize: 16, letterSpacing: -0.64), + showItem("${LocaleKeys.brand.tr()}: ", requestDetail.brand), + showItem("${LocaleKeys.model.tr()}: ", requestDetail.model), + showItem("${LocaleKeys.year.tr()}: ", "${requestDetail.year}"), + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "${requestDetail.city ?? ""} ${requestDetail.countryName}".toText( + color: MyColors.lightTextColor, + ), + if (requestDetail.createdOn != null) ...[ + DateTime.parse(requestDetail.createdOn!).getTimeAgo().toText( + color: MyColors.lightTextColor, + ), + ], + ], + ), + ], + ), + if (requestDetail.customerName.isNotEmpty) ...[ + showItem("${LocaleKeys.customerName.tr()}: ", requestDetail.customerName), + ], + showItem("${LocaleKeys.description.tr()}: ", requestDetail.description), + 16.height, + + if (AppState().currentAppType == AppType.provider && + (requestDetailPageArguments.requestModel.requestStatus == RequestStatusEnum.inProgress || requestDetailPageArguments.requestModel.requestStatus == RequestStatusEnum.submitted)) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ("${LocaleKeys.reportComplaint.tr()}?").toText(fontSize: 14, color: MyColors.darkTextColor), + ], + ).onPress( + () { + int customerID = requestDetailPageArguments.requestModel.customerId; + int complainType = 2; + String customerName = requestDetailPageArguments.requestModel.customerName; + + context.read().buildComplaintBottomSheet( + customerID: customerID, + customerName: customerName, + complainType: complainType, + context: context, + ); + }, + ), + ], + + // showItem("${LocaleKeys.priceRange.tr()}:", ""), + // Row( + // children: [ + // Expanded( + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.end, + // children: [ + // Row( + // crossAxisAlignment: CrossAxisAlignment.end, + // children: [ + // "${requestDetail.price.toInt()}".toText(fontSize: 19, isBold: true, letterSpacing: -1.16), + // 2.width, + // LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4), + // ], + // ), + // Row( + // children: [ + // Utils.statusContainerChip( + // text: (requestDetail.requestStatusName), + // chipColor: MyColors.grey98Color.withOpacity(0.1), + // textColor: MyColors.lightTextColor, + // ), + // ], + // ), + // ], + // ), + // ), + // // const Icon(Icons.arrow_forward) + // ], + // ), + ], + ); + } + Widget buildRequestDetailActionFooter({ required int requestId, required RequestStatusEnum requestStatus, @@ -209,107 +310,6 @@ class RequestDetailPage extends StatelessWidget { ); } - Widget buildRequestDetailsContainer(BuildContext context) { - final requestDetail = requestDetailPageArguments.requestModel; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - requestDetail.vehicleTypeName.toText(fontSize: 16, letterSpacing: -0.64), - showItem("${LocaleKeys.brand.tr()}: ", requestDetail.brand), - showItem("${LocaleKeys.model.tr()}: ", requestDetail.model), - showItem("${LocaleKeys.year.tr()}: ", "${requestDetail.year}"), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "${requestDetail.city ?? ""} ${requestDetail.countryName}".toText( - color: MyColors.lightTextColor, - ), - if (requestDetail.createdOn != null) ...[ - DateTime.parse(requestDetail.createdOn!).getTimeAgo().toText( - color: MyColors.lightTextColor, - ), - ], - ], - ), - ], - ), - if (requestDetail.customerName.isNotEmpty) ...[ - showItem("${LocaleKeys.customerName.tr()}: ", requestDetail.customerName), - ], - showItem("${LocaleKeys.description.tr()}: ", requestDetail.description), - 16.height, - - if (AppState().currentAppType == AppType.provider && - (requestDetailPageArguments.requestModel.requestStatus == RequestStatusEnum.inProgress || requestDetailPageArguments.requestModel.requestStatus == RequestStatusEnum.submitted)) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - ("${LocaleKeys.reportComplaint.tr()}?").toText(fontSize: 14, color: MyColors.darkTextColor), - ], - ).onPress( - () { - int customerID = requestDetailPageArguments.requestModel.customerId; - int complainType = 2; - String customerName = requestDetailPageArguments.requestModel.customerName; - - context.read().buildComplaintBottomSheet( - customerID: customerID, - customerName: customerName, - complainType: complainType, - context: context, - ); - }, - ), - ], - - // showItem("${LocaleKeys.priceRange.tr()}:", ""), - // Row( - // children: [ - // Expanded( - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // crossAxisAlignment: CrossAxisAlignment.end, - // children: [ - // Row( - // crossAxisAlignment: CrossAxisAlignment.end, - // children: [ - // "${requestDetail.price.toInt()}".toText(fontSize: 19, isBold: true, letterSpacing: -1.16), - // 2.width, - // LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4), - // ], - // ), - // Row( - // children: [ - // Utils.statusContainerChip( - // text: (requestDetail.requestStatusName), - // chipColor: MyColors.grey98Color.withOpacity(0.1), - // textColor: MyColors.lightTextColor, - // ), - // ], - // ), - // ], - // ), - // ), - // // const Icon(Icons.arrow_forward) - // ], - // ), - ], - ); - } - Widget showItem(String title, String value) { return Row( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/views/requests/review_request_offer.dart b/lib/views/requests/review_request_offer.dart index ac250e9..a2b9cf8 100644 --- a/lib/views/requests/review_request_offer.dart +++ b/lib/views/requests/review_request_offer.dart @@ -90,7 +90,12 @@ class _ReviewRequestOfferState extends State { Widget buildLocationInformation(BuildContext context) { final requestVM = context.watch(); - + String address = ""; + if (requestVM.acceptedRequestOffer != null && requestVM.acceptedRequestOffer!.requestDeliveryOption == RequestDeliveryOptionEnum.delivery) { + address = requestVM.currentSelectedRequest!.address; + } else { + address = requestVM.currentSelectedOffer!.providerAddress ?? ""; + } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -107,7 +112,11 @@ class _ReviewRequestOfferState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SingleDetailWidget(text: requestVM.currentSelectedRequest!.address ?? "", type: LocaleKeys.location.tr()), + Row( + children: [ + SingleDetailWidget(text: address, type: LocaleKeys.location.tr()), + ], + ), // 16.height, // SingleDetailWidget( // text: requestVM.additionalAddressSparePartRequestDelivery.isNotEmpty ? requestVM.additionalAddressSparePartRequestDelivery : "N/A", @@ -161,8 +170,9 @@ class _ReviewRequestOfferState extends State { // SingleDetailWidget(text: "${requestVM.acceptedRequestOffer!.price.toString()} ${LocaleKeys.sar.tr()}", type: LocaleKeys.offerPrice.tr()), 16.height, SingleDetailWidget(text: requestVM.acceptedRequestOfferProviderName ?? "", type: LocaleKeys.providerName.tr()), + 16.height, - SingleDetailWidget(text: requestVM.currentSelectedRequest!.description, type: LocaleKeys.description.tr()), + SingleDetailWidget(text: LocaleKeys.online.tr(), type: LocaleKeys.paymentType.tr()), ], ), ), @@ -180,21 +190,18 @@ class _ReviewRequestOfferState extends State { SingleDetailWidget(text: manufacturedOnFormattedDate, type: LocaleKeys.manufacturedOn.tr()), ], 16.height, - // SingleDetailWidget(text: "${requestVM.currentSelectedRequest!.price.toString()} ${LocaleKeys.sar.tr()}", type: LocaleKeys.totalPrice.tr()), SingleDetailWidget(text: "${requestVM.acceptedRequestOffer!.price.toString()} ${LocaleKeys.sar.tr()}", type: LocaleKeys.offerPrice.tr()), - if (requestCreatedOn.isNotEmpty) ...[ 16.height, SingleDetailWidget(text: requestCreatedOn, type: LocaleKeys.requestCreatedOn.tr()), ], - - 16.height, - SingleDetailWidget(text: LocaleKeys.online.tr(), type: LocaleKeys.paymentType.tr()), ], ), ), ], ), + 16.height, + SingleDetailWidget(text: requestVM.currentSelectedRequest!.description, type: LocaleKeys.description.tr()), ], ); } diff --git a/lib/views/setting_options/setting_options_more.dart b/lib/views/setting_options/setting_options_more.dart index 5c1ec77..8d17728 100644 --- a/lib/views/setting_options/setting_options_more.dart +++ b/lib/views/setting_options/setting_options_more.dart @@ -108,7 +108,9 @@ class _SettingOptionsMoreState extends State { onTap: () { navigateWithName(context, AppRoutes.shippingManagementView); }, - ), + ).toViewOnly(context, onTap: () { + navigateWithName(context, AppRoutes.loginWithPassword, arguments: false); + }), ], CustomSettingOptionsTile( leadingWidget: const Icon(Icons.settings, size: 20), diff --git a/lib/views/shipping_management/shipping_management_view.dart b/lib/views/shipping_management/shipping_management_view.dart index 209c783..f2b15e0 100644 --- a/lib/views/shipping_management/shipping_management_view.dart +++ b/lib/views/shipping_management/shipping_management_view.dart @@ -1,7 +1,9 @@ import 'dart:async'; import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/routes.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'; @@ -39,7 +41,14 @@ class _ShippingManagementViewState extends State { if (shippingViewModel.shippingRequestFilterOptions.isNotEmpty) { await shippingViewModel.populateShippingRequestFilterList(); } - await shippingViewModel.getShippingRequestsListByFilters(); + if (shippingViewModel.selfPickupRequestsFilterOptions.isNotEmpty) { + await shippingViewModel.populateSelfPickupRequestFilterList(); + } + if (shippingViewModel.isSelfPickupTapped) { + await shippingViewModel.getSelfPickupRequestsListByFilters(); + } else { + await shippingViewModel.getShippingRequestsListByFilters(); + } }); super.initState(); } @@ -146,27 +155,78 @@ class _ShippingManagementViewState extends State { 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, + appBar: CustomAppBar(title: LocaleKeys.shippingManagement.tr()), + body: Container( + color: MyColors.backgroundColor, + width: double.infinity, + height: double.infinity, + child: Column( + children: [ + 16.height, + Row( + children: [ + Expanded( + child: ShowFillButton( + isFilled: !shippingVm.isSelfPickupTapped, + maxHeight: 55, + fontSize: 15, + title: LocaleKeys.delivery.tr(), + txtColor: !shippingVm.isSelfPickupTapped ? MyColors.white : MyColors.darkTextColor, + onPressed: () async { + shippingVm.updateIsSelfPickupTapped(false); + int index = shippingVm.shippingRequestFilterOptions.indexWhere((element) => element.isSelected); + int id = shippingVm.shippingRequestFilterOptions[index].id; + await shippingVm.getShippingRequestsListByFilters(shippingStatusEnum: id.toShippingStatusEnum()); + }, + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + isFilled: shippingVm.isSelfPickupTapped, + txtColor: shippingVm.isSelfPickupTapped ? MyColors.white : MyColors.darkTextColor, + maxHeight: 55, + fontSize: 15, + title: LocaleKeys.selfPickup.tr(), + onPressed: () async { + shippingVm.updateIsSelfPickupTapped(true); + int index = shippingVm.selfPickupRequestsFilterOptions.indexWhere((element) => element.isSelected); + int id = shippingVm.selfPickupRequestsFilterOptions[index].id; + await shippingVm.getSelfPickupRequestsListByFilters(selfPickupStatusEnum: id.toSelfPickupStatusEnum()); + }, + ), + ), + ], + ).horPaddingMain(), + 16.height, + if (shippingVm.isSelfPickupTapped) ...[ + FiltersList( + filterList: shippingVm.selfPickupRequestsFilterOptions, + onFilterTapped: (index, selectedFilterId) { + shippingVm.applyFiltersOnSelfPickupRequests(selfPickupRequestStatusEnum: selectedFilterId.toSelfPickupStatusEnum()); + }, + ), + ] else ...[ FiltersList( filterList: shippingVm.shippingRequestFilterOptions, onFilterTapped: (index, selectedFilterId) { shippingVm.applyFiltersOnShippingRequests(shippingRequestStatusEnum: selectedFilterId.toShippingStatusEnum()); }, ), - 8.height, - Expanded( - child: RefreshIndicator( + ], + 8.height, + Expanded( + child: RefreshIndicator( onRefresh: () async { - int index = shippingVm.shippingRequestFilterOptions.indexWhere((element) => element.isSelected); - int id = shippingVm.shippingRequestFilterOptions[index].id; - await shippingVm.getShippingRequestsListByFilters(shippingStatusEnum: id.toShippingStatusEnum()); + if (shippingVm.isSelfPickupTapped) { + int index = shippingVm.selfPickupRequestsFilterOptions.indexWhere((element) => element.isSelected); + int id = shippingVm.selfPickupRequestsFilterOptions[index].id; + await shippingVm.getSelfPickupRequestsListByFilters(selfPickupStatusEnum: id.toSelfPickupStatusEnum()); + } else { + int index = shippingVm.shippingRequestFilterOptions.indexWhere((element) => element.isSelected); + int id = shippingVm.shippingRequestFilterOptions[index].id; + await shippingVm.getShippingRequestsListByFilters(shippingStatusEnum: id.toShippingStatusEnum()); + } }, child: (shippingVm.state == ViewState.busy) ? const Center(child: CircularProgressIndicator()) @@ -220,10 +280,12 @@ class _ShippingManagementViewState extends State { }, separatorBuilder: (context, index) => 16.height, ), - )), - ], - ), - )); + ), + ), + ], + ), + ), + ); }); } } diff --git a/lib/widgets/txt_field.dart b/lib/widgets/txt_field.dart index 8781a4c..eddbc98 100644 --- a/lib/widgets/txt_field.dart +++ b/lib/widgets/txt_field.dart @@ -36,6 +36,7 @@ class TxtField extends StatelessWidget { Widget? preFixWidget; bool numbersOnly; bool allowOnlyOneDigit; + bool isNeedLabelOnTop; TxtField({ super.key, @@ -66,6 +67,7 @@ class TxtField extends StatelessWidget { this.onPostFixPressed, this.numbersOnly = false, this.allowOnlyOneDigit = false, + this.isNeedLabelOnTop = true, }); TextEditingController controller = TextEditingController(); @@ -77,7 +79,7 @@ class TxtField extends StatelessWidget { return Column( children: [ - if (hint != null) ...[ + if (isNeedLabelOnTop && hint != null) ...[ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -149,7 +151,7 @@ class TxtField extends StatelessWidget { prefixIcon: prefixData != null ? Icon(prefixData, color: borderColor) : preFixWidget, labelStyle: const TextStyle(color: borderColor, fontSize: 13, fontWeight: MyFonts.Medium), hintStyle: const TextStyle(color: borderColor, fontSize: 13, fontWeight: MyFonts.Medium), - // hintText: hint ?? "", + hintText: isNeedLabelOnTop ? null : hint ?? "", contentPadding: prefixData == null ? EdgeInsets.only( left: 12,