Request Module Completed

master_new_changes
Faiz Hashmi 1 year ago
parent 55363e4e9f
commit f290f2e04f

@ -594,7 +594,41 @@
"reserved": "محجوز", "reserved": "محجوز",
"delete": "يمسح", "delete": "يمسح",
"deleteBranchConfirmation": "هل تريد حذف الفرع؟", "deleteBranchConfirmation": "هل تريد حذف الفرع؟",
"deleteBranchConfirmationMessage": "سيتم حذف فرعك بشكل دائم ولن تتمكن من التراجع عن هذا الإجراء" "deleteBranchConfirmationMessage": "سيتم حذف فرعك بشكل دائم ولن تتمكن من التراجع عن هذا الإجراء",
"reviewAndPayment": "المراجعة والدفع",
"awaitingPaymentFromCustomer": "في انتظار الدفع من العميل",
"awaitingResponseFromProvider": "في انتظار الرد من المزود",
"offerNoLongerAvailable": "العرض لم يعد متاحاً",
"doYouWantToCompleteThisDeal": "هل تريد إكمال هذه الصفقة؟",
"customerCompletingDealMeansThat": "إكمال هذه الصفقة يعني أن الطلب الذي قمت بنشره قد تم استلامه بنجاح ولا يمكن التراجع عن هذا الإجراء.",
"providerCompletingDealMeansThat": "إكمال هذه الصفقة يعني أنك قد قدمت الخدمة للعميل بنجاح وفقاً لطلبه ولا يمكن التراجع عن هذا الإجراء.",
"offerSummary": "ملخص العرض",
"personalInformation": "المعلومات الشخصية",
"name": "الاسم",
"phone": "الهاتف",
"serviceInformation": "معلومات الخدمة",
"locationInformation": "معلومات الموقع",
"additionalAddressDetails": "تفاصيل العنوان الإضافية",
"serviceName": "اسم الخدمة",
"serviceCategory": "فئة الخدمة",
"offerPrice": "سعر العرض",
"totalPrice": "السعر الإجمالي",
"providerName": "اسم المزود",
"createdOn": "تم الإنشاء في",
"manufacturedBy": "صُنع بواسطة",
"manufacturedOn": "تاريخ الصنع",
"shipping": "الشحن",
"delivery": "التسليم",
"selectDeliveryType": "اختر نوع التسليم",
"shippingManagementInstruction": "يرجى الذهاب إلى الإعدادات > شاشة إدارة الشحن لإدارة عناصر الشحن/التسليم بشكل أكبر.",
"withdrawOffer": "سحب العرض",
"manufacturer": "الصانع",
"priceRange": "نطاق السعر",
"cancelOffer": "إلغاء العرض",
"pleaseSpecify": "يرجى التحديد",
"customerNotResponding": "العميل غير متجاوب",
"cancelRequestPrompt": "هل تريد إلغاء هذا الطلب؟",
"requestPermanentlyCancelled": "سيتم إلغاء طلبك بشكل نهائي. لا يمكنك التراجع عن هذا الإجراء.",
"awaitingResponseFromCustomer": "في انتظار الرد من العميل",
"acknowledgePaymentToMowater": "أقر بأنه عند إكمال هذه الصفقة، سأدفع 2٪ من إجمالي هذه الصفقة لشركة مواتر مقابل خدماتهم."
} }

@ -595,5 +595,41 @@
"reserved": "Reserved", "reserved": "Reserved",
"delete": "Delete", "delete": "Delete",
"deleteBranchConfirmation": "Do you want to delete the Branch?", "deleteBranchConfirmation": "Do you want to delete the Branch?",
"deleteBranchConfirmationMessage": "Your branch will be permanently deleted and you cannot undo this action" "deleteBranchConfirmationMessage": "Your branch will be permanently deleted and you cannot undo this action",
"reviewAndPayment": "Review & Payment",
"awaitingPaymentFromCustomer": "Awaiting Payment from Customer",
"awaitingResponseFromProvider": "Awaiting Response From Provider",
"offerNoLongerAvailable": "Offer is No Longer Available",
"doYouWantToCompleteThisDeal": "Do you want to complete this deal?",
"customerCompletingDealMeansThat": "Completing this deal means that the you request that you have posted has been successfully received and this action cannot be undone.",
"providerCompletingDealMeansThat": "Completing this deal means that you have successfully provided the customer according to his request and this action cannot be undone.",
"offerSummary": "Offer Summary",
"personalInformation": "Personal Information",
"name": "Name",
"phone": "Phone",
"locationInformation": "Location Information",
"serviceInformation": "Service Information",
"additionalAddressDetails": "Additional Address Details",
"serviceName": "Service Name",
"serviceCategory": "Service Category",
"offerPrice": "Offer Price",
"totalPrice": "Total Price",
"providerName": "Provider Name",
"createdOn": "Created On",
"manufacturedBy": "Manufactured By",
"manufacturedOn": "Manufactured On",
"shipping": "Shipping",
"delivery": "Delivery",
"selectDeliveryType": "Select Delivery Type",
"shippingManagementInstruction": "Please go to Settings > Shipping Management screen to manage shipping/delivery items further.",
"withdrawOffer": "Withdraw Offer",
"manufacturer": "Manufacturer",
"priceRange": "Price Range",
"cancelOffer": "Cancel Offer",
"pleaseSpecify": "Please Specify",
"customerNotResponding": "Customer Not Responding",
"cancelRequestPrompt": "Do you want to cancel this request?",
"requestPermanentlyCancelled": "Your request will be permanently cancelled. You cannot undo this action.",
"awaitingResponseFromCustomer": "Awaiting Response From Customer",
"acknowledgePaymentToMowater": "I acknowledge that upon completion of this deal, I will pay 2% of this total deal to the Mowater company for their service."
} }

@ -157,6 +157,8 @@ class ApiConsts {
static String getRequest = "${baseUrlServices}api/RequestManagement/Request_Get"; static String getRequest = "${baseUrlServices}api/RequestManagement/Request_Get";
static String getRequestOffers = "${baseUrlServices}api/RequestManagement/ReqOffer_Get"; static String getRequestOffers = "${baseUrlServices}api/RequestManagement/ReqOffer_Get";
static String updateRequestOffer = "${baseUrlServices}api/RequestManagement/RequestOffer_UpdateStatus"; static String updateRequestOffer = "${baseUrlServices}api/RequestManagement/RequestOffer_UpdateStatus";
static String updateRequestCustomer = "${baseUrlServices}api/RequestManagement/Request_StatusUpdate_Customer";
static String updateRequestProvider = "${baseUrlServices}api/RequestManagement/Request_StatusUpdate_Provider";
static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get"; static String requestOffersSpsGet = "${baseUrlServices}api/RequestManagement/Request_OfferSPs_Get";
static String getServiceRequestsForProvider = "${baseUrlServices}api/RequestManagement/Request_ServiceProvider"; static String getServiceRequestsForProvider = "${baseUrlServices}api/RequestManagement/Request_ServiceProvider";
@ -321,8 +323,6 @@ class MyFonts {
static const FontWeight ItalicBold = FontWeight.w700; static const FontWeight ItalicBold = FontWeight.w700;
static const FontWeight ItalicExtraBold = FontWeight.w800; static const FontWeight ItalicExtraBold = FontWeight.w800;
static const FontWeight ItalicBlack = FontWeight.w900; static const FontWeight ItalicBlack = FontWeight.w900;
} }
class SignalrConsts { class SignalrConsts {

@ -15,6 +15,7 @@ import 'package:mc_common_app/views/profile/profile_view.dart';
import 'package:mc_common_app/views/requests/create_request_page.dart'; import 'package:mc_common_app/views/requests/create_request_page.dart';
import 'package:mc_common_app/views/requests/offer_list_page.dart'; import 'package:mc_common_app/views/requests/offer_list_page.dart';
import 'package:mc_common_app/views/requests/request_detail_page.dart'; import 'package:mc_common_app/views/requests/request_detail_page.dart';
import 'package:mc_common_app/views/requests/review_request_offer.dart';
import 'package:mc_common_app/views/setting_options/provider_license_page.dart'; import 'package:mc_common_app/views/setting_options/provider_license_page.dart';
import 'package:mc_common_app/views/setting_options/setting_option_help.dart'; 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_faqs.dart';
@ -99,6 +100,7 @@ class AppRoutes {
static const String offersListPage = "/offersListPage"; static const String offersListPage = "/offersListPage";
static const String requestsDetailPage = "/requestsDetailPage"; static const String requestsDetailPage = "/requestsDetailPage";
static const String sendOfferPage = "/sendOfferPage"; static const String sendOfferPage = "/sendOfferPage";
static const String reviewRequestOffer = "/reviewRequestOffer";
//Setting Options //Setting Options
static const String settingOptionsFaqs = "/settingOptionsFaqs"; static const String settingOptionsFaqs = "/settingOptionsFaqs";
@ -157,9 +159,7 @@ class AppRoutes {
AppRoutes.requestsDetailPage: (context) => RequestDetailPage(requestDetailPageArguments: ModalRoute.of(context)!.settings.arguments as RequestDetailPageArguments), AppRoutes.requestsDetailPage: (context) => RequestDetailPage(requestDetailPageArguments: ModalRoute.of(context)!.settings.arguments as RequestDetailPageArguments),
AppRoutes.createRequestPage: (context) => const CreateRequestPage(), AppRoutes.createRequestPage: (context) => const CreateRequestPage(),
AppRoutes.offersListPage: (context) => OfferListPage(offerListPageArguments: ModalRoute.of(context)!.settings.arguments as OfferListPageArguments), AppRoutes.offersListPage: (context) => OfferListPage(offerListPageArguments: ModalRoute.of(context)!.settings.arguments as OfferListPageArguments),
AppRoutes.reviewRequestOffer: (context) => const ReviewRequestOffer(),
}; };
} }

@ -25,7 +25,7 @@ extension EmailValidator on String {
int? maxLines}) { int? maxLines}) {
bool isArabic = AppState().postParamsObject!.languageID == 1; // arabic -> 1 , English -> 2 bool isArabic = AppState().postParamsObject!.languageID == 1; // arabic -> 1 , English -> 2
return AutoSizeText( return AutoSizeText(
isUpperCase ? this.toUpperCase() : this, isUpperCase ? toUpperCase() : this,
textAlign: textAlign, textAlign: textAlign,
maxLines: maxLines, maxLines: maxLines,
style: TextStyle( style: TextStyle(
@ -163,23 +163,53 @@ extension FormatDate on String {
} }
extension RequestEnum on int { extension RequestEnum on int {
RequestStatus toRequestStatusEnum() { RequestStatusEnum toRequestStatusEnum() {
if (this == 1) { if (this == 1) {
return RequestStatus.submitted; return RequestStatusEnum.submitted;
} else if (this == 2) { } else if (this == 2) {
return RequestStatus.inProgress; return RequestStatusEnum.inProgress;
} else if (this == 3) { } else if (this == 3) {
return RequestStatus.completed; return RequestStatusEnum.completed;
} else if (this == 4) { } else if (this == 4) {
return RequestStatus.cancelled; return RequestStatusEnum.cancelled;
} else if (this == 5) { } else if (this == 5) {
return RequestStatus.paid; return RequestStatusEnum.paid;
} else if (this == 6) { } else if (this == 6) {
return RequestStatus.expired; return RequestStatusEnum.expired;
} else if (this == 7) { } else if (this == 7) {
return RequestStatus.shipping; return RequestStatusEnum.shipping;
} else if (this == 8) {
return RequestStatusEnum.delivery;
} else { } else {
return RequestStatus.pending; return RequestStatusEnum.pending;
}
}
}
extension RequestStatusEnumToInt on RequestStatusEnum {
int getIdFromRequestStatusEnum() {
switch (this) {
case RequestStatusEnum.submitted:
return 1;
case RequestStatusEnum.inProgress:
return 2;
case RequestStatusEnum.completed:
return 3;
case RequestStatusEnum.cancelled:
return 4;
case RequestStatusEnum.paid:
return 5;
case RequestStatusEnum.expired:
return 6;
case RequestStatusEnum.shipping:
return 7;
case RequestStatusEnum.delivery:
return 8;
case RequestStatusEnum.pending:
return 0;
default:
return 0;
} }
} }
} }
@ -353,7 +383,7 @@ extension AppointmentPaymentEnum on int {
} }
} }
extension RequestTypeTypeEnum on int { extension RequestTypeTypEnum on int {
RequestsTypeEnum toRequestTypeStatusEnum() { RequestsTypeEnum toRequestTypeStatusEnum() {
if (this == 1) { if (this == 1) {
return RequestsTypeEnum.specialCarRequest; return RequestsTypeEnum.specialCarRequest;

@ -610,7 +610,43 @@ class CodegenLoader extends AssetLoader{
"reserved": "محجوز", "reserved": "محجوز",
"delete": "يمسح", "delete": "يمسح",
"deleteBranchConfirmation": "هل تريد حذف الفرع؟", "deleteBranchConfirmation": "هل تريد حذف الفرع؟",
"deleteBranchConfirmationMessage": "سيتم حذف فرعك بشكل دائم ولن تتمكن من التراجع عن هذا الإجراء" "deleteBranchConfirmationMessage": "سيتم حذف فرعك بشكل دائم ولن تتمكن من التراجع عن هذا الإجراء",
"reviewAndPayment": "المراجعة والدفع",
"awaitingPaymentFromCustomer": "في انتظار الدفع من العميل",
"awaitingResponseFromProvider": "في انتظار الرد من المزود",
"offerNoLongerAvailable": "العرض لم يعد متاحاً",
"doYouWantToCompleteThisDeal": "هل تريد إكمال هذه الصفقة؟",
"customerCompletingDealMeansThat": "إكمال هذه الصفقة يعني أن الطلب الذي قمت بنشره قد تم استلامه بنجاح ولا يمكن التراجع عن هذا الإجراء.",
"providerCompletingDealMeansThat": "إكمال هذه الصفقة يعني أنك قد قدمت الخدمة للعميل بنجاح وفقاً لطلبه ولا يمكن التراجع عن هذا الإجراء.",
"offerSummary": "ملخص العرض",
"personalInformation": "المعلومات الشخصية",
"name": "الاسم",
"phone": "الهاتف",
"serviceInformation": "معلومات الخدمة",
"locationInformation": "معلومات الموقع",
"additionalAddressDetails": "تفاصيل العنوان الإضافية",
"serviceName": "اسم الخدمة",
"serviceCategory": "فئة الخدمة",
"offerPrice": "سعر العرض",
"totalPrice": "السعر الإجمالي",
"providerName": "اسم المزود",
"createdOn": "تم الإنشاء في",
"manufacturedBy": "صُنع بواسطة",
"manufacturedOn": "تاريخ الصنع",
"shipping": "الشحن",
"delivery": "التسليم",
"selectDeliveryType": "اختر نوع التسليم",
"shippingManagementInstruction": "يرجى الذهاب إلى الإعدادات > شاشة إدارة الشحن لإدارة عناصر الشحن/التسليم بشكل أكبر.",
"withdrawOffer": "سحب العرض",
"manufacturer": "الصانع",
"priceRange": "نطاق السعر",
"cancelOffer": "إلغاء العرض",
"pleaseSpecify": "يرجى التحديد",
"customerNotResponding": "العميل غير متجاوب",
"cancelRequestPrompt": "هل تريد إلغاء هذا الطلب؟",
"requestPermanentlyCancelled": "سيتم إلغاء طلبك بشكل نهائي. لا يمكنك التراجع عن هذا الإجراء.",
"awaitingResponseFromCustomer": "في انتظار الرد من العميل",
"acknowledgePaymentToMowater": "أقر بأنه عند إكمال هذه الصفقة، سأدفع 2٪ من إجمالي هذه الصفقة لشركة مواتر مقابل خدماتهم."
}; };
static const Map<String,dynamic> en_US = { static const Map<String,dynamic> en_US = {
"firstTimeLogIn": "First Time Log In", "firstTimeLogIn": "First Time Log In",
@ -1209,7 +1245,43 @@ static const Map<String,dynamic> en_US = {
"reserved": "Reserved", "reserved": "Reserved",
"delete": "Delete", "delete": "Delete",
"deleteBranchConfirmation": "Do you want to delete the Branch?", "deleteBranchConfirmation": "Do you want to delete the Branch?",
"deleteBranchConfirmationMessage": "Your branch will be permanently deleted and you cannot undo this action" "deleteBranchConfirmationMessage": "Your branch will be permanently deleted and you cannot undo this action",
"reviewAndPayment": "Review & Payment",
"awaitingPaymentFromCustomer": "Awaiting Payment from Customer",
"awaitingResponseFromProvider": "Awaiting Response From Provider",
"offerNoLongerAvailable": "Offer is No Longer Available",
"doYouWantToCompleteThisDeal": "Do you want to complete this deal?",
"customerCompletingDealMeansThat": "Completing this deal means that the you request that you have posted has been successfully received and this action cannot be undone.",
"providerCompletingDealMeansThat": "Completing this deal means that you have successfully provided the customer according to his request and this action cannot be undone.",
"offerSummary": "Offer Summary",
"personalInformation": "Personal Information",
"name": "Name",
"phone": "Phone",
"locationInformation": "Location Information",
"serviceInformation": "Service Information",
"additionalAddressDetails": "Additional Address Details",
"serviceName": "Service Name",
"serviceCategory": "Service Category",
"offerPrice": "Offer Price",
"totalPrice": "Total Price",
"providerName": "Provider Name",
"createdOn": "Created On",
"manufacturedBy": "Manufactured By",
"manufacturedOn": "Manufactured On",
"shipping": "Shipping",
"delivery": "Delivery",
"selectDeliveryType": "Select Delivery Type",
"shippingManagementInstruction": "Please go to Settings > Shipping Management screen to manage shipping/delivery items further.",
"withdrawOffer": "Withdraw Offer",
"manufacturer": "Manufacturer",
"priceRange": "Price Range",
"cancelOffer": "Cancel Offer",
"pleaseSpecify": "Please Specify",
"customerNotResponding": "Customer Not Responding",
"cancelRequestPrompt": "Do you want to cancel this request?",
"requestPermanentlyCancelled": "Your request will be permanently cancelled. You cannot undo this action.",
"awaitingResponseFromCustomer": "Awaiting Response From Customer",
"acknowledgePaymentToMowater": "I acknowledge that upon completion of this deal, I will pay 2% of this total deal to the Mowater company for their service."
}; };
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": ar_SA, "en_US": en_US};
} }

@ -574,5 +574,41 @@ abstract class LocaleKeys {
static const delete = 'delete'; static const delete = 'delete';
static const deleteBranchConfirmation = 'deleteBranchConfirmation'; static const deleteBranchConfirmation = 'deleteBranchConfirmation';
static const deleteBranchConfirmationMessage = 'deleteBranchConfirmationMessage'; static const deleteBranchConfirmationMessage = 'deleteBranchConfirmationMessage';
static const reviewAndPayment = 'reviewAndPayment';
static const awaitingPaymentFromCustomer = 'awaitingPaymentFromCustomer';
static const awaitingResponseFromProvider = 'awaitingResponseFromProvider';
static const offerNoLongerAvailable = 'offerNoLongerAvailable';
static const doYouWantToCompleteThisDeal = 'doYouWantToCompleteThisDeal';
static const customerCompletingDealMeansThat = 'customerCompletingDealMeansThat';
static const providerCompletingDealMeansThat = 'providerCompletingDealMeansThat';
static const offerSummary = 'offerSummary';
static const personalInformation = 'personalInformation';
static const name = 'name';
static const phone = 'phone';
static const serviceInformation = 'serviceInformation';
static const locationInformation = 'locationInformation';
static const additionalAddressDetails = 'additionalAddressDetails';
static const serviceName = 'serviceName';
static const serviceCategory = 'serviceCategory';
static const offerPrice = 'offerPrice';
static const totalPrice = 'totalPrice';
static const providerName = 'providerName';
static const createdOn = 'createdOn';
static const manufacturedBy = 'manufacturedBy';
static const manufacturedOn = 'manufacturedOn';
static const shipping = 'shipping';
static const delivery = 'delivery';
static const selectDeliveryType = 'selectDeliveryType';
static const shippingManagementInstruction = 'shippingManagementInstruction';
static const withdrawOffer = 'withdrawOffer';
static const manufacturer = 'manufacturer';
static const priceRange = 'priceRange';
static const cancelOffer = 'cancelOffer';
static const pleaseSpecify = 'pleaseSpecify';
static const customerNotResponding = 'customerNotResponding';
static const cancelRequestPrompt = 'cancelRequestPrompt';
static const requestPermanentlyCancelled = 'requestPermanentlyCancelled';
static const awaitingResponseFromCustomer = 'awaitingResponseFromCustomer';
static const acknowledgePaymentToMowater = 'acknowledgePaymentToMowater';
} }

@ -101,11 +101,11 @@ class ReqOffer {
offerStatusText = json['offerStatusText']; offerStatusText = json['offerStatusText'];
comment = json['comment']; comment = json['comment'];
serviceItemName = json['serviceItem']; serviceItemName = json['serviceItem'];
manufacturedById = json['itemManufacturer']; manufacturedById = json['offeredItemCreatedBy'];
manufacturedOn = json['manufacturedDate']; manufacturedOn = json['offeredItemCreatedOn'];
price = json['price']; price = json['price'];
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum(); requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
requestsTypeEnum = RequestsTypeEnum.serviceRequest; // TODO: THIS SHOULD COME FROM API requestsTypeEnum = RequestsTypeEnum.serviceRequest;
} }
} }

@ -7,7 +7,7 @@ class RequestModel {
int requestType; int requestType;
String requestTypeName; String requestTypeName;
String requestStatusName; String requestStatusName;
RequestStatus requestStatus; RequestStatusEnum requestStatus;
String cityName; String cityName;
String vehicleTypeName; String vehicleTypeName;
String countryName; String countryName;

@ -20,6 +20,7 @@ abstract class RequestRepo {
required int cityID, required int cityID,
required String price, required String price,
required String description, required String description,
required String address,
required bool isSpecialServiceNeeded, required bool isSpecialServiceNeeded,
required List requestImages, required List requestImages,
}); });
@ -32,7 +33,9 @@ abstract class RequestRepo {
Future<List<RequestModel>> getServiceRequestsForProviders({required int serviceProviderID}); Future<List<RequestModel>> getServiceRequestsForProviders({required int serviceProviderID});
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}); Future<GenericRespModel> updateRequestStatus({required RequestStatusEnum requestStatusEnum, required int requestId});
Future<GenericRespModel> updateRequestOfferStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments});
} }
class RequestRepoImp implements RequestRepo { class RequestRepoImp implements RequestRepo {
@ -50,6 +53,7 @@ class RequestRepoImp implements RequestRepo {
required int cityID, required int cityID,
required String price, required String price,
required String description, required String description,
required String address,
required bool isSpecialServiceNeeded, required bool isSpecialServiceNeeded,
required List requestImages, required List requestImages,
}) async { }) async {
@ -65,6 +69,7 @@ class RequestRepoImp implements RequestRepo {
"cityID": cityID, "cityID": cityID,
"price": price, "price": price,
"description": description, "description": description,
"address": address,
"isSpecialServiceNeeded": false, "isSpecialServiceNeeded": false,
"requestImages": requestImages, "requestImages": requestImages,
}; };
@ -106,9 +111,18 @@ class RequestRepoImp implements RequestRepo {
@override @override
Future<List<RequestModel>> getServiceRequestsForProviders({required int serviceProviderID}) async { Future<List<RequestModel>> getServiceRequestsForProviders({required int serviceProviderID}) async {
List<String> requestStatusList = [
RequestStatusEnum.submitted.getIdFromRequestStatusEnum().toString(),
RequestStatusEnum.completed.getIdFromRequestStatusEnum().toString(),
RequestStatusEnum.inProgress.getIdFromRequestStatusEnum().toString(),
RequestStatusEnum.paid.getIdFromRequestStatusEnum().toString(),
RequestStatusEnum.delivery.getIdFromRequestStatusEnum().toString(),
RequestStatusEnum.shipping.getIdFromRequestStatusEnum().toString(),
];
final parameters = { final parameters = {
"ServiceProviderId": serviceProviderID.toString(), "ServiceProviderId": serviceProviderID.toString(),
"RequestTypeId": "2", // Only to get the Service Request "RequestTypeId": "2", // Only to get the Service Request
"RequestStatuses": requestStatusList,
}; };
GenericRespModel genericRespModel = await apiClient.getJsonForObject( GenericRespModel genericRespModel = await apiClient.getJsonForObject(
(json) => GenericRespModel.fromJson(json), (json) => GenericRespModel.fromJson(json),
@ -165,7 +179,23 @@ class RequestRepoImp implements RequestRepo {
} }
@override @override
Future<GenericRespModel> updateOfferRequestStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}) async { Future<GenericRespModel> updateRequestStatus({required RequestStatusEnum requestStatusEnum, required int requestId}) async {
var queryParameters = {
"requestId": requestId.toString(),
"requestStatus": requestStatusEnum.getIdFromRequestStatusEnum().toString(),
};
GenericRespModel genericRespModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
appState.currentAppType == AppType.provider ? ApiConsts.updateRequestProvider : ApiConsts.updateRequestCustomer,
queryParameters,
token: appState.getUser.data!.accessToken,
);
return genericRespModel;
}
@override
Future<GenericRespModel> updateRequestOfferStatus({required RequestOfferStatusEnum requestOfferStatusEnum, required int requestOfferId, required String comments}) async {
var queryParameters = { var queryParameters = {
"requestOfferId": requestOfferId.toString(), "requestOfferId": requestOfferId.toString(),
"offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum().toString(), "offerStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum().toString(),

@ -50,6 +50,16 @@ class MyColors {
static const Color adSoldStatusColor = Color(0xff22742B); static const Color adSoldStatusColor = Color(0xff22742B);
static const Color adPendingStatusColor = Color(0xffEDB947); static const Color adPendingStatusColor = Color(0xffEDB947);
static const Color pendingColor = Colors.amber;
static const Color submittedColor = Colors.blue;
static const Color inProgressColor = Colors.deepOrange;
static const Color completedColor = Colors.green;
static const Color cancelledColor = Colors.red;
static const Color paidColor = Colors.teal;
static const Color expiredColor = Colors.grey;
static const Color shippingColor = Colors.purple;
static const Color deliveryColor = Colors.brown;
static Decoration gradient = BoxDecoration( static Decoration gradient = BoxDecoration(
gradient: const LinearGradient(colors: [ gradient: const LinearGradient(colors: [
darkPrimaryColor, darkPrimaryColor,

@ -1,4 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/app_permission_handler.dart'; import 'package:mc_common_app/utils/app_permission_handler.dart';
@ -11,7 +13,7 @@ Future<ConfirmAction?> showConfirmDialogs(context, msg, positiveText, negativeTe
builder: (context) { builder: (context) {
return AlertDialog( return AlertDialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
title: Text(msg, style: TextStyle(fontSize: 16)), title: Text(msg, style: const TextStyle(fontSize: 16)),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: Text( child: Text(
@ -35,7 +37,7 @@ Future<ConfirmAction?> showConfirmDialogs(context, msg, positiveText, negativeTe
); );
} }
void actionConfirmationBottomSheet({required BuildContext context, required Widget title, required subtitle, required Widget actionButtonYes, required Widget actionButtonNo}) { void actionConfirmationBottomSheet({required BuildContext context, required Widget title, required subtitle, required Widget actionButtonYes, required Widget actionButtonNo, Widget? confirmationWidget, bool isOnlyOneButton = false}) {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
@ -46,8 +48,19 @@ void actionConfirmationBottomSheet({required BuildContext context, required Widg
description: Column( description: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"$subtitle".toText(fontSize: 16), "$subtitle".toText(fontSize: 14, fontWeight: MyFonts.Medium),
if (confirmationWidget != null) ...[
10.height,
confirmationWidget,
],
25.height, 25.height,
if (isOnlyOneButton) ...[
Row(
children: [
actionButtonYes,
],
),
] else ...[
Row( Row(
children: [ children: [
actionButtonYes, actionButtonYes,
@ -55,9 +68,11 @@ void actionConfirmationBottomSheet({required BuildContext context, required Widg
actionButtonNo, actionButtonNo,
], ],
), ),
],
19.height, 19.height,
], ],
)); ),
);
}, },
); );
} }

@ -56,7 +56,7 @@ enum AdPostStatus {
allAds, allAds,
} }
enum RequestStatus { enum RequestStatusEnum {
pending, pending,
submitted, submitted,
inProgress, inProgress,
@ -65,21 +65,8 @@ enum RequestStatus {
paid, paid,
expired, expired,
shipping, shipping,
delivery,
} }
//TODO: Needs to remove
// public enum RequestType : int
// {
// Special_Car_Request = 1,
// Service_Request = 2 //SparePart
// }
// public enum OfferStatus : int
// {
// Offer = 1,//SP
// Negotiate = 2,
// Accepted = 3,
// Rejected = 4,
// Cancelled = 5 //SP
// }
enum PaymentMethods { enum PaymentMethods {
mada, mada,

@ -222,30 +222,26 @@ class Utils {
} }
} }
static Color getChipColorByRequestStatus(RequestStatus requestStatus) { static Color getChipColorByRequestStatus(RequestStatusEnum requestStatus) {
switch (requestStatus) { switch (requestStatus) {
case RequestStatus.pending: case RequestStatusEnum.pending:
return MyColors.adPendingStatusColor; return MyColors.pendingColor;
case RequestStatus.submitted: case RequestStatusEnum.submitted:
return MyColors.lightTextColor; return MyColors.submittedColor;
case RequestStatusEnum.inProgress:
case RequestStatus.inProgress: return MyColors.inProgressColor;
return MyColors.lightTextColor; case RequestStatusEnum.completed:
return MyColors.completedColor;
case RequestStatus.completed: case RequestStatusEnum.cancelled:
return MyColors.greenColor; return MyColors.cancelledColor;
case RequestStatusEnum.paid:
case RequestStatus.cancelled: return MyColors.paidColor;
return MyColors.redColor; case RequestStatusEnum.expired:
return MyColors.expiredColor;
case RequestStatus.paid: case RequestStatusEnum.shipping:
return MyColors.greenColor; return MyColors.shippingColor;
case RequestStatusEnum.delivery:
case RequestStatus.expired: return MyColors.deliveryColor;
return MyColors.redColor;
case RequestStatus.shipping:
return MyColors.greenColor;
} }
} }
@ -271,7 +267,6 @@ class Utils {
} }
} }
static String getChipStatusTextByBranchStatus(BranchStatusEnum branchStatusEnum) { static String getChipStatusTextByBranchStatus(BranchStatusEnum branchStatusEnum) {
switch (branchStatusEnum) { switch (branchStatusEnum) {
case BranchStatusEnum.pending: case BranchStatusEnum.pending:
@ -301,11 +296,7 @@ class Utils {
borderRadius: const BorderRadius.all(Radius.circular(200)), borderRadius: const BorderRadius.all(Radius.circular(200)),
), ),
padding: padding, padding: padding,
child: text.toText( child: text.toText(fontSize: 10, color: textColor, letterSpacing: -0.50));
fontSize: 10,
color: textColor,
letterSpacing: -0.50
));
} }
static InputDecoration txtField(String label) { static InputDecoration txtField(String label) {

@ -46,6 +46,13 @@ class ChatVM extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
bool acknowledgePaymentToMowaterStatus = false;
updateAcknowledgePaymentToMowaterStatus(var value) {
acknowledgePaymentToMowaterStatus = value;
notifyListeners();
}
bool isUserOnChatScreen = false; bool isUserOnChatScreen = false;
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
@ -66,7 +73,7 @@ class ChatVM extends ChangeNotifier {
List<OfferRequestCommentModel> offerRejectModelList = [ List<OfferRequestCommentModel> offerRejectModelList = [
OfferRequestCommentModel( OfferRequestCommentModel(
index: 0, index: 0,
isSelected: false, isSelected: true,
title: LocaleKeys.changedMind.tr(), title: LocaleKeys.changedMind.tr(),
), ),
OfferRequestCommentModel( OfferRequestCommentModel(
@ -81,15 +88,20 @@ class ChatVM extends ChangeNotifier {
), ),
OfferRequestCommentModel( OfferRequestCommentModel(
index: 3, index: 3,
isSelected: true, isSelected: false,
title: LocaleKeys.customerNotResponding.tr(),
),
OfferRequestCommentModel(
index: 4,
isSelected: false,
title: LocaleKeys.otherVar.tr(), title: LocaleKeys.otherVar.tr(),
), ),
]; ];
OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel( OfferRequestCommentModel selectedOfferRequestCommentModel = OfferRequestCommentModel(
index: 3, index: 0,
isSelected: true, isSelected: true,
title: LocaleKeys.otherVar.tr(), title: LocaleKeys.changedMind.tr(),
); );
void updateSelectionInOfferRejectModelList(int index) { void updateSelectionInOfferRejectModelList(int index) {
@ -131,26 +143,44 @@ class ChatVM extends ChangeNotifier {
Future<void> onNewMessageReceivedForRequestOffer({required List<ChatMessageModel> messages, bool isMyOwnOffer = false, required RequestsVM requestsVM}) async { Future<void> onNewMessageReceivedForRequestOffer({required List<ChatMessageModel> messages, bool isMyOwnOffer = false, required RequestsVM requestsVM}) async {
if (AppState().currentAppType == AppType.customer) { if (AppState().currentAppType == AppType.customer) {
for (var msg in messages) { for (var currentMessage in messages) {
int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == msg.senderUserID); int providerIndex = serviceProviderOffersList.indexWhere((element) => element.providerUserId == currentMessage.senderUserID);
if (providerIndex != -1) { if (providerIndex != -1) {
serviceProviderOffersList[providerIndex].chatMessages!.add(msg); if (currentMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
for (var chatMessage in serviceProviderOffersList[providerIndex].chatMessages!) {
if (chatMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer && chatMessage.reqOffer!.id == currentMessage.reqOffer!.id) {
logger.i("chatMessage reqOfferID: ${chatMessage.reqOffer!.id.toString()}");
logger.i("currentMessage reqOfferID: ${currentMessage.reqOffer!.id.toString()}");
chatMessage.reqOffer!.requestOfferStatusEnum = currentMessage.reqOffer!.requestOfferStatusEnum;
}
}
}
serviceProviderOffersList[providerIndex].chatMessages!.add(currentMessage);
scrollChatDown(); scrollChatDown();
} }
} }
} else { } else {
for (var msg in messages) { for (var currentMessage in messages) {
logger.i(msg); logger.i(currentMessage);
// Where we need to call this function for saving a message in chat we will use receiverUserID and in those cases where received ID is null , it means it is a signal R call // Where we need to call this function for saving a message in chat we will use receiverUserID and in those cases where received ID is null , it means it is a signal R call
int providerIndex = -1; int requestIndex = -1;
if (isMyOwnOffer) { if (isMyOwnOffer) {
providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.receiverUserID && element.id == msg.requestID)); requestIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == currentMessage.receiverUserID && element.id == currentMessage.requestID));
} else { } else {
providerIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == msg.senderUserID && element.id == msg.requestID)); requestIndex = requestsVM.myFilteredRequests.indexWhere((element) => (element.customerUserID == currentMessage.senderUserID && element.id == currentMessage.requestID));
} }
log("providerIndex: $providerIndex"); log("requestIndex: $requestIndex");
if (providerIndex != -1) { if (requestIndex != -1) {
requestsVM.addChatMessagesInRequestsModel(msg: msg, index: providerIndex); if (currentMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
for (var chatMessage in requestsVM.myFilteredRequests[requestIndex].chatMessages) {
if (chatMessage.chatMessageTypeEnum == ChatMessageTypeEnum.offer && chatMessage.reqOffer!.id == currentMessage.reqOffer!.id) {
logger.i("chatMessage reqOfferID: ${chatMessage.reqOffer!.id.toString()}");
logger.i("currentMessage reqOfferID: ${currentMessage.reqOffer!.id.toString()}");
chatMessage.reqOffer!.requestOfferStatusEnum = currentMessage.reqOffer!.requestOfferStatusEnum;
}
}
}
requestsVM.addChatMessagesInRequestsModel(msg: currentMessage, index: requestIndex);
scrollChatDown(); scrollChatDown();
} }
} }
@ -158,8 +188,6 @@ class ChatVM extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> onNewMessageReceivedForAds({required List<ChatMessageModel> messages}) async { Future<void> onNewMessageReceivedForAds({required List<ChatMessageModel> messages}) async {
for (var msg in messages) { for (var msg in messages) {
currentMessagesForAds.add(msg); currentMessagesForAds.add(msg);
@ -323,10 +351,7 @@ class ChatVM extends ChangeNotifier {
serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel); serviceProviderOffersList[providerIndex].chatMessages!.add(chatMessageModel);
} }
} else { } else {
int providerIndex = context int providerIndex = context.read<RequestsVM>().myFilteredRequests.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
.read<RequestsVM>()
.myFilteredRequests
.indexWhere((element) => (element.customerUserID == receiverId && element.id == requestId));
log("providerIndex2:$providerIndex"); log("providerIndex2:$providerIndex");
if (providerIndex != -1) { if (providerIndex != -1) {
context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex); context.read<RequestsVM>().addChatMessagesInRequestsModel(msg: chatMessageModel, index: providerIndex);
@ -370,6 +395,10 @@ class ChatVM extends ChangeNotifier {
for (var message in serviceProviderOffersList[providerOfferIndex].chatMessages!) { for (var message in serviceProviderOffersList[providerOfferIndex].chatMessages!) {
if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) { if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
updateLatestOfferId(message.reqOfferID ?? 0); updateLatestOfferId(message.reqOfferID ?? 0);
if (message.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.accepted) {
context.read<RequestsVM>().updateAcceptedReqOffer(message.reqOffer!);
context.read<RequestsVM>().updateAcceptedRequestOfferProviderName(serviceProviderOffersList[providerOfferIndex].name ?? "");
}
log("latestOfferId: $latestOfferId"); log("latestOfferId: $latestOfferId");
} }
} }
@ -404,9 +433,11 @@ class ChatVM extends ChangeNotifier {
} }
Future<int> onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId, required String comments}) async { Future<int> onActionOfferTapped({required BuildContext context, required RequestOfferStatusEnum requestOfferStatusEnum, required int reqOfferId, required String comments}) async {
Utils.showLoading(context);
try { try {
GenericRespModel genericRespModel = await requestRepo.updateOfferRequestStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId, comments: comments); GenericRespModel genericRespModel = await requestRepo.updateRequestOfferStatus(requestOfferStatusEnum: requestOfferStatusEnum, requestOfferId: reqOfferId, comments: comments);
Utils.showToast(genericRespModel.message.toString()); Utils.showToast(genericRespModel.message.toString());
Utils.showLoading(context);
return genericRespModel.messageStatus == 1 ? reqOfferId : -1; return genericRespModel.messageStatus == 1 ? reqOfferId : -1;
} catch (e) { } catch (e) {
logger.i(e.toString()); logger.i(e.toString());
@ -563,7 +594,8 @@ class ChatVM extends ChangeNotifier {
notifyListeners(); notifyListeners();
if (AppState().currentAppType == AppType.customer) {} else {} if (AppState().currentAppType == AppType.customer) {
} else {}
return true; return true;
} }
return false; return false;

@ -10,6 +10,7 @@ import 'package:mc_common_app/services/payments_service.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; import 'package:mc_common_app/view_models/subscriptions_view_model.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -132,8 +133,8 @@ class PaymentVM extends ChangeNotifier {
Future<void> placeThePayment({required PaymentTypes paymentTypeEnum, required BuildContext context}) async { Future<void> placeThePayment({required PaymentTypes paymentTypeEnum, required BuildContext context}) async {
await paymentService.placePayment( await paymentService.placePayment(
// This will be request ID for request payment || ad ID for Ad Related Payment || OrderProviderSubscriptionID for SubscriptionPayment
id: getIdTypeByPaymentType(paymentTypeEnum), id: getIdTypeByPaymentType(paymentTypeEnum),
// This will be request ID for request payment || ad ID for Ad Related Payment || OrderProviderSubscriptionID for SubscriptionPayment
appointmentIds: appointmentIdsForPayment, appointmentIds: appointmentIdsForPayment,
paymentType: paymentTypeEnum, paymentType: paymentTypeEnum,
onFailure: () { onFailure: () {
@ -141,26 +142,37 @@ class PaymentVM extends ChangeNotifier {
switch (paymentTypeEnum) { switch (paymentTypeEnum) {
case PaymentTypes.subscription: case PaymentTypes.subscription:
// TODO: Handle this case. // TODO: Handle this case.
Utils.showToast("Appointment Payment has been Failed!!");
break; break;
case PaymentTypes.appointment:
case PaymentTypes.request:
// TODO: Handle this case. // TODO: Handle this case.
log("Appointment Payment has been Failed!!"); Utils.showToast("Request Payment has been Failed!!");
break; break;
case PaymentTypes.adReserve: case PaymentTypes.adReserve:
// TODO: Handle this case. // TODO: Handle this case.
Utils.showToast("adReserve Payment has been Failed!!");
break; break;
case PaymentTypes.ads: case PaymentTypes.ads:
// TODO: Handle this case. // TODO: Handle this case.
Utils.showToast("ads Payment has been Failed!!");
break; break;
case PaymentTypes.request:
case PaymentTypes.extendAds:
// TODO: Handle this case. // TODO: Handle this case.
Utils.showToast("extendAds Payment has been Failed!!");
break; break;
case PaymentTypes.extendAds:
case PaymentTypes.appointment:
// TODO: Handle this case. // TODO: Handle this case.
Utils.showToast("Appointment Payment has been Failed!!");
break; break;
case PaymentTypes.partialAppointment:
log("Partial Appointment Payment has been Failed!!");
case PaymentTypes.partialAppointment:
Utils.showToast("partialAppointment Payment has been Failed!!");
break; break;
} }
}, },
@ -168,35 +180,39 @@ class PaymentVM extends ChangeNotifier {
// TOD0: we have to take payment confirmation methods from Backend team and make success callbacks like onAdsPaymentSuccess // TOD0: we have to take payment confirmation methods from Backend team and make success callbacks like onAdsPaymentSuccess
switch (paymentTypeEnum) { switch (paymentTypeEnum) {
case PaymentTypes.subscription: case PaymentTypes.subscription:
onSubscriptionSuccess(context); onSubscriptionPaymentSuccess(context);
break; break;
case PaymentTypes.appointment: case PaymentTypes.appointment:
log("Appointment Payment has been Succeeded"); Utils.showToast("Appointment Payment has been Succeeded");
break; break;
case PaymentTypes.partialAppointment:
Utils.showToast("Partial Appointment Payment has been Succeeded");
break;
case PaymentTypes.request: case PaymentTypes.request:
Utils.showToast("Request Payment has been Succeeded");
onRequestPaymentSuccess(context);
break; break;
case PaymentTypes.adReserve: case PaymentTypes.adReserve:
case PaymentTypes.ads: case PaymentTypes.ads:
case PaymentTypes.extendAds: case PaymentTypes.extendAds:
await onAdsPaymentSuccess(context: context, paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(), currentAdId: currentAdId); await onAdsPaymentSuccess(context: context, paymentTypeId: paymentTypeEnum.getIdFromPaymentTypesEnum(), currentAdId: currentAdId);
break; break;
case PaymentTypes.partialAppointment:
log("Partial Appointment Payment has been Succeeded");
break;
} }
}, },
); );
} }
onSubscriptionSuccess(BuildContext context) { void onRequestPaymentSuccess(BuildContext context) {
// pop(context); context.read<DashboardVmCustomer>().onNavbarTapped(4);
// pop(context); navigateReplaceWithName(context, AppRoutes.dashboard);
// pop(context); }
// context.read<SubscriptionsVM>().getMySubscriptions(AppState().getUser.data?.userInfo?.providerId.toString() ?? ""); void onSubscriptionPaymentSuccess(BuildContext context) {
context context.read<SubscriptionsVM>().mySubscriptionsBySp = [];
.read<SubscriptionsVM>()
.mySubscriptionsBySp = [];
context.read<SubscriptionsVM>().getMySubscriptionsBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? ""); context.read<SubscriptionsVM>().getMySubscriptionsBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "");
navigateReplaceWithNameUntilRoute(context, AppRoutes.mySubscriptionsPage); navigateReplaceWithNameUntilRoute(context, AppRoutes.mySubscriptionsPage);
} }
@ -210,7 +226,8 @@ class PaymentVM extends ChangeNotifier {
await placeThePayment(context: context, paymentTypeEnum: paymentType); await placeThePayment(context: context, paymentTypeEnum: paymentType);
break; break;
case PaymentTypes.request: case PaymentTypes.request:
// TODO: Handle this case. if (requestId == -1) return;
await placeThePayment(context: context, paymentTypeEnum: paymentType);
break; break;
case PaymentTypes.subscription: case PaymentTypes.subscription:
await placeThePayment(context: context, paymentTypeEnum: paymentType); await placeThePayment(context: context, paymentTypeEnum: paymentType);

@ -9,6 +9,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart'; import 'package:mc_common_app/models/general_models/enums_model.dart';
@ -19,6 +20,7 @@ import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/request_repo.dart'; import 'package:mc_common_app/repositories/request_repo.dart';
import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
@ -48,6 +50,20 @@ class RequestsVM extends BaseVM {
currentSelectedRequest = value; currentSelectedRequest = value;
} }
ReqOffer? acceptedRequestOffer;
updateAcceptedReqOffer(ReqOffer value) {
acceptedRequestOffer = value;
notifyListeners();
}
String? acceptedRequestOfferProviderName;
updateAcceptedRequestOfferProviderName(String value) {
acceptedRequestOfferProviderName = value;
notifyListeners();
}
populateRequestsFilterList() async { populateRequestsFilterList() async {
if (requestsTypeFilterOptions.isNotEmpty) return; if (requestsTypeFilterOptions.isNotEmpty) return;
@ -95,6 +111,10 @@ class RequestsVM extends BaseVM {
for (var message in myFilteredRequests[index].chatMessages) { for (var message in myFilteredRequests[index].chatMessages) {
if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) { if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) {
context.read<ChatVM>().updateLatestOfferId(message.reqOfferID ?? 0); context.read<ChatVM>().updateLatestOfferId(message.reqOfferID ?? 0);
if (message.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.accepted) {
updateAcceptedReqOffer(message.reqOffer!);
updateAcceptedRequestOfferProviderName(message.senderName ?? "");
}
} }
} }
} }
@ -227,10 +247,10 @@ class RequestsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
bool isShippingDeliveryEnabled = false; bool shippingEnabled = false;
void updateShippingDeliverEnabled(bool v) { void updateShippingEnabled(bool v) {
isShippingDeliveryEnabled = v; shippingEnabled = v;
notifyListeners(); notifyListeners();
} }
@ -256,15 +276,20 @@ class RequestsVM extends BaseVM {
//Request Management //Request Management
String price = ""; String price = "";
String description = ""; String description = "";
String address = "";
updatePrice(String v) { void updatePrice(String v) {
price = v; price = v;
} }
updateDescription(String v) { void updateDescription(String v) {
description = v; description = v;
} }
void updateAddress(String v) {
address = v;
}
Future<RequestPostingImages> convertFileToRequestPostingImages({required File file}) async { Future<RequestPostingImages> convertFileToRequestPostingImages({required File file}) async {
List<int> imageBytes = await file.readAsBytes(); List<int> imageBytes = await file.readAsBytes();
String image = base64Encode(imageBytes); String image = base64Encode(imageBytes);
@ -305,6 +330,7 @@ class RequestsVM extends BaseVM {
cityID: vehicleCityId.selectedId, cityID: vehicleCityId.selectedId,
price: price, price: price,
description: description, description: description,
address: address,
isSpecialServiceNeeded: false, isSpecialServiceNeeded: false,
requestImages: requestImages, requestImages: requestImages,
); );
@ -353,6 +379,9 @@ class RequestsVM extends BaseVM {
} else if (description.isEmpty) { } else if (description.isEmpty) {
Utils.showToast(LocaleKeys.addValidDescription.tr()); Utils.showToast(LocaleKeys.addValidDescription.tr());
isValid = false; isValid = false;
} else if (address.isEmpty && requestTypeId.selectedId == 2) {
Utils.showToast(LocaleKeys.addValidDescription.tr());
isValid = false;
} }
return isValid; return isValid;
} }
@ -410,6 +439,49 @@ class RequestsVM extends BaseVM {
} }
} }
List<OfferRequestCommentModel> providerDeliveryActionsList = [
OfferRequestCommentModel(
index: 0,
isSelected: false,
title: LocaleKeys.shipping.tr(),
),
OfferRequestCommentModel(
index: 1,
isSelected: true,
title: LocaleKeys.delivery.tr(),
),
];
OfferRequestCommentModel selectedProviderDeliveryAction = OfferRequestCommentModel(
index: 1,
isSelected: true,
title: LocaleKeys.delivery.tr(),
);
void updateSelectedProviderDeliveryAction(int index) {
for (var value in providerDeliveryActionsList) {
value.isSelected = false;
}
selectedProviderDeliveryAction = providerDeliveryActionsList[index];
providerDeliveryActionsList[index].isSelected = true;
notifyListeners();
}
Future<bool> onActionRequestTapped({required BuildContext context, required RequestStatusEnum requestStatusEnum, required int requestId}) async {
Utils.showLoading(context);
try {
GenericRespModel genericRespModel = await requestRepo.updateRequestStatus(requestStatusEnum: requestStatusEnum, requestId: requestId);
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;
}
}
//SENDING OFFER //SENDING OFFER
bool isSendOfferValidated() { bool isSendOfferValidated() {
bool isValidated = true; bool isValidated = true;

@ -175,6 +175,14 @@ class SubscriptionsVM extends BaseVM {
} }
} }
// Rights
// Branch CRUD
// Services in Branch (CRUD)
// Appointment Management
// Request Management with Chat
// Ads CRUD with Chat
// General Chat
// My Provider Subscription // My Provider Subscription
getMySubscriptionsBySP(String? serviceProviderID) async { getMySubscriptionsBySP(String? serviceProviderID) async {
setState(ViewState.busy); setState(ViewState.busy);

@ -37,8 +37,8 @@ class SingleDetailWidget extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"$type:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), (type.isEmpty ? type : "$type:").toText(fontSize: 12, color: MyColors.lightTextColor),
text.toText(fontSize: 14, color: MyColors.black, isBold: true), text.toText(fontSize: 14, color: MyColors.darkTextColor),
], ],
); );
} }

@ -1,6 +1,5 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
@ -22,7 +21,7 @@ class ReviewAppointment extends StatelessWidget {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>(); AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Padding( return Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
bottom: 10, bottom: 0,
left: 21, left: 21,
right: 21, right: 21,
), ),
@ -48,17 +47,12 @@ class ReviewAppointment extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
(appointmentsVM.selectedBranchModel!.branchName ?? (appointmentsVM.selectedBranchModel!.branchName ?? "").toText(fontSize: 16, isBold: true),
"")
.toText(fontSize: 16, isBold: true),
Row( Row(
children: [ children: [
LocaleKeys.location.tr().toText( LocaleKeys.location.tr().toText(color: MyColors.lightTextColor, fontSize: 12),
color: MyColors.lightTextColor,
fontSize: 12),
2.width, 2.width,
": ${appointmentsVM.selectedBranchModel!.branchDescription ?? ""}" ": ${appointmentsVM.selectedBranchModel!.branchDescription ?? ""}".toText(fontSize: 12),
.toText(fontSize: 12),
], ],
), ),
], ],
@ -82,9 +76,7 @@ class ReviewAppointment extends StatelessWidget {
), ),
), ),
], ],
) ).onPress(() {}).toWhiteContainer(width: double.infinity, allPading: 12));
.onPress(() {})
.toWhiteContainer(width: double.infinity, allPading: 12));
} }
Widget buildServicesInfoCard({required BuildContext context}) { Widget buildServicesInfoCard({required BuildContext context}) {
@ -93,18 +85,14 @@ class ReviewAppointment extends StatelessWidget {
shrinkWrap: true, shrinkWrap: true,
itemCount: appointmentsVM.serviceAppointmentScheduleList.length, itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
itemBuilder: (BuildContext context, int scheduleIndex) { itemBuilder: (BuildContext context, int scheduleIndex) {
ServiceAppointmentScheduleModel scheduleData = ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
return Column( return Column(
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: LocaleKeys.services.tr().toText( child: LocaleKeys.services.tr().toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
fontSize: 14,
isBold: true,
color: MyColors.lightTextColor),
), ),
], ],
), ),
@ -112,60 +100,38 @@ class ReviewAppointment extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ListView.separated( ListView.separated(
physics: NeverScrollableScrollPhysics(), // physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: scheduleData.servicesListInAppointment!.length, itemCount: scheduleData.servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) { itemBuilder: (BuildContext context, int serviceIndex) {
String selectedTimeSlot = ""; String selectedTimeSlot = "";
if (scheduleData if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
.selectedCustomTimeDateSlotModel!.availableSlots != selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot;
null) {
selectedTimeSlot = scheduleData
.selectedCustomTimeDateSlotModel!.availableSlots!
.firstWhere((element) => element.isSelected)
.slot;
} }
return Column( return Column(
children: [ children: [
if (scheduleData if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[
.servicesListInAppointment!.isNotEmpty) ...[
Column( Column(
children: List.generate( children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) {
scheduleData.servicesListInAppointment!.length, ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex];
(serviceIndex) {
ServiceModel serviceData = scheduleData
.servicesListInAppointment![serviceIndex];
return Column( return Column(
children: [ children: [
Row( Row(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
children: [ children: [
"${serviceData.providerServiceDescription}" "${serviceData.providerServiceDescription}".toText(fontSize: 16, isBold: true),
.toText(fontSize: 16, isBold: true),
], ],
), ),
Column( Column(
children: List.generate( children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
serviceData.serviceItems!.length, ItemData itemData = serviceData.serviceItems![itemIndex];
(itemIndex) {
ItemData itemData =
serviceData.serviceItems![itemIndex];
return Column( return Column(
children: [ children: [
Row( Row(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
("${itemData.name}: ${itemData.price} " + ("${itemData.name}: ${itemData.price} ${LocaleKeys.sar.tr()}").toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor),
LocaleKeys.sar.tr())
.toText(
fontSize: 13,
isBold: true,
color: MyColors
.lightTextColor),
], ],
), ),
], ],
@ -183,33 +149,21 @@ class ReviewAppointment extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.timeLocation LocaleKeys.timeLocation.tr().toText(fontSize: 16, isBold: true),
.tr()
.toText(fontSize: 16, isBold: true),
3.height, 3.height,
Row(children: [ Row(children: [
LocaleKeys.dateAndTime.tr().toText( LocaleKeys.dateAndTime.tr().toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
fontSize: 12, "${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at ${selectedTimeSlot}".toText(fontSize: 12, isBold: true),
color: MyColors.lightTextColor,
isBold: true),
"${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at ${selectedTimeSlot}"
.toText(fontSize: 12, isBold: true),
]), ]),
Row(children: [ Row(children: [
(LocaleKeys.location.tr() + " ").toText( ("${LocaleKeys.location.tr()} ").toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
fontSize: 12, (scheduleData.appointmentType == 2 ? LocaleKeys.home.tr() : LocaleKeys.workshop.tr()).toText(fontSize: 12, isBold: true),
color: MyColors.lightTextColor,
isBold: true),
(scheduleData.appointmentType == 2
? LocaleKeys.home.tr()
: LocaleKeys.workshop.tr())
.toText(fontSize: 12, isBold: true),
]), ]),
], ],
), ),
), ),
10.height, 10.height,
Divider(thickness: 0.7), const Divider(thickness: 0.7),
Builder(builder: (BuildContext context) { Builder(builder: (BuildContext context) {
double totalServicePrice = 0.0; double totalServicePrice = 0.0;
double totalKms = 15.3; double totalKms = 15.3;
@ -219,35 +173,20 @@ class ReviewAppointment extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.amountVAR LocaleKeys.amountVAR.tr().toText(fontSize: 16, isBold: true),
.tr()
.toText(fontSize: 16, isBold: true),
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.serviceCharges.tr().toText( LocaleKeys.serviceCharges.tr().toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true),
fontSize: 14, "${scheduleData.amountTotal.toString()} SAR".toText(fontSize: 16, isBold: true),
color: MyColors.lightTextColor,
isBold: true),
"${scheduleData.amountTotal.toString()} SAR"
.toText(fontSize: 16, isBold: true),
], ],
), ),
if (scheduleData.appointmentType == 1) ...[ if (scheduleData.appointmentType == 1) ...[
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
(LocaleKeys.locationCharges.tr() + ("${LocaleKeys.locationCharges.tr()} ($rangePricePerKm x $totalKms )").toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true),
" ($rangePricePerKm x $totalKms )") ("${totalServicePrice.toString()} ${LocaleKeys.sar.tr()}").toText(fontSize: 16, isBold: true),
.toText(
fontSize: 14,
color: MyColors.lightTextColor,
isBold: true),
("${totalServicePrice.toString()} " +
LocaleKeys.sar.tr())
.toText(fontSize: 16, isBold: true),
], ],
), ),
], ],
@ -258,16 +197,12 @@ class ReviewAppointment extends StatelessWidget {
], ],
); );
}, },
separatorBuilder: (BuildContext context, int index) => separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2),
Divider(thickness: 2),
).paddingOnly(bottom: 10), ).paddingOnly(bottom: 10),
], ],
), ),
], ],
).toWhiteContainer( ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.fromLTRB(21 , 0, 21, 12));
width: double.infinity,
allPading: 12,
margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 0));
}, },
); );
} }
@ -289,17 +224,9 @@ class ReviewAppointment extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
appointmentsVM.amountToPayForAppointment appointmentsVM.amountToPayForAppointment.toString().toText(fontSize: 16, isBold: true),
.toString()
.toText(fontSize: 16, isBold: true),
2.width, 2.width,
LocaleKeys.sar LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 12,
isBold: true)
.paddingOnly(bottom: 2),
], ],
) )
], ],
@ -307,24 +234,13 @@ class ReviewAppointment extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.remainingAmount LocaleKeys.remainingAmount.tr().toText(fontSize: 14, isBold: true),
.tr()
.toText(fontSize: 14, isBold: true),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
(appointmentsVM.totalAmount - (appointmentsVM.totalAmount - appointmentsVM.amountToPayForAppointment).toString().toText(fontSize: 16, isBold: true),
appointmentsVM.amountToPayForAppointment)
.toString()
.toText(fontSize: 16, isBold: true),
2.width, 2.width,
LocaleKeys.sar LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 12,
isBold: true)
.paddingOnly(bottom: 2),
], ],
) )
], ],
@ -337,17 +253,9 @@ class ReviewAppointment extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
appointmentsVM.totalAmount appointmentsVM.totalAmount.toString().toText(fontSize: 29, isBold: true),
.toString()
.toText(fontSize: 29, isBold: true),
2.width, 2.width,
LocaleKeys.sar LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
.tr()
.toText(
color: MyColors.lightTextColor,
fontSize: 16,
isBold: true)
.paddingOnly(bottom: 5),
], ],
) )
], ],
@ -383,7 +291,9 @@ class ReviewAppointment extends StatelessWidget {
children: [ children: [
ListView( ListView(
children: [ children: [
10.height,
buildBranchInfoCard(context: context), buildBranchInfoCard(context: context),
10.height,
buildServicesInfoCard(context: context), buildServicesInfoCard(context: context),
], ],
).expand(), ).expand(),

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
@ -7,10 +8,14 @@ import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart'; import 'package:mc_common_app/view_models/chat_view_model.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/view_models/requests_view_model.dart';
import 'package:mc_common_app/views/chat/widgets/chat_bottom_sheets.dart';
import 'package:mc_common_app/views/chat/widgets/chat_message_widget.dart'; import 'package:mc_common_app/views/chat/widgets/chat_message_widget.dart';
import 'package:mc_common_app/views/requests/request_bottomsheets.dart'; 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/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:mc_common_app/widgets/txt_field.dart';
@ -90,7 +95,7 @@ class _ChatViewState extends State<ChatView> {
if (chatTypeEnum == ChatTypeEnum.ads) { if (chatTypeEnum == ChatTypeEnum.ads) {
chatMessages = chatVM.currentMessagesForAds; chatMessages = chatVM.currentMessagesForAds;
} else if (chatTypeEnum == ChatTypeEnum.requestOffer) { } else if (chatTypeEnum == ChatTypeEnum.requestOffer) {
if (AppState().currentAppType == AppType.customer) { if (AppState().currentAppType == AppType.customer && chatVM.serviceProviderOffersList.isNotEmpty) {
chatMessages = chatVM.serviceProviderOffersList[chatViewArgumentsForRequest!.providerIndex].chatMessages ?? []; chatMessages = chatVM.serviceProviderOffersList[chatViewArgumentsForRequest!.providerIndex].chatMessages ?? [];
} else { } else {
chatMessages = requestVM.myFilteredRequests[chatViewArgumentsForRequest!.requestIndex].chatMessages; chatMessages = requestVM.myFilteredRequests[chatViewArgumentsForRequest!.requestIndex].chatMessages;
@ -107,7 +112,7 @@ class _ChatViewState extends State<ChatView> {
separatorBuilder: (BuildContext context, int index) => 20.height, separatorBuilder: (BuildContext context, int index) => 20.height,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
ChatMessageModel chatMessageModel = chatMessages[index]; ChatMessageModel chatMessageModel = chatMessages[index];
return ChatMessageCustomWidget(chatMessageModel: chatMessageModel); return ChatMessageCustomWidget(chatMessageModel: chatMessageModel, requestStatusEnum: requestVM.currentSelectedRequest!.requestStatus);
}, },
).horPaddingMain(), ).horPaddingMain(),
), ),
@ -115,16 +120,48 @@ class _ChatViewState extends State<ChatView> {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (chatTypeEnum == ChatTypeEnum.requestOffer && requestVM.currentSelectedRequest!.requestStatus == RequestStatus.inProgress) ...[ if (chatTypeEnum == ChatTypeEnum.requestOffer &&
Center( requestVM.currentSelectedRequest!.requestType.toRequestTypeStatusEnum() == RequestsTypeEnum.serviceRequest &&
child: LocaleKeys.requestAlreadyInProgress.tr().toText( requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.inProgress &&
textAlign: TextAlign.center, AppState().currentAppType == AppType.customer) ...[
color: MyColors.lightTextColor, Expanded(
fontSize: 14, child: ShowFillButton(
maxWidth: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
maxHeight: 55,
title: LocaleKeys.reviewAndPayment.tr(),
isBold: false,
onPressed: () {
context.read<PaymentVM>().updateRequestId(id: requestVM.currentSelectedRequest!.id);
navigateWithName(context, AppRoutes.reviewRequestOffer, arguments: PaymentTypes.request);
},
),
),
// Center(
// child: LocaleKeys.requestAlreadyInProgress.tr().toText(
// textAlign: TextAlign.center,
// color: MyColors.lightTextColor,
// fontSize: 14,
// ),
// ).paddingAll(15)
] else if (chatTypeEnum == ChatTypeEnum.requestOffer &&
requestVM.currentSelectedRequest!.requestType.toRequestTypeStatusEnum() == RequestsTypeEnum.specialCarRequest &&
requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.inProgress &&
AppState().currentAppType == AppType.customer) ...[
Expanded(
child: ShowFillButton(
maxWidth: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
maxHeight: 55,
title: LocaleKeys.completeDeal.tr(),
isBold: false,
onPressed: () {
return dealCompletedConfirmationBottomSheet(mainContext: context, requestStatusEnum: RequestStatusEnum.completed, requestId: requestVM.currentSelectedRequest!.id);
},
),
), ),
).paddingAll(15)
] else ...[ ] else ...[
if (AppState().currentAppType == AppType.provider && chatTypeEnum == ChatTypeEnum.requestOffer) ...[ if (AppState().currentAppType == AppType.provider && chatTypeEnum == ChatTypeEnum.requestOffer && requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.submitted) ...[
Expanded( Expanded(
flex: 1, flex: 1,
child: const Icon( child: const Icon(
@ -134,7 +171,7 @@ class _ChatViewState extends State<ChatView> {
).onPress( ).onPress(
() { () {
RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments(requestIndex: chatViewArgumentsForRequest!.requestIndex, requestModel: chatViewArgumentsForRequest!.requestModel!); RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments(requestIndex: chatViewArgumentsForRequest!.requestIndex, requestModel: chatViewArgumentsForRequest!.requestModel!);
buildSendOfferBottomSheet(context, requestDetailArguments); buildSendOfferBottomSheet(context: context, requestDetailPageArguments: requestDetailArguments, isFromChatScreen: true);
}, },
), ),
), ),
@ -167,7 +204,7 @@ class _ChatViewState extends State<ChatView> {
), ),
], ],
], ],
).toContainer(isShadowEnabled: true), ).toContainer(isShadowEnabled: true)
], ],
); );
}), }),

@ -0,0 +1,70 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.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/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/requests_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:provider/provider.dart';
void dealCompletedConfirmationBottomSheet({required BuildContext mainContext, required RequestStatusEnum requestStatusEnum, required int requestId}) {
final requestVM = mainContext.read<RequestsVM>();
return actionConfirmationBottomSheet(
isOnlyOneButton: true,
context: mainContext,
title: LocaleKeys.doYouWantToCompleteThisDeal.tr().toText(fontSize: 26, isBold: true, letterSpacing: -1.44),
subtitle: AppState().currentAppType == AppType.provider ? LocaleKeys.providerCompletingDealMeansThat.tr() : LocaleKeys.customerCompletingDealMeansThat.tr(),
confirmationWidget: Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return Row(
children: [
Expanded(
child: CircleCheckBoxWithTitle(
isChecked: chatVM.acknowledgePaymentToMowaterStatus,
title: LocaleKeys.acknowledgePaymentToMowater.tr(),
onSelected: () {
chatVM.updateAcknowledgePaymentToMowaterStatus(!chatVM.acknowledgePaymentToMowaterStatus);
},
selectedColor: MyColors.darkPrimaryColor,
),
),
],
);
}),
actionButtonYes: Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return Expanded(
child: ShowFillButton(
maxHeight: 55,
isDisabled: !chatVM.acknowledgePaymentToMowaterStatus,
title: LocaleKeys.submit.tr(),
fontSize: 15,
onPressed: () async {
Navigator.pop(context);
bool status = await requestVM.onActionRequestTapped(context: mainContext, requestStatusEnum: requestStatusEnum, requestId: requestId);
if (status) {
chatVM.updateAcknowledgePaymentToMowaterStatus(false);
mainContext.read<DashboardVmCustomer>().onNavbarTapped(4);
navigateReplaceWithName(mainContext, AppRoutes.dashboard);
}
},
),
);
}),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.no.tr(),
fontSize: 15,
onPressed: () => Navigator.pop(mainContext),
),
),
);
}

@ -1,4 +1,3 @@
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
@ -12,6 +11,7 @@ import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.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/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/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/info_bottom_sheet.dart';
@ -22,15 +22,16 @@ import 'package:easy_localization/easy_localization.dart' as lcl;
class ChatMessageCustomWidget extends StatefulWidget { class ChatMessageCustomWidget extends StatefulWidget {
final ChatMessageModel chatMessageModel; final ChatMessageModel chatMessageModel;
final RequestStatusEnum requestStatusEnum;
const ChatMessageCustomWidget({super.key, required this.chatMessageModel}); const ChatMessageCustomWidget({super.key, required this.chatMessageModel, required this.requestStatusEnum});
@override @override
State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState(); State<ChatMessageCustomWidget> createState() => _ChatMessageCustomWidgetState();
} }
class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> { class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
Future buildRejectOfferBottomSheet({required ChatMessageModel chatMessageModel}) { Future buildRejectOrCancelOfferBottomSheet({required ChatMessageModel chatMessageModel, required RequestOfferStatusEnum requestOfferStatusEnum}) {
return showModalBottomSheet( return showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
@ -38,7 +39,7 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
builder: (BuildContext context) { builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) { return Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) {
return InfoBottomSheet( return InfoBottomSheet(
title: LocaleKeys.makeAnOffer.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44), title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
description: Padding( description: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column( child: Column(
@ -51,8 +52,16 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
ListView.separated( ListView.separated(
shrinkWrap: true, shrinkWrap: true,
itemCount: chatVM.offerRejectModelList.length, itemCount: chatVM.offerRejectModelList.length,
separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 0.5), separatorBuilder: (BuildContext context, int index) {
if (chatVM.offerRejectModelList[index].index == 3 && requestOfferStatusEnum == RequestOfferStatusEnum.rejected) {
return const SizedBox();
}
return const Divider(thickness: 0.5);
},
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
if (chatVM.offerRejectModelList[index].index == 3 && requestOfferStatusEnum == RequestOfferStatusEnum.rejected) {
return const SizedBox();
}
OfferRequestCommentModel offerRequestCommentModel = chatVM.offerRejectModelList[index]; OfferRequestCommentModel offerRequestCommentModel = chatVM.offerRejectModelList[index];
return CircleCheckBoxWithTitle( return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false, isChecked: offerRequestCommentModel.isSelected ?? false,
@ -93,8 +102,9 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
return; return;
} }
Navigator.pop(context); Navigator.pop(context);
bool status = await context.read<ChatVM>().onSendMessageForActionOnRequestOffer(
receiverId: chatMessageModel.senderUserID ?? "", bool status = await chatVM.onSendMessageForActionOnRequestOffer(
receiverId: (chatMessageModel.isMyMessage ?? false) ? chatMessageModel.receiverUserID ?? "" : chatMessageModel.senderUserID ?? "",
chatMessageType: ChatMessageTypeEnum.offer, chatMessageType: ChatMessageTypeEnum.offer,
comments: comments, comments: comments,
requestId: chatMessageModel.reqOffer!.requestID ?? -1, requestId: chatMessageModel.reqOffer!.requestID ?? -1,
@ -104,15 +114,16 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "",
manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "",
manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0, manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0,
requestOfferStatusEnum: RequestOfferStatusEnum.rejected, requestOfferStatusEnum: requestOfferStatusEnum,
context: context, context: context,
); );
if (status) { if (status) {
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.rejected; chatMessageModel.reqOffer!.requestOfferStatusEnum = requestOfferStatusEnum;
setState(() {}); setState(() {});
// Navigator.pop(context); // Navigator.pop(context);
Utils.showToast("Offer Rejected"); chatVM.updateRejectOfferDescription('');
Utils.showToast("Offer ${requestOfferStatusEnum == RequestOfferStatusEnum.rejected ? "Rejected" : "Cancelled"}");
// navigateReplaceWithName(context, AppRoutes.dashboard); // navigateReplaceWithName(context, AppRoutes.dashboard);
} }
}, },
@ -155,11 +166,15 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
); );
if (status) { if (status) {
final requestVM = context.read<RequestsVM>();
chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted; chatMessageModel.reqOffer!.requestOfferStatusEnum = RequestOfferStatusEnum.accepted;
requestVM.currentSelectedRequest!.requestStatus = RequestStatusEnum.inProgress;
requestVM.updateAcceptedReqOffer(chatMessageModel.reqOffer!);
requestVM.updateAcceptedRequestOfferProviderName(chatMessageModel.senderName ?? "");
setState(() {}); setState(() {});
// Navigator.pop(context); // Navigator.pop(context);
Utils.showToast("Offer Accepted"); Utils.showToast("Offer Accepted");
// navigateReplaceWithName(context, AppRoutes.dashboard); // navigateReplaceWithName(context, AppRoutes.dashboard);
} }
}, },
@ -181,9 +196,32 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
); );
} }
Widget buildOfferDetailsInChatMessage({required ChatMessageModel chatMessageModel, required BuildContext context}) { Widget buildOfferDetailsInChatMessage({required RequestStatusEnum requestStatusEnum, required ChatMessageModel chatMessageModel, required BuildContext context}) {
final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer; final requestOfferStatusEnum = chatMessageModel.reqOffer!.requestOfferStatusEnum ?? RequestOfferStatusEnum.offer;
if (requestStatusEnum != RequestStatusEnum.submitted && requestOfferStatusEnum != RequestOfferStatusEnum.accepted) {
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${(chatMessageModel.reqOffer!.price ?? 0.0).toInt()}".toText(fontSize: 19, isBold: true, color: chatMessageModel.isMyMessage! ? MyColors.white : MyColors.darkTextColor),
5.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
),
5.height,
Center(
child: LocaleKeys.offerNoLongerAvailable.tr().toText(
color: chatMessageModel.isMyMessage! ? MyColors.adPendingStatusColor : MyColors.lightTextColor,
fontSize: 12,
isItalic: true,
),
).toContainer(borderRadius: 40, width: double.infinity, backgroundColor: chatMessageModel.isMyMessage! ? MyColors.adPendingStatusColor.withOpacity(0.16) : MyColors.grey98Color.withOpacity(0.1)),
],
);
}
//offerNoLongerAvailable
switch (requestOfferStatusEnum) { switch (requestOfferStatusEnum) {
case RequestOfferStatusEnum.offer: case RequestOfferStatusEnum.offer:
return Column( return Column(
@ -225,13 +263,33 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
backgroundColor: MyColors.white, backgroundColor: MyColors.white,
txtColor: MyColors.redColor, txtColor: MyColors.redColor,
fontSize: 9, fontSize: 9,
onPressed: () async { onPressed: () {
buildRejectOfferBottomSheet(chatMessageModel: chatMessageModel); buildRejectOrCancelOfferBottomSheet(chatMessageModel: chatMessageModel, requestOfferStatusEnum: RequestOfferStatusEnum.rejected);
}, },
), ),
) )
], ],
), ),
] else if (requestStatusEnum == RequestStatusEnum.submitted) ...[
10.height,
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 27,
title: LocaleKeys.cancelOffer.tr(),
fontSize: 9,
borderColor: MyColors.lightTextColor,
isFilled: false,
onPressed: () {
buildRejectOrCancelOfferBottomSheet(chatMessageModel: chatMessageModel, requestOfferStatusEnum: RequestOfferStatusEnum.cancel);
},
backgroundColor: MyColors.white,
txtColor: MyColors.lightTextColor,
),
),
],
),
], ],
], ],
); );
@ -250,6 +308,15 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
case RequestOfferStatusEnum.accepted: case RequestOfferStatusEnum.accepted:
return Column( return Column(
children: [ children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${(chatMessageModel.reqOffer!.price ?? 0.0).toInt()}".toText(fontSize: 19, isBold: true, color: chatMessageModel.isMyMessage! ? MyColors.white : MyColors.darkTextColor),
5.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
),
5.height,
Center( Center(
child: LocaleKeys.offerHasBeenAccepted.tr().toText( child: LocaleKeys.offerHasBeenAccepted.tr().toText(
color: MyColors.adPendingStatusColor, color: MyColors.adPendingStatusColor,
@ -262,6 +329,15 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
case RequestOfferStatusEnum.rejected: case RequestOfferStatusEnum.rejected:
return Column( return Column(
children: [ children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${(chatMessageModel.reqOffer!.price ?? 0.0).toInt()}".toText(fontSize: 19, isBold: true, color: chatMessageModel.isMyMessage! ? MyColors.white : MyColors.darkTextColor),
5.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
),
5.height,
Center( Center(
child: LocaleKeys.offerHasBeenRejected.tr().toText( child: LocaleKeys.offerHasBeenRejected.tr().toText(
color: MyColors.adPendingStatusColor, color: MyColors.adPendingStatusColor,
@ -274,6 +350,15 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
case RequestOfferStatusEnum.cancel: case RequestOfferStatusEnum.cancel:
return Column( return Column(
children: [ children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${(chatMessageModel.reqOffer!.price ?? 0.0).toInt()}".toText(fontSize: 19, isBold: true, color: chatMessageModel.isMyMessage! ? MyColors.white : MyColors.darkTextColor),
5.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, height: 2.2, fontSize: 10, isBold: true),
],
),
5.height,
Center( Center(
child: LocaleKeys.offerHasBeenCancelled.tr().toText( child: LocaleKeys.offerHasBeenCancelled.tr().toText(
color: MyColors.adPendingStatusColor, color: MyColors.adPendingStatusColor,
@ -369,8 +454,9 @@ class _ChatMessageCustomWidgetState extends State<ChatMessageCustomWidget> {
), ),
], ],
), ),
10.height,
if (widget.chatMessageModel.chatMessageTypeEnum == ChatMessageTypeEnum.offer) ...[ if (widget.chatMessageModel.chatMessageTypeEnum == ChatMessageTypeEnum.offer) ...[
buildOfferDetailsInChatMessage(chatMessageModel: widget.chatMessageModel, context: context), buildOfferDetailsInChatMessage(requestStatusEnum: widget.requestStatusEnum, chatMessageModel: widget.chatMessageModel, context: context),
], ],
], ],
).toContainer( ).toContainer(

@ -1,82 +0,0 @@
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
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/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/requests/widget/request_item.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:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class MyRequestsFragment extends StatelessWidget {
const MyRequestsFragment({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.myRequests.tr(),
isRemoveBackButton: true,
),
body: Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Column(
children: [
16.height,
FiltersList(
filterList: requestsVM.requestsTypeFilterOptions,
onFilterTapped: (index, selectedFilterId) {
requestsVM.applyFilterOnRequestsVM(requestsTypeEnum: selectedFilterId.toRequestTypeStatusEnum());
},
),
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true, appType: AppType.provider),
child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: requestsVM.myFilteredRequests.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.noRequeststoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor),
],
)
: ListView.separated(
itemBuilder: (context, index) {
return RequestItem(request: requestsVM.myFilteredRequests[index], appType: AppState().currentAppType, requestIndex: index);
},
separatorBuilder: (context, index) {
return 16.height;
},
itemCount: requestsVM.myFilteredRequests.length,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
),
))
],
);
}),
),
floatingActionButton: AppState().currentAppType == AppType.customer
? FloatingActionButton(
onPressed: () => navigateWithName(context, AppRoutes.createRequestPage),
backgroundColor: MyColors.darkPrimaryColor,
child: const Icon(
Icons.add,
color: MyColors.white,
),
)
: null,
);
}
}

@ -0,0 +1,156 @@
import 'package:flutter/gestures.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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/requests_models/request_model.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
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/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/views/requests/widget/request_item.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/common_widgets/categories_list.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class MyRequestsFragment extends StatelessWidget {
const MyRequestsFragment({super.key});
void cancelRequestBottomSheet(BuildContext context, int requestId) {
return actionConfirmationBottomSheet(
context: context,
title: LocaleKeys.cancelRequestPrompt.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: LocaleKeys.requestPermanentlyCancelled.tr(),
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.yes.tr(),
fontSize: 15,
onPressed: () async {
Navigator.pop(context);
final requestVM = context.read<RequestsVM>();
bool status = await requestVM.onActionRequestTapped(context: context, requestStatusEnum: RequestStatusEnum.cancelled, requestId: requestId);
if (status) {
await requestVM.getRequests(isNeedToRebuild: true, appType: AppType.provider);
}
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: LocaleKeys.no.tr(),
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
bool shouldDismiss(RequestStatusEnum requestStatusEnum) {
if (AppState().currentAppType == AppType.provider) {
return false;
}
if (requestStatusEnum == RequestStatusEnum.pending || requestStatusEnum == RequestStatusEnum.submitted) {
return true;
}
return false;
;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.myRequests.tr(),
isRemoveBackButton: true,
),
body: Container(
color: MyColors.backgroundColor,
width: double.infinity,
height: double.infinity,
child: Consumer(builder: (BuildContext context, RequestsVM requestsVM, Widget? child) {
return Column(
children: [
16.height,
FiltersList(
filterList: requestsVM.requestsTypeFilterOptions,
onFilterTapped: (index, selectedFilterId) {
requestsVM.applyFilterOnRequestsVM(requestsTypeEnum: selectedFilterId.toRequestTypeStatusEnum());
},
),
8.height,
Expanded(
child: RefreshIndicator(
onRefresh: () async => await requestsVM.getRequests(isNeedToRebuild: true, appType: AppType.provider),
child: requestsVM.state == ViewState.busy
? const Center(child: CircularProgressIndicator())
: requestsVM.myFilteredRequests.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocaleKeys.noRequeststoShow.tr().toText(fontSize: 16, color: MyColors.lightTextColor),
],
)
: ListView.separated(
itemBuilder: (context, index) {
return Dismissible(
key: Key(index.toString()),
background: const SizedBox(),
secondaryBackground: Container(
color: const Color(0xFFDD0505),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
LocaleKeys.cancel.tr().toText(fontSize: 15, fontWeight: MyFonts.Medium, height: 23 / 25, color: MyColors.white).margin(right: 23),
],
),
),
dragStartBehavior: DragStartBehavior.start,
direction: shouldDismiss(requestsVM.myFilteredRequests[index].requestStatus) ? DismissDirection.endToStart : DismissDirection.none,
confirmDismiss: (DismissDirection direction) async {
cancelRequestBottomSheet(context, requestsVM.myFilteredRequests[index].id);
},
child: RequestItem(request: requestsVM.myFilteredRequests[index], appType: AppState().currentAppType, requestIndex: index),
);
},
separatorBuilder: (context, index) {
return 16.height;
},
itemCount: requestsVM.myFilteredRequests.length,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
),
))
],
);
}),
),
floatingActionButton: AppState().currentAppType == AppType.customer
? FloatingActionButton(
onPressed: () => navigateWithName(context, AppRoutes.createRequestPage),
backgroundColor: MyColors.darkPrimaryColor,
child: const Icon(
Icons.add,
color: MyColors.white,
),
)
: null,
);
}
}

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'package:easy_localization/src/public_ext.dart'; import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -16,9 +17,9 @@ import 'map_selection_widget.dart';
import 'package:geocoding/geocoding.dart'; import 'package:geocoding/geocoding.dart';
class PickLocationPage extends StatefulWidget { class PickLocationPage extends StatefulWidget {
Function(double, double, String) onPickAddress; final Function(double, double, String) onPickAddress;
PickLocationPage({required this.onPickAddress}); const PickLocationPage({super.key, required this.onPickAddress});
@override @override
State<PickLocationPage> createState() => _PickLocationPageState(); State<PickLocationPage> createState() => _PickLocationPageState();
@ -28,14 +29,14 @@ class _PickLocationPageState extends State<PickLocationPage> {
double latitude = 0; double latitude = 0;
double longitude = 0; double longitude = 0;
final Set<Marker> markers = new Set(); final Set<Marker> markers = {};
late AppMap appMap; late AppMap appMap;
static CameraPosition _kGooglePlex = CameraPosition( static CameraPosition _kGooglePlex = const CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962), target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746, zoom: 14.4746,
); );
late LatLng currentPostion; late LatLng currentPosition;
Completer<GoogleMapController> mapController = Completer(); Completer<GoogleMapController> mapController = Completer();
final ValueNotifier<String> _counter = ValueNotifier<String>(""); final ValueNotifier<String> _counter = ValueNotifier<String>("");
@ -80,7 +81,7 @@ class _PickLocationPageState extends State<PickLocationPage> {
return value.isNotEmpty return value.isNotEmpty
? Container( ? Container(
width: double.infinity, width: double.infinity,
margin: EdgeInsets.all(12), margin: const EdgeInsets.all(12),
child: Card( child: Card(
child: Padding( child: Padding(
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
@ -102,11 +103,12 @@ class _PickLocationPageState extends State<PickLocationPage> {
], ],
), ),
), ),
Container( SizedBox(
width: double.infinity, width: double.infinity,
child: Padding( child: Padding(
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
child: ShowFillButton( child: ShowFillButton(
maxHeight: 55,
title: LocaleKeys.pickAddress.tr(), title: LocaleKeys.pickAddress.tr(),
onPressed: () { onPressed: () {
widget.onPickAddress(latitude, longitude, _counter.value); widget.onPickAddress(latitude, longitude, _counter.value);
@ -120,18 +122,18 @@ class _PickLocationPageState extends State<PickLocationPage> {
); );
} }
Future<void> _updatePosition(CameraPosition _position) async { Future<void> _updatePosition(CameraPosition position) async {
latitude = _position.target.latitude; latitude = position.target.latitude;
longitude = _position.target.longitude; longitude = position.target.longitude;
print(latitude); log(latitude.toString());
print(latitude); log(latitude.toString());
updateAddress(latitude, longitude); updateAddress(latitude, longitude);
} }
void _getUserLocation() async { void _getUserLocation() async {
if (await Permission.location.request().isGranted) { if (await Permission.location.request().isGranted) {
var position = await GeolocatorPlatform.instance.getCurrentPosition(); var position = await GeolocatorPlatform.instance.getCurrentPosition();
currentPostion = LatLng(position.latitude, position.longitude); currentPosition = LatLng(position.latitude, position.longitude);
latitude = position.latitude; latitude = position.latitude;
longitude = position.longitude; longitude = position.longitude;
setMap(); setMap();
@ -141,7 +143,7 @@ class _PickLocationPageState extends State<PickLocationPage> {
(value) async { (value) async {
if (value[Permission.location]!.isGranted) { if (value[Permission.location]!.isGranted) {
var position = await GeolocatorPlatform.instance.getCurrentPosition(); var position = await GeolocatorPlatform.instance.getCurrentPosition();
currentPostion = LatLng(position.latitude, position.longitude); currentPosition = LatLng(position.latitude, position.longitude);
latitude = position.latitude; latitude = position.latitude;
longitude = position.longitude; longitude = position.longitude;
setMap(); setMap();
@ -160,7 +162,7 @@ class _PickLocationPageState extends State<PickLocationPage> {
setMap() { setMap() {
setState(() { setState(() {
_kGooglePlex = CameraPosition( _kGooglePlex = CameraPosition(
target: currentPostion, target: currentPosition,
zoom: 14.4746, zoom: 14.4746,
); );
appMap.moveTo(cameraPostion: _kGooglePlex); appMap.moveTo(cameraPostion: _kGooglePlex);

@ -99,7 +99,7 @@ class PaymentMethodContainer extends StatelessWidget {
return InkWell( return InkWell(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
margin: EdgeInsets.symmetric(vertical: 10), margin: const EdgeInsets.symmetric(vertical: 10),
width: double.infinity, width: double.infinity,
height: 80, height: 80,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -120,11 +120,11 @@ class PaymentMethodContainer extends StatelessWidget {
Container( Container(
height: 80.0, height: 80.0,
width: 80.0, width: 80.0,
padding: EdgeInsets.all(7.0), padding: const EdgeInsets.all(7.0),
child: Image.asset(cardAsset), child: Image.asset(cardAsset),
), ),
Utils.mFlex(1), Utils.mFlex(1),
isSelected ? Utils.statusContainerChip(text: "Selected", padding: EdgeInsets.symmetric(vertical: 6, horizontal: 10)) : SizedBox(), isSelected ? Utils.statusContainerChip(text: "Selected", padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10)) : const SizedBox(),
], ],
), ),
), ),

@ -1,4 +1,6 @@
import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
@ -8,6 +10,7 @@ import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart'; import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart';
import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart'; import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart';
import 'package:mc_common_app/views/location_views/pick_location_page.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
@ -173,11 +176,40 @@ class CreateRequestPage extends StatelessWidget {
8.height, 8.height,
TxtField( TxtField(
hint: LocaleKeys.description.tr(), hint: LocaleKeys.description.tr(),
maxLines: 5, maxLines: 3,
value: requestsVM.description, value: requestsVM.description,
onChanged: (e) => requestsVM.updateDescription(e), onChanged: (e) => requestsVM.updateDescription(e),
), ),
8.height, 8.height,
// 1 -> SpecialCarRequest
// 2 -> ServiceRequest
if (requestsVM.requestTypeId.selectedId == 2) ...[
TxtField(
hint: LocaleKeys.address.tr(),
isNeedClickAll: false,
value: requestsVM.address,
postfixWidget: IconButton(
icon: const Icon(
size: 28,
Icons.add_location_outlined,
),
onPressed: () {
navigateTo(
context,
PickLocationPage(
onPickAddress: (double latitude, double longitude, String address) {
requestsVM.address = address;
requestsVM.setState(ViewState.idle);
},
),
);
}),
onChanged: (e) => requestsVM.updateAddress(e),
),
8.height,
],
DottedRectContainer( DottedRectContainer(
onTap: () => context.read<RequestsVM>().pickMultipleImages(), onTap: () => context.read<RequestsVM>().pickMultipleImages(),
text: LocaleKeys.attachImage.tr(), text: LocaleKeys.attachImage.tr(),
@ -202,19 +234,6 @@ class CreateRequestPage extends StatelessWidget {
}, },
), ),
], ],
16.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: requestsVM.isShippingDeliveryEnabled,
onChanged: null,
),
LocaleKeys.shippingDelivery.tr().toText(color: MyColors.darkPrimaryColor, isBold: true, fontSize: 18)
],
).onPress(() {
requestsVM.updateShippingDeliverEnabled(!requestsVM.isShippingDeliveryEnabled);
}),
], ],
), ),
] ]
@ -225,6 +244,7 @@ class CreateRequestPage extends StatelessWidget {
ShowFillButton( ShowFillButton(
title: LocaleKeys.createRequest.tr(), title: LocaleKeys.createRequest.tr(),
maxWidth: double.infinity, maxWidth: double.infinity,
maxHeight: 55,
margin: const EdgeInsets.all(16), margin: const EdgeInsets.all(16),
onPressed: () async { onPressed: () async {
await context.read<RequestsVM>().onCreateRequestTapped(context); await context.read<RequestsVM>().onCreateRequestTapped(context);

@ -3,17 +3,22 @@ import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.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/utils/utils.dart';
import 'package:mc_common_app/view_models/chat_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.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/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:mc_common_app/widgets/txt_field.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
Future buildSendOfferBottomSheet(BuildContext context, RequestDetailPageArguments requestDetailPageArguments) { Future buildSendOfferBottomSheet({required BuildContext context, required RequestDetailPageArguments requestDetailPageArguments, required bool isFromChatScreen}) {
final requestDetail = requestDetailPageArguments.requestModel; final requestDetail = requestDetailPageArguments.requestModel;
return showModalBottomSheet( return showModalBottomSheet(
context: context, context: context,
@ -54,13 +59,13 @@ Future buildSendOfferBottomSheet(BuildContext context, RequestDetailPageArgument
value: requestsVM.itemManufacturer, value: requestsVM.itemManufacturer,
errorValue: requestsVM.offerPriceError, errorValue: requestsVM.offerPriceError,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
hint: "Manufacturer", hint: LocaleKeys.manufacturer.tr(),
onChanged: (v) => requestsVM.updateItemManufacturer(v), onChanged: (v) => requestsVM.updateItemManufacturer(v),
), ),
12.height, 12.height,
TxtField( TxtField(
errorValue: "", errorValue: "",
hint: "Manufactured On", hint: LocaleKeys.manufacturedOn.tr(),
value: requestsVM.serviceItemCreatedOn, value: requestsVM.serviceItemCreatedOn,
isNeedClickAll: true, isNeedClickAll: true,
postfixData: Icons.calendar_month_rounded, postfixData: Icons.calendar_month_rounded,
@ -95,7 +100,7 @@ Future buildSendOfferBottomSheet(BuildContext context, RequestDetailPageArgument
offerPrice: requestsVM.offerPrice, offerPrice: requestsVM.offerPrice,
requestModel: requestDetail, requestModel: requestDetail,
requestIndex: requestDetailPageArguments.requestIndex, requestIndex: requestDetailPageArguments.requestIndex,
isFromChatScreen: false, isFromChatScreen: isFromChatScreen,
manufacturedById: 1, manufacturedById: 1,
// Todo: It should be the ID of the manufacturer // Todo: It should be the ID of the manufacturer
manufacturedOn: requestsVM.serviceItemCreatedOn, manufacturedOn: requestsVM.serviceItemCreatedOn,
@ -111,3 +116,69 @@ Future buildSendOfferBottomSheet(BuildContext context, RequestDetailPageArgument
}, },
); );
} }
Future buildRequestStatusUpdateSheetForProvider({required BuildContext mainContext, required int requestId}) {
return showModalBottomSheet(
context: mainContext,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return Consumer(builder: (BuildContext context, RequestsVM requestVM, Widget? child) {
return InfoBottomSheet(
title: LocaleKeys.selectDeliveryType.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: requestVM.providerDeliveryActionsList.length,
separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 0.5),
itemBuilder: (BuildContext context, int index) {
OfferRequestCommentModel offerRequestCommentModel = requestVM.providerDeliveryActionsList[index];
return CircleCheckBoxWithTitle(
isChecked: offerRequestCommentModel.isSelected ?? false,
title: '${offerRequestCommentModel.title}',
onSelected: () {
requestVM.updateSelectedProviderDeliveryAction(index);
},
selectedColor: MyColors.darkPrimaryColor,
);
},
),
],
),
25.height,
ShowFillButton(
title: LocaleKeys.submit.tr(),
maxHeight: 55,
onPressed: () async {
// index 0-> shipping
// index 1-> delivery
pop(context);
bool status = false;
if (requestVM.selectedProviderDeliveryAction.index == 0) {
status = await requestVM.onActionRequestTapped(context: mainContext, requestStatusEnum: RequestStatusEnum.shipping, requestId: requestId);
} else if (requestVM.selectedProviderDeliveryAction.index == 1) {
status = await requestVM.onActionRequestTapped(context: mainContext, requestStatusEnum: RequestStatusEnum.delivery, requestId: requestId);
}
if (status) {
await requestVM.getRequests(isNeedToRebuild: true, appType: AppType.provider);
pop(mainContext);
}
},
maxWidth: double.infinity,
),
19.height,
],
),
));
});
},
);
}

@ -9,7 +9,9 @@ import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.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/chat_view_model.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart'; import 'package:mc_common_app/views/advertisement/components/ads_images_corousel_widget.dart';
import 'package:mc_common_app/views/chat/widgets/chat_bottom_sheets.dart';
import 'package:mc_common_app/views/requests/request_bottomsheets.dart'; 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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
@ -22,43 +24,78 @@ class RequestDetailPage extends StatelessWidget {
const RequestDetailPage({Key? key, required this.requestDetailPageArguments}) : super(key: key); const RequestDetailPage({Key? key, required this.requestDetailPageArguments}) : super(key: key);
Widget buildBottomButton({ Widget buildRequestDetailActionFooter({required int requestId, required RequestStatusEnum requestStatus, required RequestsTypeEnum requestTypeEnum, required String statusText, required BuildContext context}) {
required RequestStatus requestStatus, final requestsVM = context.read<RequestsVM>();
required String statusText,
required BuildContext context,
required Function() onViewChatTapped,
}) {
switch (requestStatus) { switch (requestStatus) {
case RequestStatus.submitted: case RequestStatusEnum.submitted:
case RequestStatus.inProgress:
case RequestStatus.paid:
case RequestStatus.shipping:
return ShowFillButton( return ShowFillButton(
maxWidth: double.infinity, maxWidth: double.infinity,
margin: const EdgeInsets.all(15), margin: const EdgeInsets.all(15),
maxHeight: 55, maxHeight: 55,
title: LocaleKeys.viewChat.tr(), title: LocaleKeys.viewChat.tr(),
isBold: false, isBold: false,
onPressed: onViewChatTapped, onPressed: () => onViewChatTapped(context),
); );
case RequestStatus.completed:
case RequestStatus.cancelled: case RequestStatusEnum.inProgress:
case RequestStatus.expired: if (requestTypeEnum == RequestsTypeEnum.serviceRequest) {
case RequestStatus.pending: return buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr());
return buildDisabledButton(statusText); } else {
} return buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr());
} }
Widget buildDisabledButton(String text) { case RequestStatusEnum.paid:
if (AppState().currentAppType == AppType.provider) {
return ShowFillButton( return ShowFillButton(
backgroundColor: MyColors.grey98Color.withOpacity(0.3),
txtColor: MyColors.lightTextColor,
maxWidth: double.infinity, maxWidth: double.infinity,
margin: const EdgeInsets.all(15), margin: const EdgeInsets.all(15),
maxHeight: 55, maxHeight: 55,
title: text, title: LocaleKeys.selectDeliveryType.tr(),
isBold: false, isBold: false,
onPressed: () {}, onPressed: () {
buildRequestStatusUpdateSheetForProvider(mainContext: context, requestId: requestId);
},
);
} else {
return buildStatusContainer(LocaleKeys.awaitingResponseFromProvider.tr());
}
case RequestStatusEnum.shipping:
case RequestStatusEnum.delivery:
if (AppState().currentAppType == AppType.provider) {
return buildStatusContainer(LocaleKeys.shippingManagementInstruction.tr(), isForShippingOrDelivery: true);
} else {
return ShowFillButton(
maxWidth: double.infinity,
margin: const EdgeInsets.all(15),
maxHeight: 55,
title: LocaleKeys.completeDeal.tr(),
onPressed: () {
return dealCompletedConfirmationBottomSheet(mainContext: context, requestStatusEnum: RequestStatusEnum.completed, requestId: requestId);
},
);
}
case RequestStatusEnum.completed:
case RequestStatusEnum.cancelled:
case RequestStatusEnum.expired:
case RequestStatusEnum.pending:
return buildStatusContainer(statusText);
}
}
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),
); );
} }
@ -94,6 +131,18 @@ class RequestDetailPage extends StatelessWidget {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: LocaleKeys.requestDetail.tr(), title: LocaleKeys.requestDetail.tr(),
actions: [
(requestDetailPageArguments.requestModel.isChatted)
? Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8, right: 21),
child: const Icon(Icons.messenger_outline_rounded, color: Colors.black, size: 18).toContainer(
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
),
).onPress(() => onViewChatTapped(context))
: const SizedBox(),
],
), ),
body: SizedBox( body: SizedBox(
width: double.infinity, width: double.infinity,
@ -120,14 +169,15 @@ class RequestDetailPage extends StatelessWidget {
title: LocaleKeys.sendOffer.tr(), title: LocaleKeys.sendOffer.tr(),
isBold: false, isBold: false,
fontSize: 18, fontSize: 18,
onPressed: () => buildSendOfferBottomSheet(context, requestDetailPageArguments), onPressed: () => buildSendOfferBottomSheet(context: context, requestDetailPageArguments: requestDetailPageArguments, isFromChatScreen: false),
), ),
] else ...[ ] else ...[
buildBottomButton( buildRequestDetailActionFooter(
requestId: requestDetailPageArguments.requestModel.id,
requestStatus: requestDetailPageArguments.requestModel.requestStatus, requestStatus: requestDetailPageArguments.requestModel.requestStatus,
statusText: "Offer ${requestDetailPageArguments.requestModel.requestStatusName}", statusText: "Offer ${requestDetailPageArguments.requestModel.requestStatusName}",
context: context, context: context,
onViewChatTapped: () async => onViewChatTapped(context), requestTypeEnum: requestDetailPageArguments.requestModel.requestType.toRequestTypeStatusEnum(),
), ),
], ],
], ],
@ -151,8 +201,8 @@ class RequestDetailPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
requestDetail.vehicleTypeName.toText(fontSize: 16, letterSpacing: -0.64), requestDetail.vehicleTypeName.toText(fontSize: 16, letterSpacing: -0.64),
showItem("Manufacturer:", requestDetail.brand), showItem("${LocaleKeys.manufacturer.tr()}: ", requestDetail.brand),
showItem("Model:", "${requestDetail.year}"), showItem("${LocaleKeys.model.tr()}: ", "${requestDetail.year}"),
], ],
), ),
), ),
@ -172,10 +222,10 @@ class RequestDetailPage extends StatelessWidget {
), ),
], ],
), ),
showItem("Customer Name: ", requestDetail.customerName), showItem("${LocaleKeys.customerName.tr()}: ", requestDetail.customerName),
showItem("Description: ", requestDetail.description), showItem("${LocaleKeys.description.tr()}: ", requestDetail.description),
16.height, 16.height,
showItem("Price Range:", ""), showItem("${LocaleKeys.priceRange.tr()}:", ""),
Row( Row(
children: [ children: [
Expanded( Expanded(
@ -195,7 +245,7 @@ class RequestDetailPage extends StatelessWidget {
children: [ children: [
Utils.statusContainerChip( Utils.statusContainerChip(
text: (requestDetail.requestStatusName), text: (requestDetail.requestStatusName),
chipColor: MyColors.grey98Color.withOpacity(0.3), chipColor: MyColors.grey98Color.withOpacity(0.1),
textColor: MyColors.lightTextColor, textColor: MyColors.lightTextColor,
), ),
], ],

@ -0,0 +1,197 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
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';
import 'package:mc_common_app/models/user_models/user.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/requests_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_review_containers.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:provider/provider.dart';
class ReviewRequestOffer extends StatelessWidget {
const ReviewRequestOffer({super.key});
Widget buildPersonalInformation() {
UserInfo userInfo = AppState().getUser.data!.userInfo!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.personalInformation.tr().toText(fontSize: 18),
MyAssets.icEdit.buildSvg().onPress(() {}),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: "${userInfo.firstName ?? ""} ${userInfo.lastName ?? ""}", type: LocaleKeys.name.tr()),
16.height,
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: userInfo.email ?? "", type: "${LocaleKeys.email.tr()} / ${LocaleKeys.phone.tr()}"),
16.height,
],
),
),
],
),
],
);
}
Widget buildLocationInformation(BuildContext context) {
// final requestVM = context.read<RequestsVM>();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.locationInformation.tr().toText(fontSize: 18),
MyAssets.icEdit.buildSvg().onPress(() {}),
],
),
8.height,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: "${"Will get from API"} }", type: LocaleKeys.location.tr()),
16.height,
SingleDetailWidget(text: "N/A", type: "${LocaleKeys.email.tr()} / ${LocaleKeys.additionalAddressDetails.tr()}"),
],
),
],
);
}
Widget buildServiceInformation(BuildContext context) {
final requestVM = context.read<RequestsVM>();
String formattedDate = "";
if (requestVM.acceptedRequestOffer!.manufacturedOn != null) {
formattedDate = DateHelper.formatAsDayMonthYear(DateHelper.parseStringToDate(DateHelper.formatDateT(requestVM.acceptedRequestOffer!.manufacturedOn.toString() ?? "")));
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.serviceInformation.tr().toText(fontSize: 18),
MyAssets.icEdit.buildSvg().onPress(() {}),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 6,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleDetailWidget(text: requestVM.currentSelectedRequest!.vehicleTypeName, type: LocaleKeys.vehicleType.tr()),
16.height,
SingleDetailWidget(text: '${requestVM.currentSelectedRequest!.model} ${requestVM.currentSelectedRequest!.year}', type: LocaleKeys.model.tr()),
if (requestVM.acceptedRequestOffer!.manufacturedById != null) ...[
16.height,
SingleDetailWidget(text: (requestVM.acceptedRequestOffer!.manufacturedById ?? "").toString(), type: LocaleKeys.manufacturedBy.tr()),
],
16.height,
SingleDetailWidget(text: "${requestVM.acceptedRequestOffer!.price.toString()} SAR", type: LocaleKeys.offerPrice.tr()),
16.height,
SingleDetailWidget(text: requestVM.acceptedRequestOfferProviderName ?? "", type: LocaleKeys.providerName.tr()),
16.height,
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SingleDetailWidget(text: requestVM.currentSelectedRequest!.brand, type: LocaleKeys.vehicleBrand.tr()),
16.height,
SingleDetailWidget(text: requestVM.acceptedRequestOffer!.serviceItemName ?? "", type: LocaleKeys.serviceName.tr()),
if (formattedDate.isNotEmpty) ...[
16.height,
SingleDetailWidget(text: formattedDate, type: LocaleKeys.manufacturedOn.tr()),
],
16.height,
SingleDetailWidget(text: "${requestVM.currentSelectedRequest!.price.toString()} SAR", type: LocaleKeys.totalPrice.tr()),
],
),
),
],
),
SingleDetailWidget(text: requestVM.currentSelectedRequest!.description, type: LocaleKeys.description.tr()),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: LocaleKeys.offerSummary.tr(),
isRemoveBackButton: false,
isDrawerEnabled: false,
onBackButtonTapped: () => Navigator.pop(context),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
child: Column(
children: [
10.height,
buildPersonalInformation().toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 4)),
10.height,
buildLocationInformation(context).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 4)),
10.height,
buildServiceInformation(context).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 4)),
],
),
).expand(),
ShowFillButton(
maxWidth: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 21),
maxHeight: 55,
title: LocaleKeys.payNow.tr(),
isBold: false,
onPressed: () {
// context.read<PaymentVM>().updateRequestId(id: requestVM.currentSelectedRequest!.id);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.request);
},
),
],
),
);
}
}

@ -53,7 +53,7 @@ class RequestItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
if (request.offerCount > 0 && appType == AppType.customer) ...[ if (request.offerCount > 0 && appType == AppType.customer && request.requestStatus == RequestStatusEnum.submitted) ...[
Center( Center(
child: "${request.offerCount}".toText( child: "${request.offerCount}".toText(
color: Colors.white, color: Colors.white,
@ -77,7 +77,7 @@ class RequestItem extends StatelessWidget {
], ],
), ),
showItem("${LocaleKeys.description.tr()}:", request.description), showItem("${LocaleKeys.description.tr()}:", request.description),
showItem("Price Range: ", ""), showItem("${LocaleKeys.priceRange.tr()}: ", ""),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
@ -85,18 +85,12 @@ class RequestItem extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
request.price.toInt().toString().toText( request.price.toInt().toString().toText(fontSize: 19, color: MyColors.darkTextColor, isBold: true, letterSpacing: -1.16),
fontSize: 19,
color: MyColors.darkTextColor,
isBold: true,
letterSpacing: -1.16
),
2.width, 2.width,
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4).paddingOnly(bottom: 3), LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 10, letterSpacing: -0.4).paddingOnly(bottom: 3),
], ],
), ),
request.requestStatus == RequestStatus.submitted request.requestStatus == RequestStatusEnum.submitted
? SvgPicture.asset( ? SvgPicture.asset(
MyAssets.arrowRight, MyAssets.arrowRight,
height: 9.69, height: 9.69,
@ -109,7 +103,7 @@ class RequestItem extends StatelessWidget {
).toContainer(isShadowEnabled: true).onPress(() async { ).toContainer(isShadowEnabled: true).onPress(() async {
RequestsVM requestsVM = context.read<RequestsVM>(); RequestsVM requestsVM = context.read<RequestsVM>();
requestsVM.updateCurrentSelectedRequest(request); requestsVM.updateCurrentSelectedRequest(request);
if (request.requestStatus == RequestStatus.pending) { if (request.requestStatus == RequestStatusEnum.pending || request.requestStatus == RequestStatusEnum.cancelled) {
return; return;
} }
if (appType == AppType.provider) { if (appType == AppType.provider) {

@ -19,9 +19,9 @@ class RequestStatusChip extends StatelessWidget {
) )
.toContainer( .toContainer(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
backgroundColor: request.requestStatus == RequestStatus.pending backgroundColor: request.requestStatus == RequestStatusEnum.pending
? MyColors.adPendingStatusColor ? MyColors.adPendingStatusColor
: request.requestStatus == RequestStatus.cancelled : request.requestStatus == RequestStatusEnum.cancelled
? MyColors.redColor ? MyColors.redColor
: MyColors.greenColor, : MyColors.greenColor,
borderRadius: 100, borderRadius: 100,

@ -75,12 +75,12 @@ class CircleCheckBoxWithTitle extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
title.toText(fontSize: 14,), title.toText(fontSize: 14),
], ],
), ),
), ),
], ],
).onPress((){ ).onPress(() {
onSelected(); onSelected();
}), }),
); );

Loading…
Cancel
Save