diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 53f04a9..4de7982 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -736,5 +736,9 @@ "pleaseSelectService": "يرجى اختيار خدمة واحدة على الأقل", "operationalIssue": "مشكلة تشغيلية", "materialIssue": "مشكلة في المواد", - "selectReasonBeforeCancel": "يرجى اختيار سبب قبل إلغاء هذا الموعد. لا يمكن التراجع عن هذا الإجراء." + "selectReasonBeforeCancel": "يرجى اختيار سبب قبل إلغاء هذا الموعد. لا يمكن التراجع عن هذا الإجراء.", + "blockedByAdmin": "تم حظرها من قبل المسؤول", + "active": "نشط", + "paymentType": "نوع الدفع", + "searchByCreatedDate": "البحث حسب تاريخ الإنشاء" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 8839c3c..dc824d2 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -734,5 +734,9 @@ "pleaseSelectService": "Please select at least one service.", "operationalIssue": "Operational Issue", "materialIssue": "Material Issue", - "selectReasonBeforeCancel": "Please select a reason before cancelling this appointment. This action cannot be undone." + "selectReasonBeforeCancel": "Please select a reason before cancelling this appointment. This action cannot be undone.", + "blockedByAdmin": "Blocked by admin", + "active": "Active", + "paymentType": "Payment Type", + "searchByCreatedDate": "Search By Created Date" } \ No newline at end of file diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index a95bb50..674bf8d 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -490,7 +490,7 @@ extension AdPostStatusToInt on AdPostStatus { case AdPostStatus.deActive: return 12; - + case AdPostStatus.pendingForActive: return 13; @@ -642,6 +642,33 @@ extension ServiceEnum on int { } } +extension BranchServiceEnumStatusToInt on ServiceStatusEnum { + int getIdFromServiceStatusEnum() { + switch (this) { + case ServiceStatusEnum.pending: + return 1; + + case ServiceStatusEnum.review: + return 2; + + case ServiceStatusEnum.approvedOrActive: + return 3; + + case ServiceStatusEnum.rejected: + return 4; + + case ServiceStatusEnum.blocked: + return 5; + + case ServiceStatusEnum.deactivated: + return 6; + + default: + return 1; + } + } +} + extension DateTimeConversions on DateTime { String getTimeAgo({bool numericDates = true}) { final date2 = DateTime.now(); diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 17eaa37..4c1e4f7 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -752,7 +752,11 @@ class CodegenLoader extends AssetLoader{ "pleaseSelectService": "يرجى اختيار خدمة واحدة على الأقل", "operationalIssue": "مشكلة تشغيلية", "materialIssue": "مشكلة في المواد", - "selectReasonBeforeCancel": "يرجى اختيار سبب قبل إلغاء هذا الموعد. لا يمكن التراجع عن هذا الإجراء." + "selectReasonBeforeCancel": "يرجى اختيار سبب قبل إلغاء هذا الموعد. لا يمكن التراجع عن هذا الإجراء.", + "blockedByAdmin": "تم حظرها من قبل المسؤول", + "active": "نشط", + "paymentType": "نوع الدفع", + "searchByCreatedDate": "البحث حسب تاريخ الإنشاء" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1490,7 +1494,11 @@ static const Map en_US = { "pleaseSelectService": "Please select at least one service.", "operationalIssue": "Operational Issue", "materialIssue": "Material Issue", - "selectReasonBeforeCancel": "Please select a reason before cancelling this appointment. This action cannot be undone." + "selectReasonBeforeCancel": "Please select a reason before cancelling this appointment. This action cannot be undone.", + "blockedByAdmin": "Blocked by admin", + "active": "Active", + "paymentType": "Payment Type", + "searchByCreatedDate": "Search By Created Date" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 201e3e6..cce5331 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -716,5 +716,9 @@ abstract class LocaleKeys { static const operationalIssue = 'operationalIssue'; static const materialIssue = 'materialIssue'; static const selectReasonBeforeCancel = 'selectReasonBeforeCancel'; + static const blockedByAdmin = 'blockedByAdmin'; + static const active = 'active'; + static const paymentType = 'paymentType'; + static const searchByCreatedDate = 'searchByCreatedDate'; } diff --git a/lib/models/appointments_models/appointment_list_model.dart b/lib/models/appointments_models/appointment_list_model.dart index bb8353f..b31255b 100644 --- a/lib/models/appointments_models/appointment_list_model.dart +++ b/lib/models/appointments_models/appointment_list_model.dart @@ -21,6 +21,10 @@ class AppointmentListModel { String? providerName; String? duration; String? appointmentDate; + String? paymentType; + String? appointmentAddress; + String? appointmentLatitude; + String? appointmentLongitude; String? branchName; int? branchId; int? servicePaymentStatus; @@ -34,7 +38,8 @@ class AppointmentListModel { List? customerAppointmentList; List? mergeAppointmentList; - AppointmentListModel({this.id, + AppointmentListModel({ + this.id, this.serviceSlotID, this.appointmentStatusID, this.appointmentStatusText, @@ -49,7 +54,10 @@ class AppointmentListModel { this.appointmentType, this.appointmentTypeEnum, this.providerName, - this.duration, + this.paymentType, + this.appointmentAddress, + this.appointmentLatitude, + this.appointmentLongitude, this.branchName, this.branchId, this.servicePaymentStatus, @@ -58,7 +66,9 @@ class AppointmentListModel { this.isSelected, this.appointmentDate, this.appointmentServicesList, - this.customerAppointmentList, this.mergeAppointmentList,}); + this.customerAppointmentList, + this.mergeAppointmentList, + }); @override String toString() { @@ -83,28 +93,25 @@ class AppointmentListModel { providerName = json['providerName']; duration = json['duration']; appointmentDate = json['appointmentDate']; + paymentType = json['paymentType']; + appointmentAddress = json['address'] ?? ""; + appointmentLatitude = json['branchLatitude']; + appointmentLongitude = json['branchLongitude']; branchName = json['branchName']; branchId = json['branchID']; servicePaymentStatus = json['servicePaymentStatus']; totalAmount = json['amountTotal']; remainingAmount = json['amountRem']; isSelected = false; - appointmentStatusEnum = - (json['appointmentStatusID'] as int).toAppointmentStatusEnum(); - appointmentPaymentStatusEnum = - (json['servicePaymentStatus'] as int).toAppointmentPaymentStatusEnum(); - + appointmentStatusEnum = (json['appointmentStatusID'] as int).toAppointmentStatusEnum(); + appointmentPaymentStatusEnum = (json['servicePaymentStatus'] as int).toAppointmentPaymentStatusEnum(); if (json['serviceList'] != null) { appointmentServicesList = []; json['serviceList'].forEach((v) { - appointmentServicesList! - .add(ServiceModel.fromJson(v, isForAppointment: true)); + appointmentServicesList!.add(ServiceModel.fromJson(v, isForAppointment: true)); }); } - mergeAppointmentList = - json["mergeAppointmentList"] == null ? [] : List.from( - json["mergeAppointmentList"]!.map((x) => - MergeAppointmentList.fromJson(x))); + mergeAppointmentList = json["mergeAppointmentList"] == null ? [] : List.from(json["mergeAppointmentList"]!.map((x) => MergeAppointmentList.fromJson(x))); } } @@ -114,10 +121,7 @@ class ServiceAppointmentItems { String? serviceItemName; String? serviceItemDescription; - ServiceAppointmentItems({this.id, - this.serviceItemID, - this.serviceItemName, - this.serviceItemDescription}); + ServiceAppointmentItems({this.id, this.serviceItemID, this.serviceItemName, this.serviceItemDescription}); ServiceAppointmentItems.fromJson(Map json) { id = json['id']; @@ -142,12 +146,9 @@ class CustomerData { final String customerName; final List appointmentList; - CustomerData({required this.customerID, - required this.customerName, - required this.appointmentList}); + CustomerData({required this.customerID, required this.customerName, required this.appointmentList}); } - class MergeAppointmentList { int? id; int? mergeAppointmentId; @@ -159,17 +160,15 @@ class MergeAppointmentList { this.serviceAppointmentId, }); - factory MergeAppointmentList.fromJson(Map json) => - MergeAppointmentList( + factory MergeAppointmentList.fromJson(Map json) => MergeAppointmentList( id: json["id"], mergeAppointmentId: json["mergeAppointmentID"], serviceAppointmentId: json["serviceAppointmentID"], ); - Map toJson() => - { + Map toJson() => { "id": id, "mergeAppointmentID": mergeAppointmentId, "serviceAppointmentID": serviceAppointmentId, }; -} \ No newline at end of file +} diff --git a/lib/models/services_models/service_model.dart b/lib/models/services_models/service_model.dart index ea06c99..fcc54f7 100644 --- a/lib/models/services_models/service_model.dart +++ b/lib/models/services_models/service_model.dart @@ -1,5 +1,6 @@ +import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/services_models/item_model.dart'; -import 'package:mc_common_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/utils/enums.dart'; class ServiceModel { final int? serviceProviderServiceId; @@ -10,6 +11,7 @@ class ServiceModel { final String? serviceDescription; final String? serviceDescriptionN; final int? serviceStatus; + final ServiceStatusEnum? serviceStatusEnum; final dynamic statusText; final bool? isAllowAppointment; final bool? isAllowAppointmentHome; @@ -23,6 +25,7 @@ class ServiceModel { bool isHomeSelected; double currentTotalServicePrice; CurrentLocationInfoModel servicelocationInfo; + bool isActive; ServiceModel({ this.serviceProviderServiceId, @@ -33,6 +36,7 @@ class ServiceModel { this.serviceDescription, this.serviceDescriptionN, this.serviceStatus, + this.serviceStatusEnum, this.statusText, this.isAllowAppointment, this.isAllowAppointmentHome, @@ -42,6 +46,7 @@ class ServiceModel { this.serviceItems, this.isHomeSelected = false, this.currentTotalServicePrice = 0.0, + this.isActive = true, required this.isExpandedOrSelected, required this.providerServiceId, required this.providerServiceName, @@ -57,6 +62,7 @@ class ServiceModel { serviceDescription: json["serviceDescription"] ?? json["serviceName"], serviceDescriptionN: json["serviceDescriptionN"] ?? json["serviceNameN"], serviceStatus: json["serviceStatus"], + serviceStatusEnum: ((json["serviceStatus"] ?? 0) as int).toServiceStatusEnum(), statusText: json["statusText"], isAllowAppointment: json["isAllowAppointment"], isAllowAppointmentHome: json["isAllowAppointmentHome"], @@ -74,6 +80,7 @@ class ServiceModel { providerServiceId: 0, providerServiceName: "", isHomeSelected: false, + isActive: json["isActive"] ?? true, servicelocationInfo: CurrentLocationInfoModel(address: '', distanceToBranch: 0.0, homeChargesInCurrentService: 0.0, latitude: 0.0, longitude: 0.0), ); diff --git a/lib/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index 79f12d8..a76b314 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -24,7 +24,14 @@ abstract class AdsRepo { Future> getAllAds({required bool isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum}); - Future> getExploreAdsBasedOnFilters({List? cityIdsList, List? vehicleModelYearIdsList, List? vehicleBrandIdsList, List? createdByRolesIdsList}); + Future> getExploreAdsBasedOnFilters({ + List? cityIdsList, + List? vehicleModelYearIdsList, + List? vehicleBrandIdsList, + List? createdByRolesIdsList, + List? vehicleAdConditionIdsList, + List? vehicleAdCreatedDateList, + }); Future> getMyReservedAds(); @@ -60,7 +67,7 @@ class AdsRepoImp implements AdsRepo { }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), queryParameters: param, ApiConsts.vehicleAdsDurationGet, ); @@ -74,7 +81,7 @@ class AdsRepoImp implements AdsRepo { "SpecialServiceType": specialServiceType.toString(), }; GenericRespModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSpecialServicesGet, queryParameters: params); + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSpecialServicesGet, queryParameters: params); List vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index])); return vehicleAdsDuration; } @@ -149,7 +156,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), isCreateNew ? ApiConsts.vehicleAdsSingleStepCreate : ApiConsts.vehicleAdsSingleStepUpdate, postParams, token: token, @@ -183,7 +190,7 @@ class AdsRepoImp implements AdsRepo { } GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsGet, queryParameters: isMyAds ? onlyMyAdsParams : allAdsParams, ); @@ -197,6 +204,8 @@ class AdsRepoImp implements AdsRepo { List? vehicleModelYearIdsList, List? vehicleBrandIdsList, List? createdByRolesIdsList, + List? vehicleAdConditionIdsList, + List? vehicleAdCreatedDateList, }) async { var parameters = { "CityIDs": cityIdsList ?? [], @@ -204,6 +213,10 @@ class AdsRepoImp implements AdsRepo { "VehicleModelYearIDs": vehicleModelYearIdsList ?? [], "CreatedByRoles": createdByRolesIdsList ?? [], "AdsStatuses": ["${AdPostStatus.active.getIdFromAdPostStatusEnum()}"], //only Active ADS + + // TODO: This has to be converted into list + "VehicleNew": (vehicleAdConditionIdsList != null && vehicleAdConditionIdsList.isNotEmpty) ? vehicleAdConditionIdsList.first.toString() : "", + "CreatedOn": (vehicleAdCreatedDateList != null && vehicleAdCreatedDateList.isNotEmpty) ? vehicleAdCreatedDateList.first.toString() : "", "isActive": "true", //only Active ADS "isExplore": "true", "PageSize": "30", @@ -211,7 +224,7 @@ class AdsRepoImp implements AdsRepo { GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsGet, queryParameters: parameters, ); @@ -227,7 +240,7 @@ class AdsRepoImp implements AdsRepo { GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.myAdsReserveGet, queryParameters: params, ); @@ -249,7 +262,7 @@ class AdsRepoImp implements AdsRepo { }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), queryParameters: params, ApiConsts.vehicleAdsGet, ); @@ -271,7 +284,7 @@ class AdsRepoImp implements AdsRepo { }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), queryParameters: params, ApiConsts.vehicleAdsGet, ); @@ -287,7 +300,7 @@ class AdsRepoImp implements AdsRepo { }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), queryParameters: params, ApiConsts.adsMCBankAccountAdGet, ); @@ -309,7 +322,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.adsUpdateStatus, postParams, token: token, @@ -328,7 +341,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.adsExtendDurationCreate, postParams, token: token, @@ -345,7 +358,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.deleteAd, postParams, token: token, @@ -367,7 +380,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.deleteAd, postParams, token: token, @@ -388,7 +401,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.adsReserveCreate, postParams, token: token, @@ -416,7 +429,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.adsPhotoOfficeAppointmentCreate, postParams, token: token, @@ -449,7 +462,7 @@ class AdsRepoImp implements AdsRepo { String token = appState.getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.adsPhotoOfficeAppointmentCreate, postParams, token: token, @@ -462,7 +475,7 @@ class AdsRepoImp implements AdsRepo { Future> getChatBuyersForAds({required int adsID}) async { var queryParameters = {"AdsID": adsID.toString()}; GenericRespModel genericRespModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getChatBuyersForAds, queryParameters: queryParameters, token: appState.getUser.data!.accessToken, diff --git a/lib/utils/enums.dart b/lib/utils/enums.dart index f168af0..38cb1f9 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -11,6 +11,7 @@ class AppEnums { static const int requestFilterEnumId = 16; // Requests Filter Enums + static const int branchServicesEnumId = 6; // Branch Services Filter Enums static const int myAdsFilterEnumId = 18; // My Ads Filter Enums static const int exploreAdsFilterEnumId = 23; // Explore Ads Filter Enums static const int appointmentsFilterEnumId = 13; // Appointments Filter Enums @@ -136,6 +137,7 @@ enum ServiceStatusEnum { rejected, //4 blocked, //5 deactivated, //6 + allServices, //0 } enum DocumentStatusEnum { diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 040f778..bffe45d 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -364,7 +364,7 @@ class Utils { return MyColors.adCancelledStatusColor; case BranchStatusEnum.blocked: - return MyColors.adPendingStatusColor; + return MyColors.expiredColor; case BranchStatusEnum.approvedOrActive: return MyColors.greenColor; diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index d46b5a4..76b0f09 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -114,10 +114,7 @@ class AdVM extends BaseVM { } void removeSpecialServiceCard(int index) { - String option = specialServiceCards - .elementAt(index) - .serviceSelectedId! - .selectedOption; + String option = specialServiceCards.elementAt(index).serviceSelectedId!.selectedOption; for (var value in vehicleAdsSpecialServices) { if (value.name == option) { @@ -550,8 +547,17 @@ class AdVM extends BaseVM { SelectionModel vehicleConditionId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - void updateSelectionVehicleConditionId(SelectionModel id) { - vehicleConditionId = id; + void updateSelectionVehicleConditionId(SelectionModel id, {bool showSelectionInDropdown = true, bool isForSearch = false}) { + if (isForSearch) { + EnumsModel owner = vehicleConditionsEnum.firstWhere((element) => element.enumValue == id.selectedId); + DropValue ownerValue = DropValue(owner.enumValue, owner.enumValueStr, ""); + if (!ifAlreadyExist(list: vehicleAdConditionSearchHistory, value: ownerValue)) { + addToVehicleAdConditionSearchHistory(value: ownerValue); + } + } + if (showSelectionInDropdown) { + vehicleConditionId = id; + } notifyListeners(); } @@ -1249,10 +1255,7 @@ class AdVM extends BaseVM { } void removeDamagePartCard(int index) { - String option = vehicleDamageCards - .elementAt(index) - .partSelectedId! - .selectedOption; + String option = vehicleDamageCards.elementAt(index).partSelectedId!.selectedOption; for (var value in vehicleDamageParts) { if (value.partName == option) { @@ -1530,9 +1533,7 @@ class AdVM extends BaseVM { File file = File(imageModel.filePath!); List imageBytes = await file.readAsBytes(); String image = base64Encode(imageBytes); - String fileName = file.path - .split('/') - .last; + String fileName = file.path.split('/').last; vehiclePostingImages = VehiclePostingImages( imageName: fileName, imageStr: image, @@ -1567,8 +1568,15 @@ class AdVM extends BaseVM { // ************ ADS SEARCH VIEW **************** + List vehicleConditionsEnum = []; + Future populateDataForAdFilter() async { setState(ViewState.busy); + + if (vehicleConditionsEnum.isEmpty) { + vehicleConditionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.conditionEnumId); + } + if (vehicleBrands.isEmpty) { vehicleBrands = await commonRepo.getVehicleBrands(vehicleTypeId: -1); } @@ -1704,6 +1712,55 @@ class AdVM extends BaseVM { notifyListeners(); } + // Created Date + + List vehicleAdCreatedDateSearchHistory = []; + + void removeVehicleAdCreatedDateSearchHistory({bool isClear = false, required int index}) { + if (isClear) { + vehicleAdCreatedDateSearchHistory.clear(); + notifyListeners(); + return; + } + vehicleAdCreatedDateSearchHistory.removeAt(index); + if (vehicleAdCreatedDateSearchHistory.isEmpty) { + updateAdsFiltersCounter(adsFiltersCounter - 1); + } + notifyListeners(); + } + + void addToVehicleAdCreatedDateSearchHistory({required DropValue value}) { + if (vehicleAdCreatedDateSearchHistory.isEmpty) { + updateAdsFiltersCounter(adsFiltersCounter + 1); + } + vehicleAdCreatedDateSearchHistory.add(value); + notifyListeners(); + } + + // Ad Condition + List vehicleAdConditionSearchHistory = []; + + void removeVehicleAdConditionSearchHistory({bool isClear = false, required int index}) { + if (isClear) { + vehicleAdConditionSearchHistory.clear(); + notifyListeners(); + return; + } + vehicleAdConditionSearchHistory.removeAt(index); + if (vehicleAdConditionSearchHistory.isEmpty) { + updateAdsFiltersCounter(adsFiltersCounter - 1); + } + notifyListeners(); + } + + void addToVehicleAdConditionSearchHistory({required DropValue value}) { + if (vehicleAdConditionSearchHistory.isEmpty) { + updateAdsFiltersCounter(adsFiltersCounter + 1); + } + vehicleAdConditionSearchHistory.add(value); + notifyListeners(); + } + int adsFiltersCounter = 0; updateAdsFiltersCounter(int value) { @@ -1716,6 +1773,8 @@ class AdVM extends BaseVM { vehicleAdOwnerSearchHistory.clear(); vehicleLocationAdSearchHistory.clear(); vehicleYearAdSearchHistory.clear(); + vehicleAdCreatedDateSearchHistory.clear(); + vehicleAdConditionSearchHistory.clear(); adsFiltersCounter = 0; getExploreAds(); notifyListeners(); @@ -1758,11 +1817,27 @@ class AdVM extends BaseVM { } } + List conditionsIdsList = []; + if (vehicleAdConditionSearchHistory.isNotEmpty) { + for (var element in vehicleAdConditionSearchHistory) { + conditionsIdsList.add(element.id.toString()); + } + } + + List createdDatesList = []; + if (vehicleAdCreatedDateSearchHistory.isNotEmpty) { + for (var element in vehicleAdCreatedDateSearchHistory) { + createdDatesList.add(element.value.toString()); + } + } + exploreAdsFilteredList = await adsRepo.getExploreAdsBasedOnFilters( cityIdsList: cityIdsList, createdByRolesIdsList: adOwnerIdsList, vehicleBrandIdsList: brandsIdsList, vehicleModelYearIdsList: vehicleYearIdsList, + vehicleAdConditionIdsList: conditionsIdsList, + vehicleAdCreatedDateList: createdDatesList, ); setState(ViewState.idle); } @@ -1953,13 +2028,13 @@ class AdVM extends BaseVM { final chatVM = context.read(); await chatVM .getUsersChatMessagesForAd( - context: context, - isForBuyer: true, - adsChatBuyerId: 1, - adID: adDetailsModel.id, - userID: myUserID, - senderName: adDetailsModel.adOwnerName, - ) + context: context, + isForBuyer: true, + adsChatBuyerId: 1, + adID: adDetailsModel.id, + userID: myUserID, + senderName: adDetailsModel.adOwnerName, + ) .whenComplete(() => navigateWithName(context, AppRoutes.chatView, arguments: chatViewArguments)); } } diff --git a/lib/view_models/dashboard_view_model_provider.dart b/lib/view_models/dashboard_view_model_provider.dart index 8d4e0ad..afc0755 100644 --- a/lib/view_models/dashboard_view_model_provider.dart +++ b/lib/view_models/dashboard_view_model_provider.dart @@ -82,6 +82,7 @@ class DashboardVMProvider extends BaseVM { appointmentVM.populateAppointmentsFilterList(); shippingManagementVM.populateShippingRequestFilterList(); await serviceVM.getBranchAndServices(); + await serviceVM.populateBranchServiceFilters(); await appointmentVM.getMyAppointmentsForProvider({"ServiceProviderID": injector.get().getUser.data?.userInfo?.providerId.toString() ?? "0"}); adVM.populateAdsFilterList(); await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index d209bc4..079cd9a 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -46,6 +46,7 @@ class RequestsVM extends BaseVM { List myRequestsTypeEnum = []; List vehicleConditionsEnum = []; + List requestStatusesEnum = []; RequestModel? currentSelectedRequest; diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index 43c3eb0..1068494 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -6,8 +6,11 @@ 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/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/general_models/enums_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; +import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart'; import 'package:mc_common_app/models/provider_branches_models/profile/document.dart'; @@ -176,6 +179,31 @@ class ServiceVM extends BaseVM { notifyListeners(); } + List branchServiceEnums = []; + + populateBranchServiceFilters() async { + if (branchServiceEnums.isEmpty) { + branchServiceEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.branchServicesEnumId); + } + + branchServicesFilterOptions.clear(); + for (int i = 0; i < branchServiceEnums.length; i++) { + branchServicesFilterOptions.add(FilterListModel(title: branchServiceEnums[i].enumValueStr, isSelected: false, id: branchServiceEnums[i].enumValue)); + } + } + + List branchServicesFilterOptions = []; + + applyFilterOnBranchServices({required ServiceStatusEnum serviceStatusEnum}) async { + if (branchServicesFilterOptions.isEmpty) return; + for (var value in branchServicesFilterOptions) { + value.isSelected = false; + } + + branchServicesFilterOptions[serviceStatusEnum.getIdFromServiceStatusEnum() - 1].isSelected = true; // -1 to match with the index + + } + // Future selectFile(BuildContext context, int index) async { // final status = await AppPermissions.checkStoragePermissions(context); // if (status) { @@ -236,7 +264,11 @@ class ServiceVM extends BaseVM { context, allowMultiple: false, ); - if (files != null && files.any((element) => element.path.split('.').last.toLowerCase() != 'pdf')) { + if (files != null && files.any((element) => + element.path + .split('.') + .last + .toLowerCase() != 'pdf')) { Utils.showToast("Only PDF Files are allowed"); return; } @@ -250,8 +282,8 @@ class ServiceVM extends BaseVM { documentID == 1 ? commerceCertificates.addAll(imageModels) : documentID == 2 - ? commercialCertificates.addAll(imageModels) - : vatCertificates.addAll(imageModels); + ? commercialCertificates.addAll(imageModels) + : vatCertificates.addAll(imageModels); document!.data![index].document = Utils.convertFileToBase64(files.first); document!.data![index].fileExt = Utils.checkFileExt(files.first.path); document!.data![index].documentUrl = files.first.path; @@ -427,10 +459,10 @@ class ServiceVM extends BaseVM { DropValue( element.id ?? 0, ((element.categoryName!.isEmpty - ? "N/A" - : countryCode == "SA" - ? element.categoryNameN - : element.categoryName) ?? + ? "N/A" + : countryCode == "SA" + ? element.categoryNameN + : element.categoryName) ?? "N/A"), "", ), @@ -625,7 +657,9 @@ class ServiceVM extends BaseVM { File file = File(imageModel.filePath!); List imageBytes = await file.readAsBytes(); String image = base64Encode(imageBytes); - String fileName = file.path.split('/').last; + String fileName = file.path + .split('/') + .last; branchPostingImages = BranchPostingImages( imageName: fileName, imageStr: image, diff --git a/lib/views/advertisement/ads_filter_view.dart b/lib/views/advertisement/ads_filter_view.dart index 1c3ae8a..705ccc0 100644 --- a/lib/views/advertisement/ads_filter_view.dart +++ b/lib/views/advertisement/ads_filter_view.dart @@ -9,12 +9,14 @@ import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/ad_view_model.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/search_entity_widget.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:provider/provider.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -134,22 +136,45 @@ class _AdsFilterViewState extends State { ), const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7), SearchEntityWidget( - title: LocaleKeys.searchByAdOwner.tr(), - actionWidget: Builder(builder: (context) { - List vehicleOwnerDrop = []; - for (var element in adVM.exploreAdsEnums) { - vehicleOwnerDrop.add(DropValue(element.enumValue.toInt(), "${element.enumValueStr} Ads", "")); - } - return DropdownField( - (DropValue value) => adVM.updateSelectionVehicleAdOwnerId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - list: vehicleOwnerDrop, - dropdownValue: adVM.vehicleOwnerId.selectedId != -1 ? DropValue(adVM.vehicleOwnerId.selectedId, adVM.vehicleOwnerId.selectedOption, "") : null, - hint: LocaleKeys.selectOwner.tr(), - errorValue: adVM.vehicleOwnerId.errorValue, - ); - }), - historyContent: adVM.vehicleAdOwnerSearchHistory, - onHistoryItemDeleted: (index) => adVM.removeVehicleAdOwnerSearchHistory(index: index), + title: LocaleKeys.searchByCondition.tr(), + actionWidget: Builder( + builder: (context) { + List vehicleOwnerDrop = []; + for (var element in adVM.vehicleConditionsEnum) { + vehicleOwnerDrop.add(DropValue(element.id.toInt(), element.enumValueStr, "")); + } + return DropdownField( + (DropValue value) => + adVM.updateSelectionVehicleConditionId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true, showSelectionInDropdown: false), + list: vehicleOwnerDrop, + dropdownValue: adVM.vehicleConditionId.selectedId != -1 ? DropValue(adVM.vehicleConditionId.selectedId, adVM.vehicleConditionId.selectedOption, "") : null, + hint: LocaleKeys.selectCondition.tr(), + errorValue: adVM.vehicleConditionId.errorValue, + ); + }, + ), + historyContent: adVM.vehicleAdConditionSearchHistory, + onHistoryItemDeleted: (index) => adVM.removeVehicleAdConditionSearchHistory(index: index), + onHistoryItemTapped: (DropValue value) => null, + ), + const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7), + SearchEntityWidget( + title: LocaleKeys.searchByCreatedDate.tr(), + actionWidget: TxtField( + isNeedBorder: true, + hint: LocaleKeys.createdOn.tr(), + value: adVM.vehicleAdDurationId.selectedOption, + isNeedClickAll: true, + postFixDataColor: MyColors.darkTextColor, + onTap: () async { + final formattedDate = await Utils.pickDateFromDatePicker(context); + adVM.updateSelectionDurationStartDate(formattedDate); + DropValue value = DropValue(0, formattedDate, ""); + adVM.addToVehicleAdCreatedDateSearchHistory(value: value); + }, + ), + historyContent: adVM.vehicleAdCreatedDateSearchHistory, + onHistoryItemDeleted: (index) => adVM.removeVehicleAdCreatedDateSearchHistory(index: index), onHistoryItemTapped: (DropValue value) => null, ) ], diff --git a/lib/views/common_fragments/ads_fragment.dart b/lib/views/common_fragments/ads_fragment.dart index 4ae6c88..0a61fa2 100644 --- a/lib/views/common_fragments/ads_fragment.dart +++ b/lib/views/common_fragments/ads_fragment.dart @@ -78,7 +78,6 @@ class AdsFragment extends StatelessWidget { txtColor: adVM.isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor, onPressed: () { print("accessToken: ${AppState().getUser.data!.accessToken}"); - adVM.populateAdsFilterList(); if (adVM.myAds.isEmpty) { adVM.getMyAds(); } @@ -135,9 +134,7 @@ class AdsFragment extends StatelessWidget { } }, child: adVM.state == ViewState.busy - ? const Center( - child: CircularProgressIndicator(), - ) + ? const Center(child: CircularProgressIndicator()) : AdsListWidget(isAdsFragment: true, shouldShowAdStatus: !adVM.isExploreAdsTapped, adsList: getAdsList(adVM)), ), ) diff --git a/lib/views/setting_options/setting_options_contact_us.dart b/lib/views/setting_options/setting_options_contact_us.dart index 817c3de..b30b99b 100644 --- a/lib/views/setting_options/setting_options_contact_us.dart +++ b/lib/views/setting_options/setting_options_contact_us.dart @@ -90,13 +90,15 @@ class _SettingOptionsContactUsState extends State { padding: const EdgeInsets.all(16), itemBuilder: (context, index) { ContactInfoModel contactInfoModel = settingsOptionsVM.contactInfosList[index]; - return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ contactInfoModel.companyName.toString().toText(fontSize: 16), 5.height, - if (contactInfoModel.latitude != null && contactInfoModel.latitude!.isNotEmpty && contactInfoModel.longitude != null && contactInfoModel.longitude!.isNotEmpty) ...[ + if (contactInfoModel.latitude != null && + contactInfoModel.latitude!.isNotEmpty && + contactInfoModel.longitude != null && + contactInfoModel.longitude!.isNotEmpty) ...[ LocaleKeys.openMapLocation.tr().toText(isUnderLine: true, color: MyColors.darkPrimaryColor, fontSize: 10).onPress(() async { double latitude, longitude = 0.0; latitude = double.parse(contactInfoModel.latitude!); diff --git a/lib/widgets/checkbox_with_title_desc.dart b/lib/widgets/checkbox_with_title_desc.dart index 4cf774d..73a9a2a 100644 --- a/lib/widgets/checkbox_with_title_desc.dart +++ b/lib/widgets/checkbox_with_title_desc.dart @@ -8,8 +8,16 @@ class CheckBoxWithTitleDescription extends StatelessWidget { final bool isSelected; final String title, description; final Function(bool) onSelection; + final bool isDisabled; - const CheckBoxWithTitleDescription({required this.isSelected, required this.title, required this.description, required this.onSelection, Key? key}) : super(key: key); + const CheckBoxWithTitleDescription({ + required this.isSelected, + required this.title, + required this.description, + required this.onSelection, + this.isDisabled = false, + super.key, + }); @override Widget build(BuildContext context) { @@ -21,7 +29,9 @@ class CheckBoxWithTitleDescription extends StatelessWidget { children: [ Checkbox( value: isSelected, + activeColor: isDisabled ? MyColors.lightIconColor : MyColors.darkPrimaryColor, onChanged: (bool? v) { + if (isDisabled) return; onSelection(v ?? false); }, ),