diff --git a/lib/config/customer_dependencies.dart b/lib/config/customer_dependencies.dart index 6fd51e7..252b4f9 100644 --- a/lib/config/customer_dependencies.dart +++ b/lib/config/customer_dependencies.dart @@ -1,13 +1,8 @@ -import 'package:car_customer_app/repositories/provider_repo.dart'; -import 'package:car_customer_app/repositories/appointment_repo.dart'; -import 'package:car_customer_app/repositories/request_repo.dart'; + import 'package:mc_common_app/config/dependencies.dart'; class CustomerDependencies { static void addDependencies() { AppDependencies.addDependencies(); - injector.registerSingleton(() => ProviderRepoImp()); - injector.registerSingleton(() => ScheduleRepoImp()); - injector.registerSingleton(() => RequestRepoImp()); } } diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index 8f85512..7aaa1d7 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -1,10 +1,10 @@ import 'package:car_customer_app/chat/chat_view.dart'; -import 'package:car_customer_app/views/appointments/appointment_detail_view.dart'; -import 'package:car_customer_app/views/appointments/book_appointment_schedules_view.dart'; -import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart'; -import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart'; -import 'package:car_customer_app/views/appointments/pick_items_view.dart'; -import 'package:car_customer_app/views/appointments/review_appointment_view.dart'; +import 'package:mc_common_app/views/appointments/appointment_detail_view.dart'; +import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart'; +import 'package:mc_common_app/views/appointments/book_appointment_services_view.dart'; +import 'package:mc_common_app/views/appointments/book_appointments_item_view.dart'; +import 'package:mc_common_app/views/appointments/pick_items_view.dart'; +import 'package:mc_common_app/views/appointments/review_appointment_view.dart'; import 'package:car_customer_app/views/dashboard/dashboard_page.dart'; import 'package:car_customer_app/views/provider/branch_detail_page.dart'; import 'package:car_customer_app/views/provider/provider_profile_page.dart'; diff --git a/lib/main.dart b/lib/main.dart index 79209f2..e4961d5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,11 @@ import 'package:car_customer_app/config/customer_dependencies.dart'; import 'package:car_customer_app/config/customer_routes.dart'; -import 'package:car_customer_app/repositories/provider_repo.dart'; -import 'package:car_customer_app/repositories/appointment_repo.dart'; -import 'package:car_customer_app/repositories/request_repo.dart'; -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; -import 'package:car_customer_app/view_models/requests_view_model.dart'; +import 'package:mc_common_app/repositories/provider_repo.dart'; +import 'package:mc_common_app/repositories/appointment_repo.dart'; +import 'package:mc_common_app/repositories/request_repo.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; +import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; @@ -40,8 +40,8 @@ Future main() async { MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => BaseVM()), - ChangeNotifierProvider( - create: (_) => DashboardVM( + ChangeNotifierProvider( + create: (_) => DashboardVmCustomer( commonServices: injector.get(), userRepo: injector.get(), ), diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart deleted file mode 100644 index dc25367..0000000 --- a/lib/repositories/appointment_repo.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'dart:developer'; - -import 'package:mc_common_app/api/api_client.dart'; -import 'package:mc_common_app/classes/app_state.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; -import 'package:mc_common_app/models/generic_resp_model.dart'; -import 'package:mc_common_app/models/m_response.dart'; -import 'package:mc_common_app/models/provider_branches_models/profile/services.dart'; -import 'package:mc_common_app/models/schedule_model.dart'; -import 'package:mc_common_app/models/service_schedule_model.dart'; -import 'package:mc_common_app/utils/enums.dart'; - -abstract class AppointmentRepo { - Future getAllServices(String branchId); - - Future createSchedule(Map map); - - Future addServicesInSchedule(Map map); - - Future updateSchedule(Map map); - - Future> getSchedules(String branchId); - - Future updateServicesInSchedule(Map map); - - Future> mergeServiceIntoAvailableSchedules({ - required List serviceItemIdsForHome, - required List serviceItemIdsForWorkshop, - }); - - Future createServiceAppointment({required List schedules, required int serviceProviderID}); - - Future cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}); -} - -class ScheduleRepoImp implements AppointmentRepo { - @override - Future getAllServices(String branchId) async { - Map map = {"ProviderBranchID": branchId}; - String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().getJsonForObject((json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, token: t, queryParameters: map); - } - - @override - Future createSchedule(Map map) async { - String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t); - } - - @override - Future addServicesInSchedule(Map map) async { - String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t); - } - - @override - Future> getSchedules(String branchId) async { - Map map = {"ServiceProviderBranchID": branchId}; - String t = AppState().getUser.data!.accessToken ?? ""; - - GenericRespModel adsGenericModel = await injector.get().getJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.getSchedule, - token: t, - queryParameters: map, - ); - - return List.generate(adsGenericModel.data.length, (index) => ScheduleData.fromJson(adsGenericModel.data[index])); - } - - @override - Future updateSchedule(Map map) async { - String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, token: t); - } - - @override - Future updateServicesInSchedule(Map map) async { - String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t); - } - - Future> mergeServiceIntoAvailableSchedules({ - required List serviceItemIdsForHome, - required List serviceItemIdsForWorkshop, - }) async { - String t = AppState().getUser.data!.accessToken ?? ""; - var queryParameters = [ - { - "appointmentType": 2, - "ServiceItemIDs": serviceItemIdsForHome, - }, - { - "appointmentType": 1, - "ServiceItemIDs": serviceItemIdsForWorkshop, - } - ]; - GenericRespModel adsGenericModel = await injector.get().postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.GetServiceItemAppointmentScheduleSlots, - queryParameters, - token: t, - ); - List serviceAppointmentScheduleModel = - List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index], isForAppointment: true)); - return serviceAppointmentScheduleModel; - } - - Future createServiceAppointment({required List schedules, required int serviceProviderID}) async { - String t = AppState().getUser.data!.accessToken ?? ""; - int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0; - - List> mapList = []; - schedules.forEach((schedule) { - List serviceItemIds = []; - schedule.servicesListInAppointment!.forEach((service) { - service.serviceItems!.forEach((item) { - serviceItemIds.add(item.id!); - }); - }); - mapList.add({ - "serviceSlotID": schedule.selectedCustomTimeDateSlotModel!.date!.slotId, - "serviceProviderID": serviceProviderID, - "customerID": customerId, - "serviceItemID": serviceItemIds, - }); - }); - - GenericRespModel adsGenericModel = await injector.get().postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.ServiceProvidersAppointmentCreate, - mapList, - token: t, - ); - - return adsGenericModel; - } - - @override - Future cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}) async { - String t = AppState().getUser.data!.accessToken ?? ""; - - final payload = { - "serviceAppointmentID": serviceAppointmentID, - "serviceSlotID": serviceSlotID, - "appointmentScheduleAction": appointmentScheduleAction, - }; - - GenericRespModel adsGenericModel = await injector.get().postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment, - payload, - token: t, - ); - - return adsGenericModel; - } -} diff --git a/lib/repositories/provider_repo.dart b/lib/repositories/provider_repo.dart deleted file mode 100644 index fee2cc1..0000000 --- a/lib/repositories/provider_repo.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'dart:async'; - -import 'package:mc_common_app/api/api_client.dart'; -import 'package:mc_common_app/classes/app_state.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; -import 'package:mc_common_app/models/generic_resp_model.dart'; -import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; -import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; - -abstract class ProviderRepo { - Future> getAllNearBranchAndServices(); - - Future> getServiceItems(int serviceId); - - Future getBranchAndServices(int providerId); -} - -class ProviderRepoImp implements ProviderRepo { - ApiClient apiClient = injector.get(); - AppState appState = injector.get(); - - @override - Future> getAllNearBranchAndServices() async { - GenericRespModel adsGenericModel = await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.GetAllNearBranches, token: appState.getUser.data!.accessToken); - List nearBranches = List.generate(adsGenericModel.data.length, (index) => BranchDetailModel.fromJson(adsGenericModel.data[index])); - return nearBranches; - } - - @override - Future> getServiceItems(int serviceId) async { - var queryParameters = { - "ServiceProviderServiceID": serviceId.toString(), - }; - - GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.getServiceItems, - token: appState.getUser.data!.accessToken, - queryParameters: queryParameters, - ); - List serviceItems = List.generate(adsGenericModel.data.length, (index) => ItemData.fromJson(adsGenericModel.data[index])); - return serviceItems; - } - - @override - Future getBranchAndServices(int providerId) async { - var postParams = {"serviceProviderID": providerId.toString()}; - GenericRespModel adsGenericModel = - await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.BranchesAndServices, token: appState.getUser.data!.accessToken, queryParameters: postParams); - - return ProviderProfileModel.fromJson(adsGenericModel.data); - } -} diff --git a/lib/repositories/request_repo.dart b/lib/repositories/request_repo.dart deleted file mode 100644 index 2b8de66..0000000 --- a/lib/repositories/request_repo.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'package:mc_common_app/api/api_client.dart'; -import 'package:mc_common_app/classes/app_state.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/config/dependencies.dart'; -import 'package:mc_common_app/models/generic_resp_model.dart'; -import 'package:mc_common_app/models/requests/offers_model.dart'; -import 'package:mc_common_app/models/requests/request_model.dart'; - -abstract class RequestRepo { - Future createRequest(Map map); - - Future> getOffersByRequest({required int requestId, int serviceProviderId = 0}); - - Future> getRequests(Map postParams); -} - -class RequestRepoImp implements RequestRepo { - ApiClient apiClient = injector.get(); - AppState appState = injector.get(); - - @override - Future createRequest(Map postParams) async { - GenericRespModel enumGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.createRequest, - postParams, - token: appState.getUser.data!.accessToken, - ); - return enumGenericModel; - } - - @override - Future> getRequests(Map postParams) async { - GenericRespModel enumGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.getRequest, - postParams, - token: appState.getUser.data!.accessToken, - ); - List requests = List.generate( - enumGenericModel.data.length, - (index) => RequestModel.fromJson( - enumGenericModel.data[index], - ), - ); - return requests; - } - - @override - Future> getOffersByRequest({required int requestId, int serviceProviderId = 0}) async { - var queryParameters = { - "RequestID": requestId.toString(), - "ServiceProviderID": serviceProviderId.toString(), - }; - GenericRespModel genericRespModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.getRequestOffers, - queryParameters: queryParameters, - token: appState.getUser.data!.accessToken, - ); - List offersList = List.generate( - genericRespModel.data.length, - (index) => OffersModel.fromJson( - genericRespModel.data[index], - ), - ); - return offersList; - } -} diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart deleted file mode 100644 index 613ba4d..0000000 --- a/lib/view_models/appointments_view_model.dart +++ /dev/null @@ -1,677 +0,0 @@ -import 'package:car_customer_app/repositories/provider_repo.dart'; -import 'package:car_customer_app/repositories/appointment_repo.dart'; -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; -import 'package:car_customer_app/views/appointments/book_appointment_schedules_view.dart'; -import 'package:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.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/models/appointments_models/appointment_list_model.dart'; -import 'package:mc_common_app/models/enums_model.dart'; -import 'package:mc_common_app/models/generic_resp_model.dart'; -import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; -import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart'; -import 'package:mc_common_app/models/service_schedule_model.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:mc_common_app/models/services/service_model.dart'; -import 'package:mc_common_app/models/widgets_models.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/payment_view_model.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'; - -class AppointmentsVM extends BaseVM { - final CommonRepo commonRepo; - final CommonAppServices commonServices; - final ProviderRepo providerRepo; - final AppointmentRepo scheduleRepo; - - AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo}); - - bool isFetchingLists = false; - - List myAppointments = []; - List myUpComingAppointments = []; - List myFilteredAppointments = []; - List appointmentsFilterOptions = []; - - // List availableSchedules = []; - - bool isFetchingServices = false; - - List branchCategories = []; - - bool isHomeTapped = false; - - List serviceAppointmentScheduleList = []; - - bool ifItemAlreadySelected(int id) { - int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id); - if (indexFound != -1) { - return true; - } - return false; - } - - List allSelectedItemsInAppointments = []; - - Future onItemsSelectedInService() async { - if (currentServiceSelection != null) { - int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); - - if (index == -1) { - double totalPrice = 0.0; - currentServiceSelection!.serviceItems!.forEach((element) { - totalPrice = totalPrice + double.parse(element.price ?? "0.0"); - }); - currentServiceSelection!.currentTotalServicePrice = totalPrice; - servicesInCurrentAppointment.insert(0, currentServiceSelection!); - } - - resetCategorySelectionBottomSheet(); - notifyListeners(); - } - } - - Future onBookAppointmentPressed(BuildContext context) async { - Utils.showLoading(context); - bool isSuccess = false; - List appointmentIdsList = []; - try { - GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment( - schedules: serviceAppointmentScheduleList, - serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0, - ); - - if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) { - Utils.hideLoading(context); - Utils.showToast("${genericRespModel.message.toString()}"); - return; - } - if (genericRespModel.data != null) { - genericRespModel.data.forEach((element) { - if (element['appointmentID'] != 0) { - appointmentIdsList.add(element['appointmentID']); - isSuccess = true; - } else { - isSuccess = false; - 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("Your appointment has been booked successfully!"); - 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 scheduleRepo.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.data == 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 providersFilterOptions = []; - List nearbyBranches = []; - BranchDetailModel? selectedBranchModel; - - List branchServices = []; - - List servicesInCurrentAppointment = []; - ServiceModel? currentServiceSelection; - - void updateBranchServiceId(SelectionModel id) async { - branchSelectedServiceId = id; - currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId); - - notifyListeners(); - } - - resetCategorySelectionBottomSheet() { - selectedSubServicesCounter = 0; - branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - isHomeTapped = false; - branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - currentServiceSelection = null; - } - - resetAfterBookingAppointment() { - servicesInCurrentAppointment.clear(); - allSelectedItemsInAppointments.clear(); - serviceAppointmentScheduleList.clear(); - } - - List myAppointmentsEnum = []; - - populateAppointmentsFilterList() async { - appointmentsFilterOptions.clear(); - - myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); //TODO: 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)); - - notifyListeners(); - } - - applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) { - if (appointmentsFilterOptions.isEmpty) return; - for (var value in appointmentsFilterOptions) { - value.isSelected = false; - } - appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true; - - if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) { - myFilteredAppointments = myAppointments; - notifyListeners(); - return; - } - - myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList(); - notifyListeners(); - } - - Future getMyAppointments({bool isNeedToRebuild = false}) async { - if (isNeedToRebuild) setState(ViewState.busy); - - myAppointments = await commonRepo.getMyAppointments(); - myFilteredAppointments = myAppointments; - myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList(); - setState(ViewState.idle); - // applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); - notifyListeners(); - } - - updateSelectedBranch(BranchDetailModel branchDetailModel) { - selectedBranchModel = branchDetailModel; - getBranchCategories(); - notifyListeners(); - } - - updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) { - serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) { - 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}) { - serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) { - element.availableSlots!.forEach((element) => 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!); - - serviceItemsFromApi[index].isUpdateOrSelected = selected; - serviceItemsFromApi[index].isHomeSelected = isHomeTapped; - if (selected) { - selectedSubServicesCounter = selectedSubServicesCounter + 1; - selectSubServicesError = ""; - currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]); - allSelectedItemsInAppointments.add(serviceItemsFromApi[index]); - allSelectedItemsInAppointments.forEach((element) { - 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(); - } - - populateBranchesFilterList() { - providersFilterOptions.clear(); - providersFilterOptions = [ - FilterListModel(title: "All Providers", isSelected: true, id: 0), - FilterListModel(title: "Maintenance", isSelected: false, id: 1), - FilterListModel(title: "Oil Service", isSelected: false, id: 2), - FilterListModel(title: "Accessories", isSelected: false, id: 3), - FilterListModel(title: "Tire Service", isSelected: false, id: 4), - FilterListModel(title: "Dent and Paint", isSelected: false, id: 5), - ]; - notifyListeners(); - } - - applyFilterOnProviders({required int index}) { - if (providersFilterOptions.isEmpty) return; - for (var value in providersFilterOptions) { - value.isSelected = false; - } - providersFilterOptions[index].isSelected = true; - notifyListeners(); - } - - getAllNearBranches({bool isNeedToRebuild = false}) async { - //TODO: needs to lat,long into API - nearbyBranches.clear(); - if (isNeedToRebuild) setState(ViewState.busy); - nearbyBranches = await providerRepo.getAllNearBranchAndServices(); - setState(ViewState.idle); - } - - Future> getServiceItems(int serviceId) async { - serviceItemsFromApi.clear(); - serviceItemsFromApi = await providerRepo.getServiceItems(serviceId); - serviceItemsFromApi.forEach((item) { - if (ifItemAlreadySelected(item.id!)) { - item.isUpdateOrSelected = true; - } - }); - setState(ViewState.idle); - return serviceItemsFromApi; - } - - getBranchAndServices(int providerId) async { - providerProfileModel = null; - providerProfileModel = await providerRepo.getBranchAndServices(providerId); - setState(ViewState.idle); - } - - String pickHomeLocationError = ""; - String selectSubServicesError = ""; - - SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - bool isCategoryAlreadyPresent(int id) { - final contain = branchCategories.where((element) => element.id == id); - if (contain.isEmpty) { - return false; - } - return true; - } - - 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; - } - - 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 = "Please select at least one sub service"; - notifyListeners(); - return false; - } - - String getTotalPrice(List serviceItems) { - var totalPrice = 0.0; - serviceItems.forEach((element) { - totalPrice = totalPrice + (element.currentTotalServicePrice); - }); - return totalPrice.toString(); - } - - void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - enableDrag: true, - builder: (BuildContext context) { - return AppointmentServicePickBottomSheet(); - }, - ); - } - - void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - enableDrag: true, - builder: (BuildContext context) { - double totalKms = 15.3; - return InfoBottomSheet( - title: "Charges Breakdown".toText(fontSize: 24, isBold: true), - description: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Services".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, - "Home Location".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: [ - "Total Amount ".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, - "SAR".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 = true; - break; - } else { - TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected); - if (slot.date.isNotEmpty) { - isValidated = true; - break; - } - } - } - } - if (!isValidated) { - Utils.showToast("You must select appointment time for each schedule's appointment."); - return; - } - navigateWithName(context, AppRoutes.reviewAppointmentView); - } - - void onServicesNextPressed(BuildContext context) async { - Utils.showLoading(context); - - List serviceItemIdsForHome = []; - List serviceItemIdsForWorkshop = []; - allSelectedItemsInAppointments.forEach((serviceItem) { - if (serviceItem.isHomeSelected!) { - serviceItemIdsForHome.add(serviceItem.id!.toString()); - } else { - serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); - } - }); - - serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( - serviceItemIdsForHome: serviceItemIdsForHome, - serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, - ); - - if (serviceAppointmentScheduleList.isEmpty) { - Utils.hideLoading(context); - Utils.showToast("There are no available appointments for selected Items."); - return; - } - totalAmount = 0.0; - amountToPayForAppointment = 0.0; - serviceAppointmentScheduleList.forEach( - (schedule) { - 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 = []; - appointmentListModel.appointmentServicesList!.forEach((service) { - service.serviceItems!.forEach((serviceItem) { - serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); - - // if (serviceItem.isHomeSelected ?? false) { - // serviceItemIdsForHome.add(serviceItem.id!.toString()); - // } else { - // serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); - // } - }); - }); - - serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( - serviceItemIdsForHome: serviceItemIdsForHome, - serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, - ); - - if (serviceAppointmentScheduleList.isEmpty) { - Utils.hideLoading(context); - Utils.showToast("There are no available appointments for selected Items."); - 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 scheduleRepo.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.data == 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()}"); - } - } -} diff --git a/lib/view_models/dashboard_view_model.dart b/lib/view_models/dashboard_view_model.dart deleted file mode 100644 index 21dca0b..0000000 --- a/lib/view_models/dashboard_view_model.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'dart:io'; -import 'package:mc_common_app/classes/app_state.dart'; -import 'package:mc_common_app/generated/locale_keys.g.dart'; -import 'package:mc_common_app/models/user/image_response.dart'; -import 'package:mc_common_app/repositories/user_repo.dart'; -import 'package:mc_common_app/services/common_services.dart'; -import 'package:mc_common_app/utils/utils.dart'; -import 'package:mc_common_app/view_models/base_view_model.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:easy_localization/easy_localization.dart'; - -class DashboardVM extends BaseVM { - final CommonAppServices commonServices; - final UserRepo userRepo; - - DashboardVM({required this.commonServices, required this.userRepo}); - - String pickedImage = ""; - - int selectedNavbarBarIndex = 2; - - void onNavbarTapped(int index) { - selectedNavbarBarIndex = index; - notifyListeners(); - } - - void pickImageFromPhone(BuildContext context, int sourceFlag) async { - final File? pickedImageFile = await commonServices.pickImageFromPhone(sourceFlag); - if (pickedImageFile == null) { - return; - } - int sizeInBytes = pickedImageFile.lengthSync(); - if (sizeInBytes > 1000) { - Utils.showToast(LocaleKeys.fileLarger.tr()); - return; - } else { - String image64 = Utils.convertFileToBase64(pickedImageFile); - - Utils.showLoading(context); - ImageResponse response = await userRepo.updateUserImage(image64); - Utils.hideLoading(context); - Navigator.pop(context); - if (response.messageStatus == 1) { - Utils.showToast(LocaleKeys.imageUploaded.tr()); - AppState().getUser.data!.userInfo!.userImageUrl = response.data; - } else { - Utils.showToast(response.message ?? ""); - } - } - } - - Future updateUserImage(String image) async { - return await userRepo.updateUserImage(image); - } -} diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart deleted file mode 100644 index e825048..0000000 --- a/lib/view_models/requests_view_model.dart +++ /dev/null @@ -1,312 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:car_customer_app/repositories/request_repo.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:mc_common_app/classes/app_state.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; -import 'package:mc_common_app/models/enums_model.dart'; -import 'package:mc_common_app/models/generic_resp_model.dart'; -import 'package:mc_common_app/models/requests/offers_model.dart'; -import 'package:mc_common_app/models/requests/request_model.dart'; -import 'package:mc_common_app/models/widgets_models.dart'; -import 'package:mc_common_app/repositories/common_repo.dart'; -import 'package:mc_common_app/services/common_services.dart'; -import 'package:mc_common_app/utils/enums.dart'; -import 'package:mc_common_app/utils/utils.dart'; -import 'package:mc_common_app/view_models/base_view_model.dart'; - -class RequestsVM extends BaseVM { - final CommonAppServices commonServices; - final CommonRepo commonRepo; - final RequestRepo requestRepo; - - RequestsVM({required this.commonServices, required this.commonRepo, required this.requestRepo}); - - List myRequests = []; - List myFilteredRequests = []; - - List requestsTypeFilterOptions = []; - - List myRequestsTypeEnum = []; - - populateRequestsFilterList() async { - requestsTypeFilterOptions.clear(); - - myRequestsTypeEnum = await commonRepo.getEnumTypeValues(enumTypeID: 16); //TODO: 13 is to get Requests Filter Enums - - for (int i = 0; i < myRequestsTypeEnum.length; i++) { - requestsTypeFilterOptions.add(FilterListModel(title: myRequestsTypeEnum[i].enumValueStr, isSelected: false, id: myRequestsTypeEnum[i].enumValue)); - } - - notifyListeners(); - } - - Future getMyRequests({bool isNeedToRebuild = false}) async { - if (isNeedToRebuild) setState(ViewState.busy); - - myRequests = await requestRepo.getRequests( - { - "customerID": AppState().getUser.data!.userInfo!.customerId, - "pageSize": 100, - "pageIndex": 0, - "requestType": 0, - }, - ); - applyFilterOnRequestsVM(requestsTypeEnum: RequestsTypeEnum.specialCarRequest); - setState(ViewState.idle); - notifyListeners(); - } - - applyFilterOnRequestsVM({required RequestsTypeEnum requestsTypeEnum}) { - if (requestsTypeFilterOptions.isEmpty) return; - for (var value in requestsTypeFilterOptions) { - value.isSelected = false; - } - requestsTypeFilterOptions[requestsTypeEnum.getIdFromRequestTypeStatusEnum() - 1].isSelected = true; // -1 to match with the index - myFilteredRequests = myRequests.where((element) => element.requestType == requestsTypeEnum.getIdFromRequestTypeStatusEnum()).toList(); - - notifyListeners(); - } - - List pickedVehicleImages = []; - String vehicleImageError = ""; - - void removeImageFromList(String filePath) { - int index = pickedVehicleImages.indexWhere((element) => element.path == filePath); - if (index == -1) { - return; - } - pickedVehicleImages.removeAt(index); - notifyListeners(); - } - - void pickMultipleImages() async { - List Images = await commonServices.pickMultipleImages(); - pickedVehicleImages.addAll(Images); - if (pickedVehicleImages.isNotEmpty) vehicleImageError = ""; - notifyListeners(); - } - - bool isFetchingRequestType = false; - bool isFetchingVehicleType = true; - bool isFetchingVehicleDetail = false; - List vehicleTypes = []; - VehicleDetailsModel? vehicleDetails; - List vehicleBrands = []; - List vehicleModels = []; - List vehicleModelYears = []; - List vehicleCountries = []; - List vehicleCities = []; - - SelectionModel requestTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - void updateSelectionRequestTypeId(SelectionModel id) async { - requestTypeId = id; - getVehicleTypes(); - notifyListeners(); - } - - SelectionModel vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - Future getVehicleTypes() async { - resetRequestCreationForm(); - isFetchingVehicleType = true; - vehicleTypes = await commonRepo.getVehicleTypes(); - isFetchingVehicleType = false; - notifyListeners(); - } - - resetRequestCreationForm() { - vehicleTypeId.selectedId = -1; - vehicleBrandId.selectedId = -1; - vehicleModelId.selectedId = -1; - vehicleModelYearId.selectedId = -1; - vehicleCountryId.selectedId = -1; - vehicleCityId.selectedId = -1; - } - - void updateSelectionVehicleTypeId(SelectionModel id) async { - vehicleTypeId = id; - getVehicleBrandsByVehicleTypeId(); - notifyListeners(); - } - - Future getVehicleBrandsByVehicleTypeId() async { - // if (vehicleBrandId.selectedId == -1) { - // return; - // } - isFetchingVehicleDetail = true; - notifyListeners(); - vehicleDetails = await commonRepo.getVehicleDetails(vehicleTypeId: vehicleTypeId.selectedId); - - if (vehicleDetails != null) { - vehicleBrands = vehicleDetails!.vehicleBrands!; - vehicleModels = vehicleDetails!.vehicleModels!; - vehicleModelYears = vehicleDetails!.vehicleModelYears!; - vehicleCountries = vehicleDetails!.vehicleCountries!; - } - isFetchingVehicleDetail = false; - notifyListeners(); - } - - SelectionModel vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - void updateSelectionVehicleBrandId(SelectionModel id) { - vehicleBrandId = id; - vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - notifyListeners(); - } - - SelectionModel vehicleModelId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - void updateSelectionVehicleModelId(SelectionModel id) { - vehicleModelId = id; - vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - notifyListeners(); - } - - SelectionModel vehicleModelYearId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - void updateSelectionVehicleModelYearId(SelectionModel id) { - vehicleModelYearId = id; - notifyListeners(); - } - - bool isShippingDeliveryEnabled = false; - - void updateShippingDeliverEnabled(bool v) { - isShippingDeliveryEnabled = v; - notifyListeners(); - } - - bool isCountryFetching = false; - SelectionModel vehicleCountryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - void updateSelectionVehicleCountryId(SelectionModel id) async { - vehicleCountryId = id; - isCountryFetching = true; - notifyListeners(); - vehicleCities = await commonRepo.getVehicleCities(countryId: vehicleCountryId.selectedId); - isCountryFetching = false; - notifyListeners(); - } - - SelectionModel vehicleCityId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - - void updateSelectionVehicleCityId(SelectionModel id) { - vehicleCityId = id; - notifyListeners(); - } - - //Request Management - String price = "", description = ""; - - updatePrice(String v) { - price = v; - } - - updateDescription(String v) { - description = v; - } - - Future convertFileToRequestPostingImages({required File file}) async { - List imageBytes = await file.readAsBytes(); - String image = base64Encode(imageBytes); - String fileName = file.path.split('/').last; - VehiclePostingImages vehiclePostingImages = VehiclePostingImages( - imageName: fileName, - imageStr: image, - imageUrl: file.path, - ); - return vehiclePostingImages; - } - - Future onCreateRequestTapped(BuildContext context) async { - if (validateCreateRequestForm()) { - Utils.showLoading(context); - List vehicleImages = []; - pickedVehicleImages.forEach((element) async { - vehicleImages.add(await convertFileToRequestPostingImages(file: element)); - }); - - Map body = { - "customerID": AppState().getUser.data!.userInfo!.customerId ?? 0, - "requestType": requestTypeId.selectedId, - "vehicleTypeID": vehicleTypeId.selectedId, - "brand": vehicleBrandId.selectedOption, - "model": vehicleModelId.selectedOption, - "year": vehicleModelYearId.selectedOption, - "isNew": true, - "countryID": vehicleCountryId.selectedId, - "cityID": vehicleCityId.selectedId, - "price": price, - "description": description, - "isSpecialServiceNeeded": false, - "requestImages": vehicleImages, - }; - try { - GenericRespModel respModel = await requestRepo.createRequest(body); - Utils.hideLoading(context); - if (respModel.messageStatus == 1) { - Utils.showToast("Request Successfully Created"); - Navigator.pop(context); - await getMyRequests(); - } else { - Utils.showToast(respModel.message.toString()); - } - } catch (e, s) { - Utils.hideLoading(context); - print(s); - } - } - } - - bool validateCreateRequestForm() { - bool isValid = true; - if (requestTypeId.selectedId == -1) { - Utils.showToast("Please select valid Request Type"); - isValid = false; - } else if (vehicleTypeId.selectedId == -1) { - Utils.showToast("Please select valid Vehicle Type"); - isValid = false; - } else if (vehicleBrandId.selectedId == -1) { - Utils.showToast("Please select valid Brand"); - isValid = false; - } else if (vehicleModelId.selectedId == -1) { - Utils.showToast("Please select valid Model"); - isValid = false; - } else if (vehicleModelYearId.selectedId == -1) { - Utils.showToast("Please select valid Year"); - isValid = false; - } else if (vehicleCountryId.selectedId == -1) { - Utils.showToast("Please select valid Country"); - isValid = false; - } else if (vehicleCityId.selectedId == -1) { - Utils.showToast("Please select valid City"); - isValid = false; - } else if (price.isEmpty) { - Utils.showToast("Please add valid Price"); - isValid = false; - } else if (description.isEmpty) { - Utils.showToast("Please add valid Description"); - isValid = false; - } - return isValid; - } - - Future> getOffersByRequest({required int requestId, required BuildContext context}) async { - try { - Utils.showLoading(context); - List respModel = await requestRepo.getOffersByRequest(requestId: requestId); - Utils.hideLoading(context); - return respModel; - } catch (e) { - Utils.showToast(e.toString()); - Utils.hideLoading(context); - return []; - } - } -} diff --git a/lib/views/appointments/appointment_detail_view.dart b/lib/views/appointments/appointment_detail_view.dart deleted file mode 100644 index bf02f3a..0000000 --- a/lib/views/appointments/appointment_detail_view.dart +++ /dev/null @@ -1,245 +0,0 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; -import 'package:mc_common_app/models/services/service_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart'; -import 'package:mc_common_app/utils/enums.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:provider/provider.dart'; - -class AppointmentDetailView extends StatelessWidget { - final AppointmentListModel appointmentListModel; - - AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key); - - Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) { - return Expanded( - child: ShowFillButton( - maxHeight: 55, - title: text, - onPressed: onPressed, - backgroundColor: color, - txtColor: textColor, - fontSize: 18, - ), - ); - } - - Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) { - switch (appointmentStatusEnum) { - case AppointmentStatusEnum.booked: - return Align( - alignment: Alignment.bottomCenter, - child: Row( - children: [ - getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), - 12.width, - getBaseActionButtonWidget( - color: MyColors.greenColor, - onPressed: () { - context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); - }, - text: "Confirm"), - ], - ), - ); - case AppointmentStatusEnum.confirmed: - return Align( - alignment: Alignment.bottomCenter, - child: Row( - children: [ - getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), - ], - ), - ); - case AppointmentStatusEnum.arrived: - return Align( - alignment: Alignment.bottomCenter, - child: Row( - children: [ - getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "In Progress"), - ], - ), - ); - case AppointmentStatusEnum.cancelled: - return Align( - alignment: Alignment.bottomCenter, - child: Row( - children: [ - getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"), - ], - ), - ); - case AppointmentStatusEnum.allAppointments: - return SizedBox(); - case AppointmentStatusEnum.rescheduled: - return Align( - alignment: Alignment.bottomCenter, - child: Row( - children: [ - getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), - 12.width, - getBaseActionButtonWidget( - color: MyColors.greenColor, - onPressed: () { - context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); - }, - text: "Confirm"), - ], - ), - ); - } - } - - void appointmentCancelConfirmationSheet(BuildContext context) { - final appointmentsVm = context.read(); - return actionConfirmationBottomSheet( - context: context, - title: "Do you want to cancel this appointment?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44), - subtitle: "Your appointment will be cancelled and you cannot undo this action.", - actionButtonYes: Expanded( - child: ShowFillButton( - maxHeight: 55, - title: "Yes", - fontSize: 15, - onPressed: () { - Navigator.pop(context); - appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel); - }, - ), - ), - actionButtonNo: Expanded( - child: ShowFillButton( - maxHeight: 55, - isFilled: false, - borderColor: MyColors.darkPrimaryColor, - title: "No", - txtColor: MyColors.darkPrimaryColor, - fontSize: 15, - onPressed: () { - Navigator.pop(context); - }, - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - AppointmentsVM appointmentsVM = context.read(); - return Scaffold( - appBar: CustomAppBar( - title: "Appointment", - profileImageUrl: MyAssets.bnCar, - isRemoveBackButton: false, - isDrawerEnabled: false, - ), - body: Container( - padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), - child: Stack( - children: [ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - appointmentListModel.providerName!.toText(fontSize: 16, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - MyAssets.miniClockDark.buildSvg( - height: 12, - width: 12, - fit: BoxFit.fill, - ), - 5.width, - "${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor), - ], - ), - 13.height, - if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[ - Column( - children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) { - ServiceModel service = appointmentListModel.appointmentServicesList![index]; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - // MyAssets.maintenanceIcon.buildSvg( - // height: 10, - // width: 10, - // fit: BoxFit.fill, - // ), - // 10.width, - "${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true), - ], - ), - if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[ - Column( - children: List.generate( - service.serviceItems!.length, - (index) => "${service.serviceItems![index].name}".toText( - textAlign: TextAlign.start, - fontSize: 12, - color: MyColors.lightTextColor, - ), - ), - ).paddingOnly(left: 15), - ], - 5.height, - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - ((service.currentTotalServicePrice).toString()).toText(fontSize: 25, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), - Icon( - Icons.arrow_drop_down, - size: 30, - ) - ], - ).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)), - ], - ); - }), - ), - ], - 15.height, - Row( - children: [ - CardButtonWithIcon( - title: "Reschedule Appointment", - onCardTapped: () { - context.read().onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel); - }, - icon: MyAssets.scheduleAppointmentIcon.buildSvg(), - ), - if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[ - 10.width, - CardButtonWithIcon( - title: "Pay for Appointment", - onCardTapped: () { - context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); - }, - icon: MyAssets.creditCardIcon.buildSvg(), - ), - ], - ], - ), - 15.height, - ], - ).toWhiteContainer(width: double.infinity, allPading: 12), - buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context), - ], - ), - ), - ); - } -} diff --git a/lib/views/appointments/book_appointment_schedules_view.dart b/lib/views/appointments/book_appointment_schedules_view.dart deleted file mode 100644 index 9cccde3..0000000 --- a/lib/views/appointments/book_appointment_schedules_view.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/views/appointments/widgets/custom_calender_widget.dart'; -import 'package:flutter/material.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/service_schedule_model.dart'; -import 'package:mc_common_app/models/services/service_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:provider/provider.dart'; - -class ScreenArgumentsForAppointmentDetailPage { - final int routeFlag; // 1 = coming from create appointment || 2 = coming from reschedule appointment - final int appointmentId; // 1 = coming from create appointment || 2 = coming from reschedule appointment - - ScreenArgumentsForAppointmentDetailPage({required this.routeFlag, required this.appointmentId}); -} - -class BookAppointmentSchedulesView extends StatelessWidget { - final ScreenArgumentsForAppointmentDetailPage screenArgumentsForAppointmentDetailPage; - - BookAppointmentSchedulesView({Key? key, required this.screenArgumentsForAppointmentDetailPage}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "Book Appointment", - isRemoveBackButton: false, - isDrawerEnabled: false, - actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], - onBackButtonTapped: () => Navigator.pop(context), - ), - body: Consumer( - builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 21.height, - ListView.builder( - shrinkWrap: true, - itemCount: appointmentsVM.serviceAppointmentScheduleList.length, - itemBuilder: (BuildContext context, int scheduleIndex) { - ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; - return ExpansionTile( - tilePadding: EdgeInsets.symmetric(horizontal: 21, vertical: 10), - childrenPadding: EdgeInsets.only(left: 16, bottom: 10, right: 16), - title: Column( - children: [ - Row( - children: [ - Expanded( - child: "Schedule ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true), - ), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - ("${scheduleData.appointmentType == 2 ? "Home" : "Workshop"}").toText(fontSize: 12, isBold: true).expand(), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 5.height, - ListView.builder( - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment!.length, - itemBuilder: (BuildContext context, int serviceIndex) { - ServiceModel selectedService = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment![serviceIndex]; - return Row( - children: [ - Expanded( - child: ("${serviceIndex + 1}. ${selectedService.providerServiceDescription}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor), - ), - ], - ); - }, - ), - ], - ), - ], - ), - children: [ - Column( - children: [ - CustomCalenderWidget(customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? [], scheduleIndex: scheduleIndex), - if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[ - 5.height, - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - ("Available Slots").toText(fontSize: 14, isBold: true), - ], - ), - 5.height, - SizedBox( - width: double.infinity, - child: BuildTimeSlots( - timeSlots: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex] - .customTimeDateSlotList![appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!].availableSlots ?? - [], - onPressed: (slotIndex) { - appointmentsVM.updateSelectedAppointmentSlotByDate(scheduleIndex: scheduleIndex, slotIndex: slotIndex); - }, - ), - ), - ], - ], - ), - ], - ).toWhiteContainer(width: double.infinity, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); - }, - ).expand(), - Row( - children: [ - Expanded( - child: ShowFillButton( - txtColor: MyColors.black, - maxHeight: 55, - title: "Cancel", - onPressed: () => Navigator.pop(context), - backgroundColor: MyColors.greyButtonColor, - ), - ), - 12.width, - Expanded( - child: ShowFillButton( - maxHeight: 55, - title: screenArgumentsForAppointmentDetailPage.routeFlag == 1 ? "Review" : "Confirm", - onPressed: () { - if (screenArgumentsForAppointmentDetailPage.routeFlag == 1) { - appointmentsVM.onReviewButtonPressed(context); - } else { - appointmentsVM.onRescheduleAppointmentConfirmPressed( - context: context, - appointmentId: screenArgumentsForAppointmentDetailPage.appointmentId, - selectedSlotId: appointmentsVM.serviceAppointmentScheduleList.first.selectedCustomTimeDateSlotModel!.date!.slotId, - ); - } - }, - backgroundColor: MyColors.darkPrimaryColor, - ), - ) - ], - ).paddingAll(21) - ], - ); - }, - )); - } -} diff --git a/lib/views/appointments/book_appointment_services_view.dart b/lib/views/appointments/book_appointment_services_view.dart deleted file mode 100644 index c149114..0000000 --- a/lib/views/appointments/book_appointment_services_view.dart +++ /dev/null @@ -1,133 +0,0 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:mc_common_app/models/services/service_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:provider/provider.dart'; - -class BookAppointmentServicesView extends StatelessWidget { - BookAppointmentServicesView({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "Book Appointment", - isRemoveBackButton: false, - isDrawerEnabled: false, - actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], - onBackButtonTapped: () => Navigator.pop(context), - ), - body: Consumer( - builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 21.height, - CustomAddButton( - needsBorder: true, - bgColor: MyColors.white, - onTap: () => appointmentsVM.openTheAddServiceBottomSheet(context, appointmentsVM), - text: "Add Services", - icon: Container( - height: 24, - width: 24, - decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: const Icon(Icons.add, color: MyColors.white), - ), - ).horPaddingMain(), - 10.height, - ListView.builder( - shrinkWrap: true, - itemCount: appointmentsVM.servicesInCurrentAppointment.length, - itemBuilder: (BuildContext context, int serviceIndex) { - ServiceModel serviceData = appointmentsVM.servicesInCurrentAppointment[serviceIndex]; - return Column( - children: [ - Row( - children: [ - Expanded( - child: (serviceData.serviceDescription ?? "").toText(fontSize: 15, isBold: true), - ), - ], - ), - if (true) ...[ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - (serviceData.isHomeSelected ? serviceData.homeLocation : "Workshop").toText(fontSize: 12, isBold: true).expand(), - ], - ), - 5.height, - Column( - children: List.generate(serviceData.serviceItems!.length, (itemIndex) { - ItemData itemData = serviceData.serviceItems![itemIndex]; - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), - ("${itemData.price}").toText(fontSize: 13, isBold: true).expand(), - ], - ); - }), - ), - 8.height, - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - ((appointmentsVM.servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), - Icon( - Icons.arrow_drop_down, - size: 30, - ) - ], - ).onPress(() => appointmentsVM.priceBreakDownClicked(context, appointmentsVM.servicesInCurrentAppointment[serviceIndex])), - ], - ], - ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); - }, - ).expand(), - Row( - children: [ - Expanded( - child: ShowFillButton( - txtColor: MyColors.black, - maxHeight: 55, - title: "Cancel", - onPressed: () { - appointmentsVM.servicesInCurrentAppointment.clear(); - appointmentsVM.allSelectedItemsInAppointments.clear(); - Navigator.pop(context); - }, - backgroundColor: MyColors.greyButtonColor, - ), - ), - 12.width, - Expanded( - child: ShowFillButton( - maxHeight: 55, - title: "Next", - onPressed: () { - appointmentsVM.onServicesNextPressed(context); - }, - backgroundColor: MyColors.darkPrimaryColor, - ), - ) - ], - ).paddingAll(21) - ], - ); - }, - )); - } -} diff --git a/lib/views/appointments/book_appointments_item_view.dart b/lib/views/appointments/book_appointments_item_view.dart deleted file mode 100644 index 8f5baeb..0000000 --- a/lib/views/appointments/book_appointments_item_view.dart +++ /dev/null @@ -1,152 +0,0 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/views/appointments/widgets/service_item_with_price_checkbox.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/models/services/item_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/navigator.dart'; -import 'package:mc_common_app/utils/utils.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:provider/provider.dart'; - -class BookAppointmentsItemView extends StatelessWidget { - const BookAppointmentsItemView({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "Select Services", - isRemoveBackButton: false, - isDrawerEnabled: false, - actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], - onBackButtonTapped: () => Navigator.pop(context), - ), - body: Consumer( - builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 40, - width: double.infinity, - color: MyColors.darkTextColor, - alignment: Alignment.centerLeft, - child: "${appointmentsVM.selectedSubServicesCounter} Item(s) Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(), - ), - 16.height, - Column( - children: [ - "Few services are not available on home location. Change the location to workshop to full access the services".toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor), - 8.height, - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Change location or service: ".toText(fontSize: 14, isBold: true), - "Edit".toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor), - 5.width, - MyAssets.icEdit.buildSvg(width: 17), - ], - ).onPress(() {}), - 16.height, - Divider(), - ], - ).horPaddingMain(), - appointmentsVM.serviceItemsFromApi.isEmpty - ? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor))) - : ListView.separated( - separatorBuilder: (BuildContext context, int index) => Divider(), - itemCount: appointmentsVM.serviceItemsFromApi.length, - itemBuilder: (BuildContext context, int index) { - ItemData itemData = appointmentsVM.serviceItemsFromApi[index]; - return ServiceItemWithPriceCheckBox( - description: itemData.description ?? "Some description about the sub-services", - title: itemData.name!, - isSelected: itemData.isUpdateOrSelected!, - onSelection: (bool value) { - print("itemId: ${itemData.id}"); - appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!); - }, - priceWidget: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - // TODO: This Price will be decided according to the service selected - itemData.price!.split(".").first.toText(fontSize: 30, isBold: true), - " SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), - ], - ), - ); - }, - ).expand(), - Column( - children: [ - Divider( - height: 1, - thickness: 0.7, - ), - 8.height, - if (appointmentsVM.selectSubServicesError != "") - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - appointmentsVM.selectSubServicesError.toText(fontSize: 14, color: Colors.red), - ], - ).paddingOnly(right: 10), - 8.height, - Row( - children: [ - Expanded( - child: ShowFillButton( - txtColor: MyColors.black, - maxHeight: 55, - title: "Cancel", - onPressed: () { - appointmentsVM.resetCategorySelectionBottomSheet(); - pop(context); - }, - backgroundColor: MyColors.greyButtonColor, - ), - ), - 12.width, - Expanded( - child: Builder( - builder: (BuildContext context) { - return ShowFillButton( - maxHeight: 55, - title: "Next", - onPressed: () async { - bool resp = appointmentsVM.validateItemsSelection(); - if (resp) { - appointmentsVM.onItemsSelectedInService(); - Navigator.pop(context); - } - // bool resp = appointmentsVM.validateItemsSelection(); - // if (resp) { - // Utils.showLoading(context); - // await appointmentsVM.mergeServiceIntoAvailableSchedules(); - // appointmentsVM.resetCategorySelectionBottomSheet(); - // Utils.hideLoading(context); - // Navigator.of(context).pushReplacementNamed(AppRoutes.bookAppointmenServicesView); - // } - }, - backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor, - ); - }, - ), - ), - ], - ).horPaddingMain(), - 16.height, - ], - ), - ], - ); - }, - )); - } -} diff --git a/lib/views/appointments/pick_items_view.dart b/lib/views/appointments/pick_items_view.dart deleted file mode 100644 index bd8c1e6..0000000 --- a/lib/views/appointments/pick_items_view.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart'; -import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; -import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; - -class BookProviderAppView extends StatefulWidget { - const BookProviderAppView({Key? key}) : super(key: key); - - @override - State createState() => _BookProviderAppViewState(); -} - -class _BookProviderAppViewState extends State { - bool isReview = false; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "Appointment", - profileImageUrl: MyAssets.bnCar, - isRemoveBackButton: false, - isDrawerEnabled: false, - ), - body: Container( - color: MyColors.backgroundColor, - width: double.infinity, - height: double.infinity, - child: Column( - children: [ - Expanded( - child: ListView( - children: [ - ProviderDetailsCard( - onCardTapped: () {}, - providerImageUrl: MyAssets.bnCar, - providerLocation: "3km", - title: "Al Ahmed Maintenance", - providerRatings: "4.9", - ), - 12.height, - isReview ? ReviewAppointmentSection() : ServicesSelectionSection(), - 10.height, - ], - ), - ), - 10.height, - Padding( - padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), - child: ShowFillButton( - title: "Book Appointment", - maxWidth: double.infinity, - onPressed: () { - isReview = !isReview; - setState(() {}); - }, - ), - ), - ], - ), - ), - ); - } -} - -class ServicesSelectionSection extends StatelessWidget { - const ServicesSelectionSection({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - List dropList = [ - DropValue(0, "Maintenance", ""), - DropValue(1, "Car Wash", ""), - DropValue(2, "Monthly Checkup", ""), - DropValue(3, "Friendly Visit", ""), - DropValue(4, "Muftaa", ""), - ]; - return Container( - padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Select services you want".toText(fontSize: 18, isBold: true), - 8.height, - DropdownField( - (DropValue value) {}, - list: dropList, - hint: "Select service type", - ), - 8.height, - DropdownField( - (DropValue value) {}, - list: dropList, - hint: "Select service type", - ), - 8.height, - DropdownField( - (DropValue value) {}, - list: dropList, - hint: "Select service type", - ), - 22.height, - "Select date and time".toText(fontSize: 18, isBold: true), - 8.height, - DropdownField( - (DropValue value) {}, - list: dropList, - hint: "Select service type", - ), - 22.height, - "Available slots".toText(fontSize: 15, isBold: true), - 8.height, - BuildTimeSlots(onPressed: (index) {}, timeSlots: []), - 22.height, - "Total Amount".toText(fontSize: 18, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - "3000".toText(fontSize: 20, isBold: true), - "SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), - ], - ), - 10.height, - ], - ).toWhiteContainer(width: double.infinity, allPading: 12), - ); - } -} - -class ReviewAppointmentSection extends StatelessWidget { - const ReviewAppointmentSection({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Review Appointment".toText(fontSize: 18, isBold: true), - 15.height, - "Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - "Car Engine Check".toText(fontSize: 18, isBold: true), - 13.height, - "Date and Time".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - "2 Feb, 2023 at 09:00am".toText(fontSize: 18, isBold: true), - 13.height, - "Total Amount".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - "3000".toText(fontSize: 20, isBold: true), - "SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), - ], - ), - 100.height, - ], - ).toWhiteContainer(width: double.infinity, allPading: 12), - ); - } -} diff --git a/lib/views/appointments/review_appointment_view.dart b/lib/views/appointments/review_appointment_view.dart deleted file mode 100644 index ff4d5ae..0000000 --- a/lib/views/appointments/review_appointment_view.dart +++ /dev/null @@ -1,307 +0,0 @@ -import 'dart:developer'; - -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/generated/locale_keys.g.dart'; -import 'package:mc_common_app/models/schedule_model.dart'; -import 'package:mc_common_app/models/service_schedule_model.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:mc_common_app/models/services/service_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; -import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:provider/provider.dart'; - -class ReviewAppointment extends StatelessWidget { - const ReviewAppointment({Key? key}) : super(key: key); - - Widget buildBranchInfoCard({required BuildContext context}) { - AppointmentsVM appointmentsVM = context.read(); - return Padding( - padding: const EdgeInsets.only( - bottom: 10, - left: 21, - right: 21, - ), - child: Row( - children: [ - Image.asset( - MyAssets.bnCar, - width: 80, - height: 60, - fit: BoxFit.cover, - ), - 12.width, - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - (appointmentsVM.selectedBranchModel!.branchName ?? "").toText(fontSize: 16, isBold: true), - Row( - children: [ - LocaleKeys.location.tr().toText(color: MyColors.lightTextColor, fontSize: 12), - 2.width, - ": ${appointmentsVM.selectedBranchModel!.branchDescription ?? ""}".toText(fontSize: 12), - ], - ), - ], - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "4.9".toText( - isUnderLine: true, - isBold: true, - fontSize: 12, - ), - 2.width, - MyAssets.starIcon.buildSvg(width: 12), - ], - ), - ], - ), - ], - ), - ), - ], - ).onPress(() {}).toWhiteContainer(width: double.infinity, allPading: 12)); - } - - Widget buildServicesInfoCard({required BuildContext context}) { - AppointmentsVM appointmentsVM = context.read(); - return ListView.builder( - shrinkWrap: true, - itemCount: appointmentsVM.serviceAppointmentScheduleList.length, - itemBuilder: (BuildContext context, int scheduleIndex) { - ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: "Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListView.separated( - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: scheduleData.servicesListInAppointment!.length, - itemBuilder: (BuildContext context, int serviceIndex) { - String selectedTimeSlot = ""; - if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) { - selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot; - } - return Column( - children: [ - if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[ - Column( - children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) { - ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex]; - return Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "${serviceData.providerServiceDescription}".toText(fontSize: 16, isBold: true), - ], - ), - Column( - children: List.generate(serviceData.serviceItems!.length, (itemIndex) { - ItemData itemData = serviceData.serviceItems![itemIndex]; - return Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "${itemData.name}: ${itemData.price} SAR".toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor), - ], - ), - ], - ); - }), - ), - ], - ); - }), - ).paddingOnly(bottom: 10), - ], - 5.height, - SizedBox( - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Time & Location".toText(fontSize: 16, isBold: true), - 3.height, - Row(children: [ - "Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at ${selectedTimeSlot}".toText(fontSize: 12, isBold: true), - ]), - Row(children: [ - "Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - (scheduleData.appointmentType == 2 ? "Home" : "Workshop").toText(fontSize: 12, isBold: true), - ]), - ], - ), - ), - 10.height, - Divider(thickness: 0.7), - Builder(builder: (BuildContext context) { - double totalServicePrice = 0.0; - double totalKms = 15.3; - double rangePricePerKm = 5; - totalServicePrice = rangePricePerKm * totalKms; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Amount".toText(fontSize: 16, isBold: true), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Service Charges".toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true), - "${scheduleData.amountTotal.toString()} SAR".toText(fontSize: 16, isBold: true), - ], - ), - if (scheduleData.appointmentType == 1) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Location Charges ($rangePricePerKm x $totalKms )".toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true), - "${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true), - ], - ), - ], - 10.height, - ], - ); - }), - ], - ); - }, - separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2), - ).paddingOnly(bottom: 10), - ], - ), - ], - ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 0)); - }, - ); - } - - Widget buildNextButtonFooter({required BuildContext context}) { - AppointmentsVM appointmentsVM = context.read(); - return Container( - color: MyColors.white, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Divider(thickness: 0.7, height: 3), - 8.height, - if (appointmentsVM.amountToPayForAppointment > 0) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Payable now".toText(fontSize: 14, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - appointmentsVM.amountToPayForAppointment.toString().toText(fontSize: 16, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2), - ], - ) - ], - ).paddingOnly(left: 21, right: 21), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Remaining Amount".toText(fontSize: 14, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - (appointmentsVM.totalAmount - appointmentsVM.amountToPayForAppointment).toString().toText(fontSize: 16, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2), - ], - ) - ], - ).paddingOnly(left: 21, right: 21), - ], - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Total Amount ".toText(fontSize: 18, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - appointmentsVM.totalAmount.toString().toText(fontSize: 29, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), - ], - ) - ], - ).paddingOnly(left: 21, right: 21), - 5.height, - SizedBox( - width: double.infinity, - child: ShowFillButton( - maxHeight: 55, - backgroundColor: MyColors.darkPrimaryColor, - title: "Book Appointment", - onPressed: () { - appointmentsVM.onBookAppointmentPressed(context); - }, - ).paddingOnly(bottom: 12, left: 21, right: 21), - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "Review Appointment", - isRemoveBackButton: false, - isDrawerEnabled: false, - onBackButtonTapped: () => Navigator.pop(context), - ), - body: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListView( - children: [ - buildBranchInfoCard(context: context), - buildServicesInfoCard(context: context), - ], - ).expand(), - buildNextButtonFooter(context: context), - ], - ), - ); - } -} diff --git a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart deleted file mode 100644 index a13af5d..0000000 --- a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart +++ /dev/null @@ -1,195 +0,0 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:mc_common_app/config/routes.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/widgets_models.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/navigator.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; -import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:mc_common_app/widgets/txt_field.dart'; -import 'package:provider/provider.dart'; - -class AppointmentServicePickBottomSheet extends StatelessWidget { - const AppointmentServicePickBottomSheet({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - AppointmentsVM appointmentsVM = context.watch(); - return SizedBox( - height: MediaQuery.of(context).size.height * 0.85, - child: Column( - children: [ - Container( - margin: const EdgeInsets.all(8), - height: 8, - width: 60, - decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))), - ), - 12.height, - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "Select Category".toText(fontSize: 24, isBold: true), - ], - ), - 30.height, - Expanded( - child: ListView( - children: [ - Builder( - builder: (context) { - return DropdownField( - (DropValue value) => appointmentsVM.updateProviderCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), - list: appointmentsVM.branchCategories, - hint: "Select Category", - dropdownValue: appointmentsVM.branchSelectedCategoryId.selectedId != -1 - ? DropValue(appointmentsVM.branchSelectedCategoryId.selectedId, appointmentsVM.branchSelectedCategoryId.selectedOption, "") - : null, - ); - }, - ), - if (appointmentsVM.isFetchingServices) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [const CircularProgressIndicator().paddingAll(10)], - ), - ] else if (appointmentsVM.branchServices.isNotEmpty) ...[ - 8.height, - Builder( - builder: (context) { - List serviceCategories = []; - for (var element in appointmentsVM.branchServices) { - if (element.categoryId == appointmentsVM.branchSelectedCategoryId.selectedId) { - serviceCategories.add(DropValue( - element.serviceProviderServiceId ?? 0, - element.serviceDescription!, - "", - )); - } - } - - return DropdownField( - (DropValue value) => appointmentsVM.updateBranchServiceId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), - list: serviceCategories, - hint: "Select Service", - dropdownValue: appointmentsVM.branchSelectedServiceId.selectedId != -1 - ? DropValue(appointmentsVM.branchSelectedServiceId.selectedId, appointmentsVM.branchSelectedServiceId.selectedOption, "") - : null, - ); - }, - ), - ], - if (appointmentsVM.branchSelectedServiceId.selectedId != -1 && !appointmentsVM.isFetchingServices) ...[ - 16.height, - Row( - children: [ - "Select Service Location".toText( - fontSize: 16, - isBold: true, - color: MyColors.black, - ), - ], - ), - 8.height, - Row( - children: [ - Expanded( - child: ShowFillButton( - isFilled: appointmentsVM.isHomeTapped, - maxHeight: 48, - title: "Home", - txtColor: appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, - onPressed: () => appointmentsVM.updateIsHomeTapped(true), - ), - ), - 12.width, - Expanded( - child: ShowFillButton( - isFilled: !appointmentsVM.isHomeTapped, - txtColor: !appointmentsVM.isHomeTapped ? MyColors.white : MyColors.darkTextColor, - maxHeight: 48, - title: "Workshop", - onPressed: () => appointmentsVM.updateIsHomeTapped(false), - ), - ), - ], - ), - if (appointmentsVM.isHomeTapped) ...[ - 8.height, - TxtField( - hint: 'Pick Home Location', - errorValue: appointmentsVM.pickHomeLocationError, - value: appointmentsVM.pickedHomeLocation, - isNeedClickAll: true, - postfixData: Icons.location_on, - postFixDataColor: MyColors.darkTextColor, - onTap: () { - //TODO: open the place picked to pick the location and save it in provider. - appointmentsVM.updatePickedHomeLocation("PM58+F97, Al Olaya, Riyadh 12333"); - }, - ), - 14.height, - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Icon( - Icons.warning, - color: MyColors.adPendingStatusColor, - size: 19, - ).paddingOnly(bottom: 2), - 3.width, - "Some services are not available on home location.".toText( - color: MyColors.adPendingStatusColor, - fontSize: 12, - isItalic: true, - ), - ], - ), - ] - ], - ], - ), - ), - SizedBox( - width: double.infinity, - child: Column( - children: [ - if (appointmentsVM.isHomeTapped && !appointmentsVM.isFetchingServices) ...[ - const Divider(thickness: 1, height: 1), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - // TODO: This Price will be decided according to the service selected - 150.toString().toText(fontSize: 30, isBold: true), - "SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5), - ], - ), - "These charges are additional to the actual service charges. For heavy items the charges may vary.".toText(fontSize: 12, color: MyColors.lightTextColor), - 22.height, - ], - SizedBox( - width: double.infinity, - child: ShowFillButton( - maxHeight: 55, - backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor, - title: "Next", - onPressed: () { - bool isValidated = appointmentsVM.isServiceSelectionValidated(); - if (isValidated) { - appointmentsVM.getServiceItems(appointmentsVM.branchSelectedServiceId.selectedId); - Navigator.pop(context); - navigateWithName(context, AppRoutes.bookAppointmentsItemView); - } - }, - ), - ), - ], - ), - ).paddingOnly(bottom: 20) - ], - )).horPaddingMain(); - } -} diff --git a/lib/views/appointments/widgets/custom_calender_widget.dart b/lib/views/appointments/widgets/custom_calender_widget.dart deleted file mode 100644 index de5c9b5..0000000 --- a/lib/views/appointments/widgets/custom_calender_widget.dart +++ /dev/null @@ -1,239 +0,0 @@ -import 'dart:developer'; - -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/models/service_schedule_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:table_calendar/table_calendar.dart'; -import 'package:provider/provider.dart'; -import 'package:intl/intl.dart'; - -class CustomCalenderWidget extends StatefulWidget { - final List customTimeDateSlotList; - final int scheduleIndex; - - const CustomCalenderWidget({super.key, required this.customTimeDateSlotList, required this.scheduleIndex}); - - @override - State createState() => _CustomCalenderWidgetState(); -} - -class _CustomCalenderWidgetState extends State { - List allDates = []; - List allMonths = []; - List datesInSelectedMonth = []; - CalendarFormat _calendarFormat = CalendarFormat.month; - - late int selectedMonth; - late int selectedYear; - - DateTime? _selectedDay; - - DateTime _focusedDay = DateTime.now(); - - @override - void initState() { - super.initState(); - populateDateList(); - } - - populateDateList() { - for (var value in widget.customTimeDateSlotList) { - DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date); - DropValue dv = DropValue(dt.month, "${dt.month.getMonthNameByNumber()}, ${dt.year}", "${dt.year}"); - allDates.add(dt); - - if (!ifMonthAlreadyThere(dv)) { - allMonths.add(dv); - } - } - selectedMonth = allDates.first.month; - selectedYear = allDates.first.year; - final appointmentsVM = context.read(); - if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel != null) { - DateTime alreadySelectedDate = DateFormat('dd MMMM, yyyy').parse(appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel!.date!.date); - _selectedDay = alreadySelectedDate; - _focusedDay = alreadySelectedDate; - selectedMonth = alreadySelectedDate.month; - selectedYear = alreadySelectedDate.year; - } - datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList(); - - if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel == null) { - _focusedDay = datesInSelectedMonth.first; - } - } - - bool ifMonthAlreadyThere(DropValue monthDate) { - int index = allMonths.indexWhere((element) => element.id == monthDate.id && element.subValue == monthDate.subValue); - if (index == -1) { - return false; - } - return true; - } - - bool ifDateAlreadyThere(DateTime dt) { - int index = allDates.indexWhere((element) => dt.month == element.month && dt.year == element.year); - if (index == -1) { - return false; - } - return true; - } - - @override - Widget build(BuildContext context) { - return Consumer( - builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Builder(builder: (context) { - return DropdownField( - (DropValue value) { - setState(() { - selectedYear = int.parse(value.value.split(',')[1]); - selectedMonth = value.value.split(',')[0].getMonthNumberByName(); - datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList(); - _focusedDay = datesInSelectedMonth.first; - }); - }, - list: allMonths, - dropdownValue: DropValue(selectedMonth, "${selectedMonth.getMonthNameByNumber()}, ${selectedYear}", "${selectedYear}"), - hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear", - errorValue: "", - showAppointmentPickerVariant: true, - ); - }), - ), - Spacer(), - Icon( - Icons.calendar_today, - color: Colors.black, - size: 18, - ).paddingOnly(right: 10) - ], - ).paddingOnly(left: 6, right: 0), - TableCalendar( - headerVisible: false, - firstDay: datesInSelectedMonth.first, - lastDay: datesInSelectedMonth.last, - focusedDay: _focusedDay, - calendarFormat: _calendarFormat, - weekendDays: [DateTime.friday, DateTime.saturday], - daysOfWeekHeight: 30, - availableGestures: AvailableGestures.none, - daysOfWeekStyle: DaysOfWeekStyle( - weekdayStyle: TextStyle(fontSize: 14, color: MyColors.black), - weekendStyle: TextStyle(fontSize: 14, color: MyColors.black.withOpacity(0.5)), - ), - calendarBuilders: CalendarBuilders( - selectedBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) { - return Container( - height: 50, - width: 50, - margin: EdgeInsets.all(5), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: MyColors.darkIconColor, - ), - alignment: Alignment.center, - child: Text( - dateTime2.day.toString(), - style: TextStyle(color: MyColors.white), - ), - ); - }, - defaultBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) { - int index = datesInSelectedMonth.indexWhere((element) => isSameDay(dateTime1, element)); - if (index == -1) { - return Container( - height: 50, - width: 50, - margin: EdgeInsets.all(5), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - shape: BoxShape.circle, - ), - alignment: Alignment.center, - child: Text( - dateTime1.day.toString(), - ), - ); - } - return Container( - height: 50, - width: 50, - margin: EdgeInsets.all(5), - decoration: BoxDecoration( - border: Border.all(color: Colors.orange, width: 2), - shape: BoxShape.circle, - ), - alignment: Alignment.center, - child: Text( - dateTime1.day.toString(), - ), - ); - }, - disabledBuilder: (BuildContext context, DateTime dateTime1, DateTime selectedDt) { - return Container( - height: 50, - width: 50, - margin: EdgeInsets.all(5), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - shape: BoxShape.circle, - ), - alignment: Alignment.center, - child: Text( - dateTime1.day.toString(), - ), - ); - }, - ), - headerStyle: HeaderStyle(formatButtonVisible: false), - selectedDayPredicate: (day) { - // Use `selectedDayPredicate` to determine which day is currently selected. - // If this returns true, then `day` will be marked as selected. - - // Using `isSameDay` is recommended to disregard - // the time-part of compared DateTime objects. - return isSameDay(_selectedDay, day); - }, - onDaySelected: (selectedDay, focusedDay) { - int index = datesInSelectedMonth.indexWhere((element) => isSameDay(selectedDay, element)); - - if (index == -1) { - return; - } - if (!isSameDay(_selectedDay, selectedDay)) { - setState(() { - _selectedDay = selectedDay; - _focusedDay = focusedDay; - }); - - int dateIndex = widget.customTimeDateSlotList.indexWhere((element) { - DateTime dateFromList = DateFormat('dd MMMM, yyyy').parse(element.date!.date); - if (isSameDay(dateFromList, selectedDay)) { - return true; - } - return false; - }); - - if (dateIndex != -1) { - appointmentsVM.updateSelectedAppointmentDate(scheduleIndex: widget.scheduleIndex, dateIndex: dateIndex); - } - } - }, - ), - ], - ); - }, - ); - } -} diff --git a/lib/views/appointments/widgets/customer_appointment_slider_widget.dart b/lib/views/appointments/widgets/customer_appointment_slider_widget.dart deleted file mode 100644 index afcb0e5..0000000 --- a/lib/views/appointments/widgets/customer_appointment_slider_widget.dart +++ /dev/null @@ -1,209 +0,0 @@ -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; -import 'package:carousel_slider/carousel_slider.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.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/models/appointments_models/appointment_list_model.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/navigator.dart'; -import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:provider/provider.dart'; - -class CustomerAppointmentSliderWidget extends StatelessWidget { - final List myUpComingAppointments; - - const CustomerAppointmentSliderWidget({Key? key, required this.myUpComingAppointments}) : super(key: key); - - @override - Widget build(BuildContext context) { - if (myUpComingAppointments.isEmpty) { - return CustomAddButton( - needsBorder: true, - bgColor: MyColors.white, - onTap: () => context.read().onNavbarTapped(1), - text: "Add New Appointment", - icon: Container( - height: 24, - width: 24, - decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: const Icon(Icons.add, color: MyColors.white), - ), - ).padding(EdgeInsets.symmetric(vertical: 10, horizontal: 21)); - return Container( - height: 86, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - height: 24, - width: 24, - decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: Icon( - Icons.add, - color: MyColors.white, - ), - ), - SizedBox(width: 10), - "Add New Appointment".toText( - fontSize: 15, - isBold: true, - color: MyColors.lightTextColor, - ), - ], - ), - ).onPress(() {}).toWhiteContainer(width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10)); - } - return CarouselSlider.builder( - options: CarouselOptions( - height: 140, - viewportFraction: 1.0, - enlargeCenterPage: false, - enableInfiniteScroll: false, - ), - itemCount: myUpComingAppointments.length, - itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => BuildAppointmentContainerForCustomer( - isForHome: true, - appointmentListModel: myUpComingAppointments[itemIndex], - onTapped: () => navigateWithName(context, AppRoutes.appointmentDetailView, arguments: myUpComingAppointments[itemIndex]), - ), - ); - } -} - -class BuildAppointmentContainerForCustomer extends StatelessWidget { - final bool? isForHome; - final AppointmentListModel? appointmentListModel; - final Function() onTapped; - - const BuildAppointmentContainerForCustomer({Key? key, this.isForHome = false, required this.onTapped, required this.appointmentListModel}) : super(key: key); - - Widget showServices(String title, String icon, {bool isMoreText = false}) { - return Row( - children: [ - if (icon != "") ...[ - SvgPicture.asset(icon), - 8.width, - ], - Flexible( - child: title.toText( - fontSize: 12, - isBold: true, - color: isMoreText ? MyColors.primaryColor : MyColors.black, - ), - ), - ], - ); - } - - List buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) { - if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) { - return [SizedBox()]; - } - - if (appointmentListModel.appointmentServicesList!.length == 1) { - return [ - showServices( - appointmentListModel.appointmentServicesList![0].providerServiceDescription, - MyAssets.modificationsIcon, - ) - ]; - } - - List servicesList = List.generate( - 2, - (index) => showServices(appointmentListModel.appointmentServicesList![index].providerServiceDescription, MyAssets.modificationsIcon), - ); - - if (appointmentListModel.appointmentServicesList!.length > 1) { - servicesList.add( - showServices( - "+ ${appointmentListModel.appointmentServicesList!.length - 1} More", - "", - isMoreText: true, - ), - ); - } - return servicesList; - } - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.only(bottom: 10, left: 21, right: 21), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isForHome != null && isForHome! - ? Image.asset( - MyAssets.bnCar, - width: 56, - height: 56, - fit: BoxFit.fill, - ).toCircle(borderRadius: 100) - : Image.asset( - MyAssets.bnCar, - width: 80, - height: 85, - fit: BoxFit.cover, - ), - 8.width, - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - (appointmentListModel!.providerName ?? "").toText(color: MyColors.black, isBold: true, fontSize: 16), - Row( - children: [ - MyAssets.miniClock.buildSvg(height: 12), - 2.width, - "${appointmentListModel!.duration ?? ""} ${appointmentListModel!.appointmentDate!.toFormattedDateWithoutTime()}".toText( - color: MyColors.lightTextColor, - fontSize: 12, - ), - ], - ), - 9.height, - isForHome != null && isForHome! - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - "Appointment Details".toText( - color: MyColors.primaryColor, - isUnderLine: true, - isBold: true, - fontSize: 14, - ), - const Icon(Icons.arrow_forward), - ], - ) - : Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: Column( - children: buildServicesFromAppointment(appointmentListModel: appointmentListModel!), - ), - ), - const Icon( - Icons.arrow_forward, - ), - ], - ), - ], - ), - ), - ], - ), - ], - ).onPress(onTapped).toWhiteContainer(width: double.infinity, allPading: 12), - ); - } -} diff --git a/lib/views/appointments/widgets/service_item_with_price_checkbox.dart b/lib/views/appointments/widgets/service_item_with_price_checkbox.dart deleted file mode 100644 index f8269c6..0000000 --- a/lib/views/appointments/widgets/service_item_with_price_checkbox.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; - -class ServiceItemWithPriceCheckBox extends StatelessWidget { - final bool isSelected; - final String title, description; - final Widget priceWidget; - - final Function(bool) onSelection; - - const ServiceItemWithPriceCheckBox({ - required this.isSelected, - required this.title, - required this.description, - this.priceWidget = const SizedBox(), - required this.onSelection, - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return SizedBox( - width: double.infinity, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Checkbox( - value: isSelected, - onChanged: (bool? v) { - onSelection(v ?? false); - }, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - title.toText(fontSize: 16, isBold: true).paddingOnly(top: 10), - description.toText(fontSize: 12, color: MyColors.lightTextColor), - priceWidget, - ], - ), - ), - ], - ), - ); - } -} diff --git a/lib/views/dashboard/dashboard_page.dart b/lib/views/dashboard/dashboard_page.dart index d3e87b9..717b142 100644 --- a/lib/views/dashboard/dashboard_page.dart +++ b/lib/views/dashboard/dashboard_page.dart @@ -1,13 +1,10 @@ import 'dart:async'; - -import 'package:car_customer_app/config/customer_routes.dart'; -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; -import 'package:car_customer_app/view_models/requests_view_model.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; +import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:car_customer_app/views/dashboard/fragments/ads_fragment.dart'; import 'package:car_customer_app/views/dashboard/fragments/appointments_fragment.dart'; import 'package:car_customer_app/views/dashboard/fragments/home_fragment.dart'; -import 'package:car_customer_app/views/dashboard/fragments/settings_fragment.dart'; import 'package:car_customer_app/views/dashboard/widgets/bottom_nav_bar.dart'; import 'package:car_customer_app/views/dashboard/widgets/drawer_widget.dart'; import 'package:flutter/material.dart'; @@ -92,7 +89,7 @@ class _DashboardPageState extends State { String getPageTitle(int index) { if (index == 0) { - return "Branches"; + return "Select Branch"; } if (index == 1) { return "Appointments"; @@ -111,12 +108,13 @@ class _DashboardPageState extends State { @override Widget build(BuildContext context) { - bool isHomePage = context.watch().selectedNavbarBarIndex == 2; + DashboardVmCustomer dashboardVM = context.read(); + bool isHomePage = dashboardVM.selectedNavbarBarIndex == 2; return Scaffold( appBar: CustomAppBar( backgroundColor: null, leadingWidth: 100, - title: getPageTitle(context.watch().selectedNavbarBarIndex), + title: getPageTitle(dashboardVM.selectedNavbarBarIndex), profileImageUrl: MyAssets.bnCar, isRemoveBackButton: true, isDrawerEnabled: isHomePage ? true : false, @@ -125,7 +123,7 @@ class _DashboardPageState extends State { ? MyAssets.notificationsBellIcon.buildSvg() : InkWell( onTap: () async { - if (context.read().selectedNavbarBarIndex == 3) { + if (dashboardVM.selectedNavbarBarIndex == 3) { await context.read().populateDataForAdFilter(); navigateWithName(context, AppRoutes.adsFilterView); } @@ -135,9 +133,9 @@ class _DashboardPageState extends State { .paddingOnly(right: 21) ], ), - drawer: CustomDrawer(dashboardVM: context.watch()), + drawer: CustomDrawer(dashboardVM: context.watch()), bottomNavigationBar: CustomBottomNavbar(), - body: fragments[context.watch().selectedNavbarBarIndex], + body: fragments[context.watch().selectedNavbarBarIndex], ); } } diff --git a/lib/views/dashboard/fragments/appointments_fragment.dart b/lib/views/dashboard/fragments/appointments_fragment.dart index 9fb81e8..7e545a8 100644 --- a/lib/views/dashboard/fragments/appointments_fragment.dart +++ b/lib/views/dashboard/fragments/appointments_fragment.dart @@ -1,7 +1,7 @@ -import 'dart:developer'; -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/views/appointments/widgets/customer_appointment_slider_widget.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; +import 'package:mc_common_app/views/appointments/widgets/customer_appointment_slider_widget.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; @@ -18,60 +18,72 @@ class AppointmentsFragment extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - color: MyColors.backgroundColor, - width: double.infinity, - height: double.infinity, - child: Consumer( - builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return Column( - children: [ - 16.height, - FiltersList( - filterList: appointmentsVM.appointmentsFilterOptions, - onFilterTapped: (index, selectedFilterId) { - appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum()); - }), - 16.height, - Expanded( - child: RefreshIndicator( - onRefresh: () async { - appointmentsVM.getMyAppointments(isNeedToRebuild: true); - }, - child: appointmentsVM.state == ViewState.busy - ? const Center(child: CircularProgressIndicator()) - : appointmentsVM.myFilteredAppointments.isEmpty - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - "No Appointments to show.".toText(fontSize: 16, color: MyColors.lightTextColor), - ], - ) - : ListView.builder( - shrinkWrap: true, - itemCount: appointmentsVM.myFilteredAppointments.length, - itemBuilder: (BuildContext context, int index) { - return BuildAppointmentContainerForCustomer( - onTapped: () { - AppointmentListModel appointmentModel = appointmentsVM.myFilteredAppointments[index]; - appointmentModel.appointmentServicesList!.forEach((service) { - double totalServicePrice = 0.0; - service.serviceItems!.forEach((item) { - totalServicePrice = totalServicePrice + (double.parse("${item.price ?? 0.0}")); + return Scaffold( + body: Container( + color: MyColors.backgroundColor, + width: double.infinity, + height: double.infinity, + child: Consumer( + builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { + return Column( + children: [ + 16.height, + FiltersList( + filterList: appointmentsVM.appointmentsFilterOptions, + onFilterTapped: (index, selectedFilterId) { + appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum()); + }), + 16.height, + Expanded( + child: RefreshIndicator( + onRefresh: () async { + appointmentsVM.getMyAppointments(isNeedToRebuild: true); + }, + child: appointmentsVM.state == ViewState.busy + ? const Center(child: CircularProgressIndicator()) + : appointmentsVM.myFilteredAppointments.isEmpty + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + "No Appointments to show.".toText(fontSize: 16, color: MyColors.lightTextColor), + ], + ) + : ListView.builder( + shrinkWrap: true, + itemCount: appointmentsVM.myFilteredAppointments.length, + itemBuilder: (BuildContext context, int index) { + return BuildAppointmentContainerForCustomer( + onTapped: () { + AppointmentListModel appointmentModel = appointmentsVM.myFilteredAppointments[index]; + appointmentModel.appointmentServicesList!.forEach((service) { + double totalServicePrice = 0.0; + service.serviceItems!.forEach((item) { + totalServicePrice = totalServicePrice + (double.parse("${item.price ?? 0.0}")); + }); + service.currentTotalServicePrice = totalServicePrice; }); - service.currentTotalServicePrice = totalServicePrice; - }); - navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentModel); - }, - appointmentListModel: appointmentsVM.myFilteredAppointments[index], - ); - }, - ), + navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentModel); + }, + appointmentListModel: appointmentsVM.myFilteredAppointments[index], + ); + }, + ), + ), ), - ), - ], - ); + ], + ); + }, + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () async { + context.read().onNavbarTapped(0); }, + backgroundColor: MyColors.darkPrimaryColor, + child: Icon( + Icons.add, + color: MyColors.white, + ), ), ); } diff --git a/lib/views/dashboard/fragments/branches_fragment.dart b/lib/views/dashboard/fragments/branches_fragment.dart index c2b2dfc..a084265 100644 --- a/lib/views/dashboard/fragments/branches_fragment.dart +++ b/lib/views/dashboard/fragments/branches_fragment.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index cf384cd..f05725b 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -1,6 +1,6 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; -import 'package:car_customer_app/views/appointments/widgets/customer_appointment_slider_widget.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; +import 'package:mc_common_app/views/appointments/widgets/customer_appointment_slider_widget.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/utils/enums.dart'; @@ -30,7 +30,7 @@ class HomeFragment extends StatelessWidget { title: "Upcoming Appointment".toUpperCase(), subTitle: "View All", onSubtitleTapped: () { - context.read().onNavbarTapped(1); + context.read().onNavbarTapped(1); context.read().applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); }, ).horPaddingMain(), @@ -40,7 +40,7 @@ class HomeFragment extends StatelessWidget { title: "My Recent Service Providers".toUpperCase(), subTitle: "View All", onSubtitleTapped: () { - context.read().onNavbarTapped(0); + context.read().onNavbarTapped(0); context.read().applyFilterOnProviders(index: 0); }).horPaddingMain(), Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { @@ -58,7 +58,7 @@ class HomeFragment extends StatelessWidget { title: "My Active Ads".toUpperCase(), subTitle: "View All", onSubtitleTapped: () { - context.read().onNavbarTapped(3); + context.read().onNavbarTapped(3); context.read().updateIsExploreAds(false); }).horPaddingMain(), BuildAdsList( @@ -78,7 +78,7 @@ class HomeFragment extends StatelessWidget { title: "My Recommended Ads".toUpperCase(), subTitle: "View All", onSubtitleTapped: () { - context.read().onNavbarTapped(3); + context.read().onNavbarTapped(3); context.read().updateIsExploreAds(true); context.read().applyFilterOnExploreAds(index: 0, createdByRoleFilter: CreatedByRoleEnum.allAds); }, diff --git a/lib/views/dashboard/fragments/requests_fragment.dart b/lib/views/dashboard/fragments/requests_fragment.dart index dfad7fb..303053f 100644 --- a/lib/views/dashboard/fragments/requests_fragment.dart +++ b/lib/views/dashboard/fragments/requests_fragment.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/requests_view_model.dart'; +import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:car_customer_app/views/requests/widget/request_item.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/config/routes.dart'; diff --git a/lib/views/dashboard/widgets/bottom_nav_bar.dart b/lib/views/dashboard/widgets/bottom_nav_bar.dart index 7cdcb4c..9897604 100644 --- a/lib/views/dashboard/widgets/bottom_nav_bar.dart +++ b/lib/views/dashboard/widgets/bottom_nav_bar.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -13,7 +13,7 @@ class CustomBottomNavbar extends StatelessWidget { @override Widget build(BuildContext context) { - DashboardVM dashboardVM = context.watch(); + DashboardVmCustomer dashboardVM = context.watch(); return BottomNavigationBar( items: [ BottomNavigationBarItem( diff --git a/lib/views/dashboard/widgets/drawer_widget.dart b/lib/views/dashboard/widgets/drawer_widget.dart index 52a1f80..36a0cd3 100644 --- a/lib/views/dashboard/widgets/drawer_widget.dart +++ b/lib/views/dashboard/widgets/drawer_widget.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/dashboard_view_model.dart'; +import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; @@ -16,7 +16,7 @@ import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class CustomDrawer extends StatefulWidget { - final DashboardVM dashboardVM; + final DashboardVmCustomer dashboardVM; const CustomDrawer({Key? key, required this.dashboardVM}) : super(key: key); diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index 142aee8..338e7ec 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:car_customer_app/views/provider/sheet/items_list_sheet.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; diff --git a/lib/views/provider/provider_profile_page.dart b/lib/views/provider/provider_profile_page.dart index 3071156..7c029da 100644 --- a/lib/views/provider/provider_profile_page.dart +++ b/lib/views/provider/provider_profile_page.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; diff --git a/lib/views/provider/sheet/items_list_sheet.dart b/lib/views/provider/sheet/items_list_sheet.dart index 2ab4dc7..2b6feeb 100644 --- a/lib/views/provider/sheet/items_list_sheet.dart +++ b/lib/views/provider/sheet/items_list_sheet.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/appointments_view_model.dart'; +import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; diff --git a/lib/views/requests/create_request_page.dart b/lib/views/requests/create_request_page.dart index 75445a5..38e0e89 100644 --- a/lib/views/requests/create_request_page.dart +++ b/lib/views/requests/create_request_page.dart @@ -1,4 +1,4 @@ -import 'package:car_customer_app/view_models/requests_view_model.dart'; +import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; diff --git a/lib/views/requests/widget/request_item.dart b/lib/views/requests/widget/request_item.dart index 08cbd78..7844b0a 100644 --- a/lib/views/requests/widget/request_item.dart +++ b/lib/views/requests/widget/request_item.dart @@ -1,5 +1,4 @@ -import 'package:car_customer_app/view_models/requests_view_model.dart'; -import 'package:car_customer_app/views/requests/widget/request_status_chip.dart'; +import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; @@ -15,7 +14,7 @@ import 'package:provider/provider.dart'; class RequestItem extends StatelessWidget { final RequestModel request; - RequestItem({required this.request}); + RequestItem({required this.request}); @override Widget build(BuildContext context) { diff --git a/pubspec.yaml b/pubspec.yaml index 6d94c35..a7d4453 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,7 +34,6 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - table_calendar: ^3.0.9 mc_common_app: path: /Volumes/Data/Projects/Flutter/car_common_app