From 841748a41f498968b2eee459165ba77fa5eccc12 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Wed, 4 Dec 2024 22:02:37 +0300 Subject: [PATCH] From MBP --- assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 3 +- lib/generated/codegen_loader.g.dart | 6 +- lib/generated/locale_keys.g.dart | 1 + lib/repositories/appointment_repo.dart | 3 + lib/repositories/branch_repo.dart | 6 +- lib/view_models/ad_view_model.dart | 4 +- lib/view_models/appointments_view_model.dart | 83 +++++++++++++++++-- .../ad_duration_selection_sheet.dart | 18 ++-- .../damage_pictures_bottom_sheet.dart | 2 +- .../appointments_filter_view.dart | 33 ++++++-- .../book_appointment_services_view.dart | 6 +- ...appointment_service_pick_bottom_sheet.dart | 2 +- 13 files changed, 131 insertions(+), 40 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 0dc0ced..d4df718 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -748,5 +748,7 @@ "offerNotMatched": "العرض لم يتطابق مع الطلب.", "offerRejected": "تم رفض العرض.", "offerAccepted": "تم قبول العرض.", - "you": "أنتم" + "you": "أنتم", + "searchByItem": "البحث حسب العنصر" + } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 2f2e648..63b1010 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -746,5 +746,6 @@ "offerNotMatched": "The offer did not match the request.", "offerRejected": "Offer has been Rejected.", "offerAccepted": "Offer has been Accepted.", - "you": "You" + "you": "You", + "searchByItem": "Search By Item" } \ No newline at end of file diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index c62ded1..f3a6bd9 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -764,7 +764,8 @@ class CodegenLoader extends AssetLoader{ "offerNotMatched": "العرض لم يتطابق مع الطلب.", "offerRejected": "تم رفض العرض.", "offerAccepted": "تم قبول العرض.", - "you": "أنتم" + "you": "أنتم", + "searchByItem": "البحث حسب العنصر" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1514,7 +1515,8 @@ static const Map en_US = { "offerNotMatched": "The offer did not match the request.", "offerRejected": "Offer has been Rejected.", "offerAccepted": "Offer has been Accepted.", - "you": "You" + "you": "You", + "searchByItem": "Search By Item" }; 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 4ba56cc..3d4daeb 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -728,5 +728,6 @@ abstract class LocaleKeys { static const offerRejected = 'offerRejected'; static const offerAccepted = 'offerAccepted'; static const you = 'you'; + static const searchByItem = 'searchByItem'; } diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart index f13fb45..cf99abe 100644 --- a/lib/repositories/appointment_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -19,6 +19,7 @@ abstract class AppointmentRepo { List? providerIdsList, List? categoryIdsList, List? serviceIdsList, + List? itemIdsList, List? branchIdsList, }); @@ -223,6 +224,7 @@ class AppointmentRepoImp implements AppointmentRepo { List? providerIdsList, List? categoryIdsList, List? serviceIdsList, + List? itemIdsList, List? branchIdsList, }) async { var params = { @@ -230,6 +232,7 @@ class AppointmentRepoImp implements AppointmentRepo { "ServiceProviderIDs": providerIdsList ?? [], "ProviderBranchIDs": branchIdsList ?? [], "ServiceIDs": serviceIdsList ?? [], + "ServiceItemIDs": itemIdsList ?? [], "CategoryIDs": categoryIdsList ?? [], }; GenericRespModel genericRespModel = await apiClient.getJsonForObject( diff --git a/lib/repositories/branch_repo.dart b/lib/repositories/branch_repo.dart index 2cb2f77..75fec0a 100644 --- a/lib/repositories/branch_repo.dart +++ b/lib/repositories/branch_repo.dart @@ -86,7 +86,7 @@ abstract class BranchRepo { Future> getAllNearBranchAndServices({required double latitude, required double longitude}); - Future> getServiceItems(int serviceId); + Future> getServiceItems({required int serviceId}); Future getBranchAndServicesByProviderId(int providerId, {double? latitude, double? longitude}); @@ -418,7 +418,7 @@ class BranchRepoImp implements BranchRepo { } @override - Future> getServiceItems(int serviceId) async { + Future> getServiceItems({required int serviceId}) async { var queryParameters = { "ServiceProviderServiceID": serviceId.toString(), }; @@ -427,7 +427,7 @@ class BranchRepoImp implements BranchRepo { (json) => GenericRespModel.fromJson(json), ApiConsts.getServiceItems, token: appState.getUser.data!.accessToken, - queryParameters: queryParameters, + queryParameters: serviceId.toString() != "-1" ? queryParameters : null, ); List serviceItems = List.generate(adsGenericModel.data.length, (index) => ItemData.fromJson(adsGenericModel.data[index])); return serviceItems; diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index c54fa50..947df6d 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -223,9 +223,7 @@ class AdVM extends BaseVM { bool isLoadingMore = false; bool hasMoreData = true; - fetchMoreAds() async { - - } + fetchMoreAds() async {} Future> getAdsByFilter({AdPostStatus? adPostStatus, required bool isMyAds, CreatedByRoleEnum? createdByRoleEnum}) async { return await adsRepo.getAllAds(isMyAds: isMyAds, adPostStatus: adPostStatus, createdByRoleEnum: createdByRoleEnum); diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index 7547d28..a908f56 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,6 +1,6 @@ import 'dart:developer'; -import 'package:flutter/cupertino.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; @@ -44,7 +44,6 @@ 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'; class AppointmentsVM extends BaseVM { final CommonRepo commonRepo; @@ -660,10 +659,10 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } - Future> getServiceItems(int serviceId) async { + Future> getServiceItems({required int serviceId}) async { setState(ViewState.busy); serviceItemsFromApi.clear(); - serviceItemsFromApi = await branchRepo.getServiceItems(serviceId); + serviceItemsFromApi = await branchRepo.getServiceItems(serviceId: serviceId); selectedSubServicesCounter = 0; for (var item in serviceItemsFromApi) { if (ifItemAlreadySelected(item.id!)) { @@ -1301,8 +1300,9 @@ class AppointmentsVM extends BaseVM { } List categoryDropList = []; - List servicesDropList = []; List providersDropList = []; + List servicesDropList = []; + List itemsDropList = []; Future fetchAllProviders() async { if (providersDropList.isNotEmpty) return; @@ -1349,10 +1349,30 @@ class AppointmentsVM extends BaseVM { setState(ViewState.idle); } + Future fetchAllItems() async { + if (itemsDropList.isNotEmpty) return; + itemsDropList.clear(); + setState(ViewState.busy); + List itemsList = await branchRepo.getServiceItems(serviceId: -1); // to get all services + + for (ItemData element in itemsList) { + if (element.name != null && element.name!.isNotEmpty) { + itemsDropList.add( + DropValue( + element.id ?? 0, + element.name ?? "", + "", + ), + ); + } + } + setState(ViewState.idle); + } + Future populateDataForBranchesFilter() async { - await fetchAllProviders(); // saudi arabia - await fetchAllCategories(); // saudi arabia - await fetchAllServices(); // saudi arabia + await fetchAllProviders(); + await fetchAllCategories(); + await fetchAllServices(); updateBranchFilterCurrentDistance(25.0); } @@ -1446,6 +1466,7 @@ class AppointmentsVM extends BaseVM { await fetchAllProviders(); await fetchAllCategories(); await fetchAllServices(); + await fetchAllItems(); } int appointmentFiltersCounter = 0; @@ -1621,14 +1642,53 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } + List appointmentFilterItemsSearchHistory = []; + + void removeAppointmentFilterItemsSearchHistory({bool isClear = false, required int index}) { + if (isClear) { + appointmentFilterItemsSearchHistory.clear(); + notifyListeners(); + return; + } + appointmentFilterItemsSearchHistory.removeAt(index); + if (appointmentFilterItemsSearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); + // appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + } + notifyListeners(); + } + + void addAppointmentFilterItemsSearchHistory({required DropValue value}) { + if (appointmentFilterItemsSearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); + } + appointmentFilterItemsSearchHistory.add(value); + notifyListeners(); + } + + SelectionModel appointmentFilterSelectedItemId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + + void updateAppointmentFilterSelectedItemId(SelectionModel id, {bool isForSearch = false}) async { + if (isForSearch) { + DropValue itemsDrop = itemsDropList.firstWhere((element) => element.id == id.selectedId); + if (!ifAlreadyExist(list: appointmentFilterItemsSearchHistory, value: itemsDrop)) { + addAppointmentFilterItemsSearchHistory(value: itemsDrop); + } + } + // appointmentFilterSelectedServiceId = id; + notifyListeners(); + } + void clearAppointmentFilterSelections() { appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + appointmentFilterSelectedItemId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } void clearAppointmentFilters() { + appointmentFilterItemsSearchHistory.clear(); appointmentFilterServicesSearchHistory.clear(); appointmentFilterCategorySearchHistory.clear(); appointmentFilterProviderSearchHistory.clear(); @@ -1659,6 +1719,12 @@ class AppointmentsVM extends BaseVM { servicesIdsList.add(element.id.toString()); } } + List itemIdsList = []; + if (appointmentFilterItemsSearchHistory.isNotEmpty) { + for (var element in appointmentFilterItemsSearchHistory) { + itemIdsList.add(element.id.toString()); + } + } List branchesIdsList = []; if (appointmentFilterBranchSearchHistory.isNotEmpty) { for (var element in appointmentFilterBranchSearchHistory) { @@ -1670,6 +1736,7 @@ class AppointmentsVM extends BaseVM { providerIdsList: providersIdsList, categoryIdsList: categoryIdsList, serviceIdsList: servicesIdsList, + itemIdsList: itemIdsList, branchIdsList: branchesIdsList, ); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); diff --git a/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart b/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart index 7f13c89..f6d224d 100644 --- a/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart +++ b/lib/views/advertisement/bottom_sheets/ad_duration_selection_sheet.dart @@ -1,11 +1,11 @@ import 'dart:developer'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/main.dart'; import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart'; import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; @@ -15,7 +15,6 @@ 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/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; -import 'package:easy_localization/easy_localization.dart'; class AdDurationSelectionSheet extends StatelessWidget { final bool isFromExtendAd; @@ -76,12 +75,15 @@ class AdDurationSelectionSheet extends StatelessWidget { CustomPaint( painter: DiagonalLinePainter(), child: "${adDuration.price}".toText( - fontSize: 16, + fontSize: 20, isBold: true, )), 2.width, - (adDuration.currency ?? LocaleKeys.sar.tr()).toText(fontSize: 8, color: MyColors.lightTextColor, isBold: true), - 10.width, + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: (adDuration.currency ?? LocaleKeys.sar.tr()).toText(fontSize: 10, color: MyColors.lightTextColor, isBold: true), + ), + 14.width, "${adDuration.priceAfterDiscount}".toText(fontSize: 20, isBold: true), 2.width, Padding( @@ -126,7 +128,7 @@ class AdDurationSelectionSheet extends StatelessWidget { SelectionModel( selectedId: adDuration.id ?? 0, selectedOption: ("${adDuration.days} ${LocaleKeys.daysVar.tr()}"), - itemPrice: adDuration.price!.toInt().toString(), + itemPrice: adDuration.priceAfterDiscount!.toInt().toString(), ), ); return; @@ -135,7 +137,7 @@ class AdDurationSelectionSheet extends StatelessWidget { SelectionModel( selectedId: adDuration.id ?? 0, selectedOption: ("${adDuration.days} ${LocaleKeys.daysVar.tr()}"), - itemPrice: adDuration.price!.toString(), + itemPrice: adDuration.priceAfterDiscount!.toString(), currency: adDuration.currency!.toString(), ), ); @@ -200,7 +202,7 @@ class DiagonalLinePainter extends CustomPainter { void paint(Canvas canvas, Size size) { final Paint paint = Paint() ..color = MyColors.redColor - ..strokeWidth = 3; + ..strokeWidth = 2.5; // Draw the diagonal line from top-left to bottom-right canvas.drawLine(const Offset(0, 0), Offset(size.width, size.height), paint); diff --git a/lib/views/advertisement/components/damage_pictures_bottom_sheet.dart b/lib/views/advertisement/components/damage_pictures_bottom_sheet.dart index c3572d2..6e4e55a 100644 --- a/lib/views/advertisement/components/damage_pictures_bottom_sheet.dart +++ b/lib/views/advertisement/components/damage_pictures_bottom_sheet.dart @@ -24,7 +24,7 @@ class _DamagePicturesListState extends State { @override void initState() { super.initState(); - context.read().getServiceItems(widget.serviceId); + context.read().getServiceItems(serviceId: widget.serviceId); } @override diff --git a/lib/views/appointments/appointments_filter_view.dart b/lib/views/appointments/appointments_filter_view.dart index 45b2faf..3523174 100644 --- a/lib/views/appointments/appointments_filter_view.dart +++ b/lib/views/appointments/appointments_filter_view.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; @@ -13,7 +14,6 @@ import 'package:mc_common_app/view_models/appointments_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:easy_localization/easy_localization.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -33,14 +33,14 @@ class _AppointmentsFilterViewState extends State { void initState() { appointmentsVM = context.read(); scheduleMicrotask(() async { - await appointmentsVM.populateDataForBranchesFilter(); + await appointmentsVM.populateDataForAppointmentsFilter(); }); super.initState(); } @override void dispose() { - appointmentsVM.clearBranchFilterSelections(); + appointmentsVM.clearAppointmentFilterSelections(); super.dispose(); } @@ -96,7 +96,7 @@ class _AppointmentsFilterViewState extends State { children: [ SizedBox( height: 5.h, - width: 5.h, + width: 5.h, child: const CircularProgressIndicator(), ), ], @@ -165,6 +165,23 @@ class _AppointmentsFilterViewState extends State { onHistoryItemDeleted: (index) => appointmentsVM.removeAppointmentFilterServicesSearchHistory(index: index), onHistoryItemTapped: (DropValue value) => null, ), + const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + SearchEntityWidget( + title: LocaleKeys.searchByItem.tr(), + actionWidget: Builder(builder: (context) { + return DropdownField( + (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedItemId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + list: appointmentsVM.itemsDropList, + dropdownValue: appointmentsVM.appointmentFilterSelectedItemId.selectedId != -1 + ? DropValue(appointmentsVM.appointmentFilterSelectedItemId.selectedId, appointmentsVM.appointmentFilterSelectedItemId.selectedOption, "") + : null, + hint: LocaleKeys.selectItems.tr(), + ); + }), + historyContent: appointmentsVM.appointmentFilterItemsSearchHistory, + onHistoryItemDeleted: (index) => appointmentsVM.removeAppointmentFilterItemsSearchHistory(index: index), + onHistoryItemTapped: (DropValue value) => null, + ), ], ).expand(), Container( @@ -193,10 +210,10 @@ class _AppointmentsFilterViewState extends State { InkWell( onTap: () => appointmentsVM.clearAppointmentFilters(), child: LocaleKeys.clearFilters.tr().toText( - fontSize: 14, - isBold: true, - color: MyColors.darkPrimaryColor, - ), + fontSize: 14, + isBold: true, + color: MyColors.darkPrimaryColor, + ), ), 10.height, ], diff --git a/lib/views/appointments/book_appointment_services_view.dart b/lib/views/appointments/book_appointment_services_view.dart index eb9c4bc..95d5fea 100644 --- a/lib/views/appointments/book_appointment_services_view.dart +++ b/lib/views/appointments/book_appointment_services_view.dart @@ -1,5 +1,4 @@ -import 'dart:developer'; - +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/routes.dart'; @@ -17,7 +16,6 @@ import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/custom_add_button_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; -import 'package:easy_localization/easy_localization.dart'; class BookAppointmentServicesView extends StatelessWidget { const BookAppointmentServicesView({super.key}); @@ -73,7 +71,7 @@ class BookAppointmentServicesView extends StatelessWidget { itemPrice: "", ), ); - appointmentsVM.getServiceItems(serviceData.serviceProviderServiceId!); + appointmentsVM.getServiceItems(serviceId: serviceData.serviceProviderServiceId!); navigateWithName(context, AppRoutes.bookAppointmentsItemView); }), 10.width, diff --git a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart index 29ed87d..a3d3c1f 100644 --- a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart +++ b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart @@ -238,7 +238,7 @@ class AppointmentServicePickBottomSheet extends StatelessWidget { onPressed: () { bool isValidated = appointmentsVM.isServiceSelectionValidated(); if (isValidated) { - appointmentsVM.getServiceItems(appointmentsVM.branchSelectedServiceId.selectedId); + appointmentsVM.getServiceItems(serviceId: appointmentsVM.branchSelectedServiceId.selectedId); Navigator.pop(context); navigateWithName(context, AppRoutes.bookAppointmentsItemView); }