import ' dart:developer ' ;
import ' package:flutter/cupertino.dart ' ;
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/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 isUpcomingEnabled = true ;
bool isFetchingLists = false ;
int selectedBranch = 0 ;
int selectedAppointmentIndex = 0 ;
int selectedAppointmentSubIndex = 0 ;
int selectedAppointmentId = 0 ;
List < AppointmentListModel > myAppointments = [ ] ;
List < AppointmentListModel > myUpComingAppointments = [ ] ;
List < AppointmentListModel > myFilteredAppointments = [ ] ;
List < FilterListModel > appointmentsFilterOptions = [ ] ;
List < CustomerData > customersAppointments = [ ] ;
List < AppointmentListModel > myFilteredAppointments2 = [ ] ;
// List<ScheduleData> availableSchedules = [];
bool isFetchingServices = false ;
List < DropValue > branchCategories = [ ] ;
bool isHomeTapped = false ;
bool isShowEmptyMessage = false ;
List < ServiceAppointmentScheduleModel > serviceAppointmentScheduleList = [ ] ;
List < ItemData > allSelectedItemsInAppointments = [ ] ;
bool ifItemAlreadySelected ( int id ) {
int indexFound = allSelectedItemsInAppointments . indexWhere ( ( element ) = > element . id = = id ) ;
if ( indexFound ! = - 1 ) {
return true ;
}
return false ;
}
Future < void > 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 < void > onPayNowPressedForAppointment ( { required BuildContext context , required int appointmentID } ) async {
context . read < PaymentVM > ( ) . updateAppointmentIdsForPayment ( ids: [ appointmentID ] ) ;
navigateWithName ( context , AppRoutes . paymentMethodsView , arguments: PaymentTypes . partialAppointment ) ;
}
Future < void > onBookAppointmentPressed ( BuildContext context ) async {
Utils . showLoading ( context ) ;
bool isSuccess = false ;
List < int > 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 < DashboardVmCustomer > ( ) . onNavbarTapped ( 1 ) ;
applyFilterOnAppointmentsVM ( appointmentStatusEnum: AppointmentStatusEnum . booked ) ;
Utils . hideLoading ( context ) ;
resetAfterBookingAppointment ( ) ;
if ( isSuccess ) {
if ( amountToPayForAppointment > 0 ) {
context . read < PaymentVM > ( ) . 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 < void > onConfirmAppointmentPressed ( { required BuildContext context , required appointmentId } ) async {
context . read < PaymentVM > ( ) . updateAppointmentIdsForPayment ( ids: [ appointmentId ] ) ;
navigateWithName ( context , AppRoutes . paymentMethodsView , arguments: PaymentTypes . appointment ) ;
}
Future < void > 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 < DashboardVmCustomer > ( ) . 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 < FilterListModel > branchesFilterOptions = [ ] ;
List < ServiceModel > 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 [ index ] . serviceItems ! . clear ( ) ;
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 < EnumsModel > myAppointmentsEnum = [ ] ;
Future < void > populateAppointmentsFilterList ( ) async {
if ( appointmentsFilterOptions . isNotEmpty ) return ;
myAppointmentsEnum = await commonRepo . getEnumTypeValues ( enumTypeID: AppEnums . appointmentsFilterEnumId ) ; // 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 < int > uniqueCustomerIDs = < int > { } ;
// Extract unique customerIDs
for ( var item in myFilteredAppointments ) {
uniqueCustomerIDs . add ( item . customerID ? ? 0 ) ;
}
// Create a list of CustomerData instances
myFilteredAppointments2 = uniqueCustomerIDs . map ( ( id ) {
List < AppointmentListModel > list = myFilteredAppointments . where ( ( item ) = > item . customerID = = id ) . toList ( ) ;
AppointmentListModel model = list . first ;
model . customerAppointmentList = list ;
return model ;
} ) . toList ( ) ;
// customersAppointments = uniqueCustomerIDs.map((id) {
// List<AppointmentListModel> 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<void> 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 < void > 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 < void > getAppointmentSlotsInfo ( { required Map < String , dynamic > map , required BuildContext context , bool isNeedToRebuild = false } ) async {
if ( isNeedToRebuild ) setState ( ViewState . busy ) ;
try {
GenericRespModel 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 < void > getMyAppointmentsForProvider ( Map < String , dynamic > 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 ( { required int appointmentId , required AppointmentStatusEnum appointmentStatusEnum , bool isNeedToRebuild = false } ) async {
if ( isNeedToRebuild ) setState ( ViewState . busy ) ;
try {
GenericRespModel genericRespModel = await appointmentRepo . updateAppointmentStatus ( appointmentId: appointmentId , appointmentStatusEnum: appointmentStatusEnum ) ;
if ( genericRespModel . messageStatus = = 1 ) {
Utils . showToast ( LocaleKeys . appointmentStatusUpdated . tr ( ) ) ;
} else {
Utils . showToast ( genericRespModel . message . toString ( ) ) ;
}
} catch ( e ) {
Utils . showToast ( e . toString ( ) ) ;
}
}
updateAppointmentPaymentStatus ( Map < String , dynamic > map , { bool isNeedToRebuild = false } ) async {
if ( isNeedToRebuild ) setState ( ViewState . busy ) ;
try {
GenericRespModel 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 ( ) ) ;
}
}
bool isShowMergeButton ( ) {
return myFilteredAppointments2 [ selectedAppointmentIndex ] . customerAppointmentList ! . every ( ( appointment ) = > appointment . appointmentStatusEnum = = AppointmentStatusEnum . confirmed ) & &
myFilteredAppointments2 [ selectedAppointmentIndex ] . customerAppointmentList ! . length > 1 ;
}
Future < GenericRespModel > createMergeAppointment ( Map < String , dynamic > map , { bool isNeedToRebuild = false } ) async {
if ( isNeedToRebuild ) setState ( ViewState . busy ) ;
GenericRespModel genericRespModel = await appointmentRepo . createMergeAppointment ( map ) ;
return genericRespModel ;
}
bool inNeedToEnableMergeButton = false ;
void 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 < AppointmentListModel > 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 < ItemData > serviceItemsFromApi = [ ] ;
ProviderProfileModel ? providerProfileModel ;
int selectedSubServicesCounter = 0 ;
void onItemUpdateOrSelected ( int index , bool selected , int itemId ) {
int serviceIndex = servicesInCurrentAppointment . indexWhere ( ( element ) = > element . serviceId = = currentServiceSelection ! . serviceId ! ) ;
log ( " index: $ index " ) ;
log ( " selected: $ selected " ) ;
log ( " itemId: $ itemId " ) ;
log ( " servicesInCurrentAppointment: ${ servicesInCurrentAppointment . length } " ) ;
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 ! ) ) {
if ( serviceIndex ! = - 1 ) {
servicesInCurrentAppointment [ serviceIndex ] . serviceItems ! . add ( serviceItemsFromApi [ index ] ) ;
servicesInCurrentAppointment [ serviceIndex ] . currentTotalServicePrice = servicesInCurrentAppointment [ serviceIndex ] . currentTotalServicePrice + double . parse ( ( serviceItemsFromApi [ index ] . price ) ? ? " 0.0 " ) ;
}
}
}
} else {
log ( " currentServiceSelection!.serviceItems: ${ currentServiceSelection ! . serviceItems ! . length } " ) ;
selectedSubServicesCounter = selectedSubServicesCounter - 1 ;
currentServiceSelection ! . serviceItems ! . removeWhere ( ( element ) = > element . id = = itemId ) ;
log ( " currentServiceSelection!.serviceItems: ${ currentServiceSelection ! . serviceItems ! . length } " ) ;
allSelectedItemsInAppointments . removeWhere ( ( element ) = > element . id = = itemId ) ;
if ( serviceIndex ! = - 1 ) {
servicesInCurrentAppointment [ serviceIndex ] . currentTotalServicePrice = servicesInCurrentAppointment [ serviceIndex ] . currentTotalServicePrice - double . parse ( ( serviceItemsFromApi [ index ] . price ) ? ? " 0.0 " ) ;
servicesInCurrentAppointment [ serviceIndex ] . serviceItems ! . removeWhere ( ( element ) = > element . id = = itemId ) ;
}
}
notifyListeners ( ) ;
}
Future < void > 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 < List < ItemData > > 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 < ServiceModel > 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 < String > serviceItemIdsForHome = [ ] ;
List < String > 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 < void > onRescheduleAppointmentPressed ( { required BuildContext context , required AppointmentListModel appointmentListModel } ) async {
Utils . showLoading ( context ) ;
List < String > serviceItemIdsForHome = [ ] ;
List < String > 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 < void > 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 < DashboardVmCustomer > ( ) . 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 < BranchDetailModel > nearbyBranches = [ ] ;
List < BranchDetailModel > myRecentBranches = [ ] ;
BranchDetailModel ? selectedBranchModel ;
List < ServiceModel > branchServices = [ ] ;
Future < void > 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 < void > 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 < void > 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 ( ) ;
}
Future < void > 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 < ServiceModel > getFilteredBranchServices ( { required int categoryId } ) {
List < ServiceModel > filteredServices = selectedBranchModel ! . branchServices ! . where ( ( element ) = > element . categoryId = = categoryId ) . toList ( ) ;
return filteredServices ;
}
Future < void > getProviderProfileWithBranchesAndServices ( int providerId ) async {
setState ( ViewState . busy ) ;
try {
providerProfileModel = await branchRepo . getBranchAndServicesByProviderId ( providerId ) ;
} catch ( e , s ) {
logger . e ( s ) ;
setState ( ViewState . idle ) ;
Utils . showToast ( e . toString ( ) ) ;
}
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 < DropValue > 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 < DropValue > 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 < DropValue > 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 < DropValue > 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 < DropValue > categoryDropList = [ ] ;
List < DropValue > servicesDropList = [ ] ;
List < DropValue > providersDropList = [ ] ;
Future < void > fetchAllProviders ( ) async {
if ( providersDropList . isNotEmpty ) return ;
providersDropList . clear ( ) ;
setOnlyState ( ViewState . busy ) ;
List < ProviderBasicDataModel > providers = await branchRepo . getAllProvidersWitheBasicData ( ) ;
for ( var element in providers ) {
providersDropList . add (
DropValue ( element . id ? ? 0 , element . providerName ? ? " N/A " , " " ) ,
) ;
}
setState ( ViewState . idle ) ;
}
Future < void > 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 < void > 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 < void > 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 < void > getBranchesBasedOnFilters ( ) async {
nearbyBranches . clear ( ) ;
setState ( ViewState . busy ) ;
List < int > providersIdsList = [ ] ;
if ( branchFilterProviderSearchHistory . isNotEmpty ) {
for ( var element in branchFilterProviderSearchHistory ) {
providersIdsList . add ( element . id ) ;
}
}
List < int > categoryIdsList = [ ] ;
if ( branchFilterCategorySearchHistory . isNotEmpty ) {
for ( var element in branchFilterCategorySearchHistory ) {
categoryIdsList . add ( element . id ) ;
}
}
List < int > 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 < void > 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 < DropValue > branchesDropList = [ ] ;
Future < void > fetchAllBranchesBySelectedProviderId ( { required List < int > providersIdsList } ) async {
branchesDropList . clear ( ) ;
setOnlyState ( ViewState . busy ) ;
List < BranchDetailModel > 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 < void > 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 < DropValue > appointmentFilterProviderSearchHistory = [ ] ;
void removeAppointmentFilterProviderSearchHistory ( { bool isClear = false , required int index } ) {
if ( isClear ) {
appointmentFilterProviderSearchHistory . clear ( ) ;
notifyListeners ( ) ;
return ;
}
appointmentFilterProviderSearchHistory . removeAt ( index ) ;
if ( appointmentFilterProviderSearchHistory . isNotEmpty ) {
List < int > 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 < int > 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 < DropValue > 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 < DropValue > 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 < DropValue > 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 < void > getAppointmentsBasedOnFilters ( ) async {
setState ( ViewState . busy ) ;
List < String > providersIdsList = [ ] ;
if ( appointmentFilterProviderSearchHistory . isNotEmpty ) {
for ( var element in appointmentFilterProviderSearchHistory ) {
providersIdsList . add ( element . id . toString ( ) ) ;
}
}
List < String > categoryIdsList = [ ] ;
if ( appointmentFilterCategorySearchHistory . isNotEmpty ) {
for ( var element in appointmentFilterCategorySearchHistory ) {
categoryIdsList . add ( element . id . toString ( ) ) ;
}
}
List < String > servicesIdsList = [ ] ;
if ( appointmentFilterServicesSearchHistory . isNotEmpty ) {
for ( var element in appointmentFilterServicesSearchHistory ) {
servicesIdsList . add ( element . id . toString ( ) ) ;
}
}
List < String > 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 < bool > addProviderToFavorite ( { required int serviceProviderID , required BuildContext context } ) async {
Utils . showLoading ( context ) ;
try {
GenericRespModel genericRespModel = await branchRepo . addProviderToFavourite ( providerID: serviceProviderID ) ;
Utils . showToast ( genericRespModel . message . toString ( ) ) ;
Utils . hideLoading ( context ) ;
return genericRespModel . messageStatus = = 1 ;
} catch ( e , s ) {
logger . e ( s ) ;
Utils . hideLoading ( context ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
}
}
Future < bool > removeProviderFromFavorite ( { required int serviceProviderID , required BuildContext context } ) async {
Utils . showLoading ( context ) ;
try {
GenericRespModel genericRespModel = await branchRepo . removeProviderFromFavourite ( providerID: serviceProviderID ) ;
Utils . hideLoading ( context ) ;
Utils . showToast ( genericRespModel . message . toString ( ) ) ;
return genericRespModel . messageStatus = = 1 ;
} catch ( e , s ) {
logger . e ( s ) ;
Utils . hideLoading ( context ) ;
Utils . showToast ( e . toString ( ) ) ;
return false ;
}
}
List < ProviderProfileModel > myFavProvidersList = [ ] ;
Future < void > getMyFavoriteProviders ( ) async {
myFavProvidersList . clear ( ) ;
setState ( ViewState . busy ) ;
try {
myFavProvidersList = await branchRepo . getMyFavoriteProviders ( ) ;
setState ( ViewState . idle ) ;
} catch ( e , s ) {
logger . e ( s ) ;
setState ( ViewState . idle ) ;
Utils . showToast ( e . toString ( ) ) ;
}
}
List < BranchRatingModel > currentBranchReviews = [ ] ;
bool isReadMoreEnabled = false ;
void resetCurrentBranchRatings ( ) {
currentBranchReviews . clear ( ) ;
isReadMoreEnabled = false ;
}
updateIsReadMoreEnabled ( var value ) {
isReadMoreEnabled = value ;
notifyListeners ( ) ;
}
Future < void > 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 ) ;
}
}