import 'dart:developer'; import 'package:flutter/material.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/main.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/appointments_models/appointment_slots.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.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/m_response.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/branch_review_model.dart'; import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart'; import 'package:mc_common_app/models/provider_branches_models/profile/services.dart'; import 'package:mc_common_app/models/provider_branches_models/provider_model.dart'; import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart'; import 'package:mc_common_app/models/services_models/item_model.dart'; import 'package:mc_common_app/models/services_models/service_model.dart'; import 'package:mc_common_app/repositories/appointment_repo.dart'; import 'package:mc_common_app/repositories/branch_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/base_view_model.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart'; import 'package:mc_common_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart'; import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.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'; import 'package:easy_localization/easy_localization.dart'; class AppointmentsVM extends BaseVM { final CommonRepo commonRepo; final CommonAppServices commonServices; final BranchRepo branchRepo; final AppointmentRepo appointmentRepo; AppointmentsVM({required this.commonServices, required this.appointmentRepo, required this.commonRepo, required this.branchRepo}); bool isUpcommingEnabled = true; bool isFetchingLists = false; int selectedBranch = 0; int selectedAppointmentIndex = 0; int selectedAppointmentSubIndex = 0; int selectedAppointmentId = 0; List myAppointments = []; List myUpComingAppointments = []; List myFilteredAppointments = []; List appointmentsFilterOptions = []; List customersAppointments = []; List myFilteredAppointments2 = []; // List availableSchedules = []; bool isFetchingServices = false; List branchCategories = []; bool isHomeTapped = false; bool isShowEmptyMessage = false; List serviceAppointmentScheduleList = []; bool ifItemAlreadySelected(int id) { int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id); if (indexFound != -1) { return true; } return false; } List allSelectedItemsInAppointments = []; // setupProviderAppointmentFilter() { // appointmentsFilterOptions.clear(); // appointmentsFilterOptions.add(FilterListModel(id: 0, title: "All Appointments", isSelected: true)); // appointmentsFilterOptions.add(FilterListModel(id: 2, title: "Confirmed", isSelected: false)); // appointmentsFilterOptions.add(FilterListModel(id: 3, title: "Arrived", isSelected: false)); // appointmentsFilterOptions.add(FilterListModel(id: 7, title: "Work In Progress", isSelected: false)); // appointmentsFilterOptions.add(FilterListModel(id: 8, title: "Completed", isSelected: false)); // appointmentsFilterOptions.add(FilterListModel(id: 4, title: "Canceled", isSelected: false)); // } Future onItemsSelectedInService() async { if (currentServiceSelection != null) { int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); if (index == -1) { double totalPrice = 0.0; for (var element in currentServiceSelection!.serviceItems!) { totalPrice = totalPrice + double.parse(element.price ?? "0.0"); } currentServiceSelection!.currentTotalServicePrice = totalPrice; servicesInCurrentAppointment.insert(0, currentServiceSelection!); } resetCategorySelectionBottomSheet(); notifyListeners(); } } Future onPayNowPressedForAppointment({required BuildContext context, required int appointmentID}) async { context.read().updateAppointmentIdsForPayment(ids: [appointmentID]); navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.partialAppointment); } Future onBookAppointmentPressed(BuildContext context) async { Utils.showLoading(context); bool isSuccess = false; List appointmentIdsList = []; try { GenericRespModel genericRespModel = await appointmentRepo.createServiceAppointment( schedules: serviceAppointmentScheduleList, serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0, ); if (genericRespModel.data.isEmpty) { Utils.hideLoading(context); Utils.showToast("${genericRespModel.message.toString()}"); return; } if (genericRespModel.data != null && genericRespModel.data.isNotEmpty) { genericRespModel.data.forEach((element) { if (element['appointmentID'] != 0) { appointmentIdsList.add(element['appointmentID']); isSuccess = true; } else { isSuccess = false; Utils.showToast(element['message']); return; } }); } context.read().onNavbarTapped(1); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked); Utils.hideLoading(context); resetAfterBookingAppointment(); if (isSuccess) { if (amountToPayForAppointment > 0) { context.read().updateAppointmentIdsForPayment(ids: appointmentIdsList); navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment); } else { Utils.showToast(LocaleKeys.appointmentBookedSuccessfully.tr()); getMyAppointments(); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); } } } catch (e) { Utils.showToast(e.toString()); } } Future onConfirmAppointmentPressed({required BuildContext context, required appointmentId}) async { context.read().updateAppointmentIdsForPayment(ids: [appointmentId]); navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment); } Future onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async { Utils.showLoading(context); try { GenericRespModel genericRespModel = await appointmentRepo.cancelOrRescheduleServiceAppointment( serviceAppointmentID: appointmentListModel.id ?? 0, serviceSlotID: appointmentListModel.serviceSlotID ?? 0, appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel ); if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) { Utils.hideLoading(context); Utils.showToast("${genericRespModel.message.toString()}"); return; } if (genericRespModel.messageStatus == 1) { context.read().onNavbarTapped(1); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled); Utils.showToast("${genericRespModel.message.toString()}"); await getMyAppointments(); Utils.hideLoading(context); getMyAppointments(); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); } } catch (e) { Utils.showToast("${e.toString()}"); } } void updateIsHomeTapped(bool value) { isHomeTapped = value; if (currentServiceSelection != null) { currentServiceSelection!.isHomeSelected = value; } notifyListeners(); } String pickedHomeLocation = ""; void updatePickedHomeLocation(String value) { pickedHomeLocation = value; pickHomeLocationError = ""; if (currentServiceSelection != null) { currentServiceSelection!.homeLocation = value; } notifyListeners(); } SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateProviderCategoryId(SelectionModel id) { branchSelectedCategoryId = id; getBranchServices(categoryId: branchSelectedCategoryId.selectedId); notifyListeners(); } List branchesFilterOptions = []; List servicesInCurrentAppointment = []; ServiceModel? currentServiceSelection; void updateBranchServiceId(SelectionModel id) async { branchSelectedServiceId = id; currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId); notifyListeners(); } void removeServiceInCurrentAppointment(int index) { int serviceId = servicesInCurrentAppointment .elementAt(index) .serviceProviderServiceId ?? -1; allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId); servicesInCurrentAppointment.removeAt(index); notifyListeners(); } resetCategorySelectionBottomSheet() { selectedSubServicesCounter = 0; branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); isHomeTapped = false; branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); currentServiceSelection = null; } resetAfterBookingAppointment() { // allSelectedItemsInAppointments.clear(); servicesInCurrentAppointment.clear(); // serviceAppointmentScheduleList.clear(); } List myAppointmentsEnum = []; Future populateAppointmentsFilterList() async { if (appointmentsFilterOptions.isNotEmpty) return; myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); // 13 is to get Appointments Filter Enums for (int i = 0; i < myAppointmentsEnum.length; i++) { appointmentsFilterOptions.add(FilterListModel(title: myAppointmentsEnum[i].enumValueStr, isSelected: false, id: myAppointmentsEnum[i].enumValue)); } appointmentsFilterOptions.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0)); // TODO: THIS SHOULD REMOVED AND ADDED IN THE ENUMS API appointmentsFilterOptions.add(FilterListModel(title: "Work In Progress", isSelected: false, id: 7)); appointmentsFilterOptions.add(FilterListModel(title: "Visit Completed", isSelected: false, id: 8)); notifyListeners(); } applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum, bool isNeedCustomerFilter = false}) { // isNeedCustomerFilter IS ONLY FOR THE PROVIDER APP if (appointmentsFilterOptions.isEmpty) return; for (var value in appointmentsFilterOptions) { value.isSelected = false; } for (var element in appointmentsFilterOptions) { if (element.id == appointmentStatusEnum.getIdFromAppointmentStatusEnum()) { element.isSelected = true; } } // appointmentsFilterOptions[ // appointmentStatusEnum.getIdFromAppointmentStatusEnum()] // .isSelected = true; if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) { myFilteredAppointments = myAppointments; if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(); notifyListeners(); return; } myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList(); if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(); notifyListeners(); } findAppointmentsBasedOnCustomers() { // Use a Set to ensure uniqueness of customerIDs Set uniqueCustomerIDs = {}; // Extract unique customerIDs for (var item in myFilteredAppointments) { uniqueCustomerIDs.add(item.customerID ?? 0); } // Create a list of CustomerData instances myFilteredAppointments2 = uniqueCustomerIDs.map((id) { List list = myFilteredAppointments.where((item) => item.customerID == id).toList(); AppointmentListModel model = list.first; model.customerAppointmentList = list; return model; }).toList(); // customersAppointments = uniqueCustomerIDs.map((id) { // List list = myFilteredAppointments // .where((item) => item.customerID == id) // .toList(); // var customerItem = // myFilteredAppointments.firstWhere((item) => item.customerID == id); // // return CustomerData( // customerID: id, // customerName: customerItem.customerName ?? "", // appointmentList: list, // ); // }).toList(); } // Future getMyAppointments() async { // setState(ViewState.busy); // // myAppointments = // await appointmentRepo.getMyAppointmentsForCustomersByFilters(); // myFilteredAppointments = myAppointments; // myUpComingAppointments = myAppointments // .where((element) => // element.appointmentStatusEnum == AppointmentStatusEnum.booked) // .toList(); // applyFilterOnAppointmentsVM( // appointmentStatusEnum: AppointmentStatusEnum.allAppointments); // if (myUpComingAppointments.isEmpty) { // isShowEmptyMessage = true; // } // setState(ViewState.idle); // notifyListeners(); // } Future getMyAppointments({bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters(); // myFilteredAppointments = myAppointments; myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList(); setState(ViewState.idle); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); notifyListeners(); } AppointmentSlots? appointmentSlots; Future getAppointmentSlotsInfo({required Map map, required BuildContext context, bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); try { MResponse genericRespModel = await appointmentRepo.getAppointmentSlots(map); if (genericRespModel.messageStatus == 1) { appointmentSlots = AppointmentSlots.fromJson(genericRespModel.data); } else { Utils.showToast(genericRespModel.message.toString()); } } catch (e) { Utils.showToast(e.toString()); } } Future getMyAppointmentsForProvider(Map map) async { setState(ViewState.busy); myAppointments = await appointmentRepo.getMyAppointmentsForProvider(map); myFilteredAppointments = myAppointments; myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList(); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true); setState(ViewState.idle); } updateAppointmentStatus(Map map, {bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); try { MResponse genericRespModel = await appointmentRepo.updateAppointmentStatus(map); if (genericRespModel.messageStatus == 1) { Utils.showToast(LocaleKeys.appointmentStatusUpdated.tr()); } else { Utils.showToast(genericRespModel.message.toString()); } } catch (e) { Utils.showToast(e.toString()); } } updateAppointmentPaymentStatus(Map map, {bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); try { MResponse genericRespModel = await appointmentRepo.updateAppointmentPaymentStatus(map); if (genericRespModel.messageStatus == 1) { Utils.showToast(LocaleKeys.paymentStatusUpdated.tr()); } else { Utils.showToast(genericRespModel.message.toString()); } } catch (e) { Utils.showToast(e.toString()); } } Future createMergeAppointment(Map map, {bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); MResponse genericRespModel = await appointmentRepo.createMergeAppointment(map); return genericRespModel; } bool inNeedToEnableMergeButton = false; updateCheckBoxInMergeRequest(int currentIndex) { myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList![currentIndex].isSelected = !(myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false); int count = countSelected(myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList ?? []); if (count > 1) inNeedToEnableMergeButton = true; else inNeedToEnableMergeButton = false; notifyListeners(); } int countSelected(List appointments) { return appointments .where((appointment) => appointment.isSelected == true) .toList() .length; } updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) { for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) { element.date!.isSelected = false; } serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true; serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex; final date = TimeSlotModel( date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date, slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId, isSelected: true, slot: "", ); serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date); notifyListeners(); } updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) { for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) { for (var element in element.availableSlots!) { element.isSelected = false; } } int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!; serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true; serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!; notifyListeners(); } double amountToPayForAppointment = 0.0; double totalAmount = 0.0; List serviceItemsFromApi = []; ProviderProfileModel? providerProfileModel; int selectedSubServicesCounter = 0; onItemUpdateOrSelected(int index, bool selected, int itemId) { int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); // print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}"); // if (serviceIndex == -1) { // return; // } serviceItemsFromApi[index].isUpdateOrSelected = selected; serviceItemsFromApi[index].isHomeSelected = isHomeTapped; if (selected) { selectedSubServicesCounter = selectedSubServicesCounter + 1; selectSubServicesError = ""; currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]); allSelectedItemsInAppointments.add(serviceItemsFromApi[index]); for (var element in allSelectedItemsInAppointments) { if (!ifItemAlreadySelected(element.id!)) { servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]); servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0"); } } } if (!selected) { selectedSubServicesCounter = selectedSubServicesCounter - 1; currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId); allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId); servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0"); servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId); } notifyListeners(); } Future applyFilterOnBranches({required int index}) async { if (branchesFilterOptions.isEmpty) return; for (var value in branchesFilterOptions) { value.isSelected = false; } branchesFilterOptions[index].isSelected = true; await getBranchesBasedOnCategoryFilters(categoryId: branchesFilterOptions[index].id); notifyListeners(); } Future> getServiceItems(int serviceId) async { setState(ViewState.busy); serviceItemsFromApi.clear(); serviceItemsFromApi = await branchRepo.getServiceItems(serviceId); for (var item in serviceItemsFromApi) { if (ifItemAlreadySelected(item.id!)) { item.isUpdateOrSelected = true; } } setState(ViewState.idle); return serviceItemsFromApi; } String pickHomeLocationError = ""; String selectSubServicesError = ""; SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updatePickHomeLocationError(String value) { pickHomeLocationError = value; // notifyListeners(); } bool isServiceSelectionValidated() { if (branchSelectedServiceId.selectedId == -1) { return false; } if (isHomeTapped) { if (pickedHomeLocation == "") { updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError); return false; } } return true; } bool validateItemsSelection() { for (var value in serviceItemsFromApi) { if (value.isUpdateOrSelected!) { return true; } } selectSubServicesError = LocaleKeys.selectOneSubService.tr(); notifyListeners(); return false; } String getTotalPrice(List serviceItems) { var totalPrice = 0.0; for (var element in serviceItems) { totalPrice = totalPrice + (element.currentTotalServicePrice); } return totalPrice.toString(); } void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) { showModalBottomSheet( context: context, isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { return const AppointmentServicePickBottomSheet(); }, ); } void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) { showModalBottomSheet( context: context, isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { double totalKms = 15.3; return InfoBottomSheet( title: LocaleKeys.chargesBreakdown.tr().toText(fontSize: 24, isBold: true), description: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.services.tr().toText(fontSize: 16, isBold: true), Column( children: List.generate( selectedService.serviceItems!.length, (index) => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ "${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true), ], ), ), ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ "${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true), ], ), if (selectedService.isHomeSelected) ...[ 20.height, LocaleKeys.homeLocation.tr().toText(fontSize: 16, isBold: true), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ "${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true), ], ), 8.height, Row( mainAxisAlignment: MainAxisAlignment.end, children: [ "${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true), ], ), ], 30.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.totalAmount.tr().toText(fontSize: 16, isBold: true), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ (selectedService.isHomeSelected ? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" : "${selectedService.currentTotalServicePrice}") .toText(fontSize: 29, isBold: true), 2.width, LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), ], ) ], ), 30.height, ], )); }); } void onReviewButtonPressed(BuildContext context) { bool isValidated = false; for (int i = 0; i < serviceAppointmentScheduleList.length; i++) { final schedule = serviceAppointmentScheduleList[i]; if (schedule.selectedCustomTimeDateSlotModel == null) { isValidated = false; break; } if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) { isValidated = false; break; } else { if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) { isValidated = false; break; } else { TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected); if (slot.date.isNotEmpty) { isValidated = true; break; } } } } if (!isValidated) { Utils.showToast(LocaleKeys.selectAppointmentTime.tr()); return; } navigateWithName(context, AppRoutes.reviewAppointmentView); } void onServicesNextPressed(BuildContext context) async { Utils.showLoading(context); List serviceItemIdsForHome = []; List serviceItemIdsForWorkshop = []; for (var serviceItem in allSelectedItemsInAppointments) { if (serviceItem.isHomeSelected!) { serviceItemIdsForHome.add(serviceItem.id!.toString()); } else { serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); } } serviceAppointmentScheduleList = await appointmentRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, ); if (serviceAppointmentScheduleList.isEmpty) { Utils.hideLoading(context); Utils.showToast(LocaleKeys.noAppointmentAvailable.tr()); return; } totalAmount = 0.0; amountToPayForAppointment = 0.0; for (var schedule in serviceAppointmentScheduleList) { amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); totalAmount = totalAmount + (schedule.amountTotal ?? 0.0); } Utils.hideLoading(context); navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment notifyListeners(); } Future onRescheduleAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async { Utils.showLoading(context); List serviceItemIdsForHome = []; List serviceItemIdsForWorkshop = []; for (var service in appointmentListModel.appointmentServicesList!) { for (var serviceItem in service.serviceItems!) { serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); // if (serviceItem.isHomeSelected ?? false) { // serviceItemIdsForHome.add(serviceItem.id!.toString()); // } else { // serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); // } } } serviceAppointmentScheduleList = await appointmentRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, ); if (serviceAppointmentScheduleList.isEmpty) { Utils.hideLoading(context); Utils.showToast(LocaleKeys.noAppointmentAvailable.tr()); return; } Utils.hideLoading(context); navigateWithName( context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 2, appointmentId: appointmentListModel.id ?? 0), ); // 2 For Rescheduling an Appointment notifyListeners(); } Future onRescheduleAppointmentConfirmPressed({required BuildContext context, required int appointmentId, required int selectedSlotId}) async { Utils.showLoading(context); try { GenericRespModel genericRespModel = await appointmentRepo.cancelOrRescheduleServiceAppointment( serviceAppointmentID: appointmentId, serviceSlotID: selectedSlotId, appointmentScheduleAction: 1, // 1 for Reschedule and 2 for Cancel ); if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) { Utils.hideLoading(context); Utils.showToast("${genericRespModel.message.toString()}"); return; } if (genericRespModel.messageStatus == 1) { context.read().onNavbarTapped(1); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled); Utils.showToast("${genericRespModel.message.toString()}"); getMyAppointments(); Utils.hideLoading(context); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); } } catch (e) { Utils.showToast("${e.toString()}"); } } // BRANCHES RELATED List nearbyBranches = []; List myRecentBranches = []; BranchDetailModel? selectedBranchModel; List branchServices = []; Future populateBranchesFilterList() async { if (branchesFilterOptions.isNotEmpty) return; branchesFilterOptions.clear(); setOnlyState(ViewState.busy); Category category = await branchRepo.fetchBranchCategory(); category.data?.forEach((element) { branchesFilterOptions.add(FilterListModel(id: element.id ?? 0, isSelected: false, title: element.categoryName ?? "N/A")); }); branchesFilterOptions.insert(0, FilterListModel(id: 0, isSelected: true, title: "All Branches")); notifyListeners(); setState(ViewState.idle); } Future getAllNearBranches({bool isNeedToRebuild = false, bool isFromRefresh = false}) async { nearbyBranches.clear(); if (isNeedToRebuild) setState(ViewState.busy); if (isFromRefresh) { var selectedBranch = branchesFilterOptions.firstWhere((element) => element.isSelected); nearbyBranches = await branchRepo.getBranchesByFilters(categoryIdsList: [selectedBranch.id]); setState(ViewState.idle); return; } nearbyBranches = await branchRepo.getAllNearBranchAndServices(); setState(ViewState.idle); } Future getMyRecentBranches({bool isNeedToRebuild = false}) async { myRecentBranches.clear(); if (isNeedToRebuild) setState(ViewState.busy); myRecentBranches = await branchRepo.getMyRecentBranchesWithServices(); setState(ViewState.idle); } void getBranchCategories() async { for (var value in selectedBranchModel!.branchServices!) { if (!isCategoryAlreadyPresent(value.categoryId!)) { branchCategories.add(DropValue(value.categoryId!, value.categoryName!, "")); } } notifyListeners(); } getBranchServices({required int categoryId}) async { branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); isHomeTapped = false; pickedHomeLocation = ""; pickHomeLocationError = ""; if (categoryId != -1) { isFetchingServices = true; branchServices = getFilteredBranchServices(categoryId: categoryId); isFetchingServices = false; notifyListeners(); } } List getFilteredBranchServices({required int categoryId}) { List filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList(); return filteredServices; } getBranchAndServices(int providerId) async { providerProfileModel = null; providerProfileModel = await branchRepo.getBranchAndServicesByProviderId(providerId); setState(ViewState.idle); } bool isCategoryAlreadyPresent(int id) { final contain = branchCategories.where((element) => element.id == id); if (contain.isEmpty) { return false; } return true; } updateSelectedBranch(BranchDetailModel branchDetailModel) { selectedBranchModel = branchDetailModel; getBranchCategories(); notifyListeners(); } int branchFiltersCounter = 0; updateBranchFiltersCounter(int value) { branchFiltersCounter = value; notifyListeners(); } double branchFilterCurrentDistance = 25.0; updateBranchFilterCurrentDistance(double value) { branchFilterCurrentDistance = value; notifyListeners(); } // Provider Filter List branchFilterProviderSearchHistory = []; void removeBranchFilterProviderSearchHistory({bool isClear = false, required int index}) { if (isClear) { branchFilterProviderSearchHistory.clear(); notifyListeners(); return; } branchFilterProviderSearchHistory.removeAt(index); if (branchFilterProviderSearchHistory.isEmpty) { updateBranchFiltersCounter(branchFiltersCounter - 1); // branchFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addBranchFilterProviderSearchHistory({required DropValue value}) { if (branchFilterProviderSearchHistory.isEmpty) { updateBranchFiltersCounter(branchFiltersCounter + 1); } branchFilterProviderSearchHistory.add(value); notifyListeners(); } SelectionModel branchFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateBranchFilterSelectedProviderId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue providerDrop = providersDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: branchFilterProviderSearchHistory, value: providerDrop)) { addBranchFilterProviderSearchHistory(value: providerDrop); } } branchFilterSelectedProviderId = id; notifyListeners(); } // Category Filter List branchFilterCategorySearchHistory = []; void removeBranchFilterCategorySearchHistory({bool isClear = false, required int index}) { if (isClear) { branchFilterCategorySearchHistory.clear(); notifyListeners(); return; } branchFilterCategorySearchHistory.removeAt(index); if (branchFilterCategorySearchHistory.isEmpty) { updateBranchFiltersCounter(branchFiltersCounter - 1); // branchFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addBranchFilterCategorySearchHistory({required DropValue value}) { if (branchFilterCategorySearchHistory.isEmpty) { updateBranchFiltersCounter(branchFiltersCounter + 1); } branchFilterCategorySearchHistory.add(value); notifyListeners(); } SelectionModel branchFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateBranchFilterSelectedCategoryId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue categoryDrop = categoryDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: branchFilterCategorySearchHistory, value: categoryDrop)) { addBranchFilterCategorySearchHistory(value: categoryDrop); } } branchFilterSelectedCategoryId = id; notifyListeners(); } // Services Filter List branchFilterServicesSearchHistory = []; void removeBranchFilterServicesSearchHistory({bool isClear = false, required int index}) { if (isClear) { branchFilterServicesSearchHistory.clear(); notifyListeners(); return; } branchFilterServicesSearchHistory.removeAt(index); if (branchFilterServicesSearchHistory.isEmpty) { updateBranchFiltersCounter(branchFiltersCounter - 1); // branchFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addBranchFilterServicesSearchHistory({required DropValue value}) { if (branchFilterServicesSearchHistory.isEmpty) { updateBranchFiltersCounter(branchFiltersCounter + 1); } branchFilterServicesSearchHistory.add(value); notifyListeners(); } SelectionModel branchFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateBranchFilterSelectedServiceId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue serviceDrop = servicesDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: branchFilterServicesSearchHistory, value: serviceDrop)) { addBranchFilterServicesSearchHistory(value: serviceDrop); } notifyListeners(); return; } branchFilterSelectedServiceId = id; notifyListeners(); } ifAlreadyExist({required List list, required DropValue value}) { int index = list.indexWhere((element) { return element.id == value.id; }); if (index != -1) { return true; } return false; } // Rating filter double branchFilterByRating = 4.0; updateBranchFilterByRating(double value) { branchFilterByRating = value; notifyListeners(); } List categoryDropList = []; List servicesDropList = []; List providersDropList = []; Future fetchAllProviders() async { if (providersDropList.isNotEmpty) return; providersDropList.clear(); setOnlyState(ViewState.busy); List providers = await branchRepo.getAllProvidersWitheBasicData(); for (var element in providers) { providersDropList.add( DropValue(element.id ?? 0, element.providerName ?? "N/A", ""), ); } setState(ViewState.idle); } Future fetchAllCategories(String countryCode) async { if (categoryDropList.isNotEmpty) return; categoryDropList.clear(); setOnlyState(ViewState.busy); Category category = await branchRepo.fetchBranchCategory(); category.data?.forEach((element) { categoryDropList.add( DropValue( element.id ?? 0, ((element.categoryName!.isEmpty ? "N/A" : countryCode == "SA" ? element.categoryNameN : element.categoryName) ?? "N/A"), ""), ); }); setState(ViewState.idle); } Future fetchAllServices() async { if (servicesDropList.isNotEmpty) return; servicesDropList.clear(); setState(ViewState.busy); Services services = await branchRepo.fetchServicesByCategoryId(serviceCategoryId: -1); // to get all services for (var element in services.data!) { servicesDropList.add( DropValue( element.id ?? 0, element.description ?? "N/A", "", ), ); } setState(ViewState.idle); } Future populateDataForBranchesFilter() async { await fetchAllProviders(); // saudi arabia await fetchAllCategories("SA"); // saudi arabia await fetchAllServices(); // saudi arabia updateBranchFilterCurrentDistance(25.0); } void clearBranchFilters() { branchFilterServicesSearchHistory.clear(); branchFilterCategorySearchHistory.clear(); branchFilterProviderSearchHistory.clear(); branchFilterByRating = 4.0; branchFilterCurrentDistance = 25.0; branchFiltersCounter = 0; clearBranchFilterSelections(); notifyListeners(); } void clearBranchFilterSelections() { branchFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); branchFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); branchFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } Future getBranchesBasedOnFilters() async { nearbyBranches.clear(); setState(ViewState.busy); List providersIdsList = []; if (branchFilterProviderSearchHistory.isNotEmpty) { for (var element in branchFilterProviderSearchHistory) { providersIdsList.add(element.id); } } List categoryIdsList = []; if (branchFilterCategorySearchHistory.isNotEmpty) { for (var element in branchFilterCategorySearchHistory) { categoryIdsList.add(element.id); } } List servicesIdsList = []; if (branchFilterServicesSearchHistory.isNotEmpty) { for (var element in branchFilterServicesSearchHistory) { servicesIdsList.add(element.id); } } nearbyBranches = await branchRepo.getBranchesByFilters( providerIdsList: providersIdsList.isNotEmpty ? providersIdsList : null, categoryIdsList: categoryIdsList.isNotEmpty ? categoryIdsList : null, serviceIdsList: servicesIdsList.isNotEmpty ? servicesIdsList : null, distanceKm: branchFilterCurrentDistance.toInt(), rating: branchFilterByRating.toInt(), latitude: 24.694969, longitude: 46.724129, ); setState(ViewState.idle); } Future getBranchesBasedOnCategoryFilters({required int categoryId}) async { if (categoryId == 0) { await getAllNearBranches(); return; } setState(ViewState.busy); nearbyBranches.clear(); nearbyBranches = await branchRepo.getBranchesByFilters(categoryIdsList: [categoryId]); setState(ViewState.idle); } // Appointments Filter Screen List branchesDropList = []; Future fetchAllBranchesBySelectedProviderId({required List providersIdsList}) async { branchesDropList.clear(); setOnlyState(ViewState.busy); List providers = await branchRepo.getBranchesByFilters(providerIdsList: providersIdsList); for (var element in providers) { branchesDropList.add(DropValue(element.id ?? 0, element.branchName ?? "N/A", "")); } setState(ViewState.idle); log("branchesDropList: ${branchesDropList.length}"); } Future populateDataForAppointmentsFilter() async { await fetchAllProviders(); // saudi arabia await fetchAllCategories("SA"); // saudi arabia await fetchAllServices(); // saudi arabia } int appointmentFiltersCounter = 0; updateAppointmentFiltersCounter(int value) { appointmentFiltersCounter = value; notifyListeners(); } // Provider Filter For Appointments List appointmentFilterProviderSearchHistory = []; void removeAppointmentFilterProviderSearchHistory({bool isClear = false, required int index}) { if (isClear) { appointmentFilterProviderSearchHistory.clear(); notifyListeners(); return; } appointmentFilterProviderSearchHistory.removeAt(index); if (appointmentFilterProviderSearchHistory.isNotEmpty) { List providerIdsSelected = []; for (var element in appointmentFilterProviderSearchHistory) { providerIdsSelected.add(element.id); } fetchAllBranchesBySelectedProviderId(providersIdsList: providerIdsSelected); } if (appointmentFilterProviderSearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); // appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addAppointmentFilterProviderSearchHistory({required DropValue value}) { if (appointmentFilterProviderSearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); } List providerIdsSelected = []; for (var element in appointmentFilterProviderSearchHistory) { providerIdsSelected.add(element.id); } fetchAllBranchesBySelectedProviderId(providersIdsList: providerIdsSelected); appointmentFilterProviderSearchHistory.add(value); notifyListeners(); } SelectionModel appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateAppointmentFilterSelectedProviderId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue providerDrop = providersDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: appointmentFilterProviderSearchHistory, value: providerDrop)) { addAppointmentFilterProviderSearchHistory(value: providerDrop); } } // appointmentFilterSelectedProviderId = id; notifyListeners(); } // Branches Filter For Appointments List appointmentFilterBranchSearchHistory = []; void removeAppointmentFilterBranchSearchHistory({bool isClear = false, required int index}) { if (isClear) { appointmentFilterBranchSearchHistory.clear(); notifyListeners(); return; } appointmentFilterBranchSearchHistory.removeAt(index); if (appointmentFilterBranchSearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); // appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addAppointmentFilterBranchSearchHistory({required DropValue value}) { if (appointmentFilterBranchSearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); } appointmentFilterBranchSearchHistory.add(value); notifyListeners(); } SelectionModel appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateAppointmentFilterSelectedBranchId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue branchesDrop = branchesDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: appointmentFilterBranchSearchHistory, value: branchesDrop)) { addAppointmentFilterBranchSearchHistory(value: branchesDrop); } } // appointmentFilterSelectedBranchId = id; notifyListeners(); } // Category Filter For Appointments List appointmentFilterCategorySearchHistory = []; void removeAppointmentFilterCategorySearchHistory({bool isClear = false, required int index}) { if (isClear) { appointmentFilterCategorySearchHistory.clear(); notifyListeners(); return; } appointmentFilterCategorySearchHistory.removeAt(index); if (appointmentFilterCategorySearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); // appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addAppointmentFilterCategorySearchHistory({required DropValue value}) { if (appointmentFilterCategorySearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); } appointmentFilterCategorySearchHistory.add(value); notifyListeners(); } SelectionModel appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateAppointmentFilterSelectedCategoryId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue categoryDrop = categoryDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: appointmentFilterCategorySearchHistory, value: categoryDrop)) { addAppointmentFilterCategorySearchHistory(value: categoryDrop); } } // appointmentFilterSelectedCategoryId = id; notifyListeners(); } List appointmentFilterServicesSearchHistory = []; void removeAppointmentFilterServicesSearchHistory({bool isClear = false, required int index}) { if (isClear) { appointmentFilterServicesSearchHistory.clear(); notifyListeners(); return; } appointmentFilterServicesSearchHistory.removeAt(index); if (appointmentFilterServicesSearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); // appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } notifyListeners(); } void addAppointmentFilterServicesSearchHistory({required DropValue value}) { if (appointmentFilterServicesSearchHistory.isEmpty) { updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); } appointmentFilterServicesSearchHistory.add(value); notifyListeners(); } SelectionModel appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateAppointmentFilterSelectedServiceId(SelectionModel id, {bool isForSearch = false}) async { if (isForSearch) { DropValue servicesDrop = servicesDropList.firstWhere((element) => element.id == id.selectedId); if (!ifAlreadyExist(list: appointmentFilterServicesSearchHistory, value: servicesDrop)) { addAppointmentFilterServicesSearchHistory(value: servicesDrop); } } // appointmentFilterSelectedServiceId = id; notifyListeners(); } void clearAppointmentFilterSelections() { appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } void clearAppointmentFilters() { appointmentFilterServicesSearchHistory.clear(); appointmentFilterCategorySearchHistory.clear(); appointmentFilterProviderSearchHistory.clear(); appointmentFilterBranchSearchHistory.clear(); appointmentFiltersCounter = 0; clearAppointmentFilterSelections(); getMyAppointments(); notifyListeners(); } Future getAppointmentsBasedOnFilters() async { setState(ViewState.busy); List providersIdsList = []; if (appointmentFilterProviderSearchHistory.isNotEmpty) { for (var element in appointmentFilterProviderSearchHistory) { providersIdsList.add(element.id.toString()); } } List categoryIdsList = []; if (appointmentFilterCategorySearchHistory.isNotEmpty) { for (var element in appointmentFilterCategorySearchHistory) { categoryIdsList.add(element.id.toString()); } } List servicesIdsList = []; if (appointmentFilterServicesSearchHistory.isNotEmpty) { for (var element in appointmentFilterServicesSearchHistory) { servicesIdsList.add(element.id.toString()); } } List branchesIdsList = []; if (appointmentFilterBranchSearchHistory.isNotEmpty) { for (var element in appointmentFilterBranchSearchHistory) { branchesIdsList.add(element.id.toString()); } } myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters( providerIdsList: providersIdsList, categoryIdsList: categoryIdsList, serviceIdsList: servicesIdsList, branchIdsList: branchesIdsList, ); applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); setState(ViewState.idle); } Future addProviderToFavorite({required String serviceProviderID}) async { setState(ViewState.busy); } List currentBranchReviews = []; bool isReadMoreEnabled = false; void resetCurrentBranchRatings() { currentBranchReviews.clear(); isReadMoreEnabled = false; } updateIsReadMoreEnabled(var value) { isReadMoreEnabled = value; notifyListeners(); } Future getReviewsByBranchId({required int serviceProviderBranchID}) async { setState(ViewState.busy); try { currentBranchReviews = await branchRepo.getBranchRatings(serviceProviderBranchID: serviceProviderBranchID); } catch (e, s) { logger.e(s); setState(ViewState.idle); Utils.showToast(e.toString()); } setState(ViewState.idle); } }