diff --git a/lib/config/customer_dependencies.dart b/lib/config/customer_dependencies.dart index 804a53f..7f5f1fb 100644 --- a/lib/config/customer_dependencies.dart +++ b/lib/config/customer_dependencies.dart @@ -1,12 +1,12 @@ import 'package:car_customer_app/repositories/provider_repo.dart'; -import 'package:car_customer_app/repositories/schedule_repo.dart'; +import 'package:car_customer_app/repositories/appointment_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(() => ScheduleRepoImp()); } } diff --git a/lib/main.dart b/lib/main.dart index bd7ca33..e526cf1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,7 @@ 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/schedule_repo.dart'; +import 'package:car_customer_app/repositories/appointment_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:easy_localization/easy_localization.dart'; @@ -56,7 +56,7 @@ Future main() async { ), ChangeNotifierProvider( create: (_) => AppointmentsVM( - scheduleRepo: injector.get(), + scheduleRepo: injector.get(), providerRepo: injector.get(), commonServices: injector.get(), commonRepo: injector.get(), diff --git a/lib/repositories/schedule_repo.dart b/lib/repositories/appointment_repo.dart similarity index 68% rename from lib/repositories/schedule_repo.dart rename to lib/repositories/appointment_repo.dart index 3ea0083..dc25367 100644 --- a/lib/repositories/schedule_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -1,3 +1,5 @@ +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'; @@ -7,8 +9,9 @@ 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 ScheduleRepo { +abstract class AppointmentRepo { Future getAllServices(String branchId); Future createSchedule(Map map); @@ -26,10 +29,12 @@ abstract class ScheduleRepo { required List serviceItemIdsForWorkshop, }); - Future createServiceAppointment({required List serviceItemIds, required int serviceSlotID}); + Future createServiceAppointment({required List schedules, required int serviceProviderID}); + + Future cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}); } -class ScheduleRepoImp implements ScheduleRepo { +class ScheduleRepoImp implements AppointmentRepo { @override Future getAllServices(String branchId) async { Map map = {"ProviderBranchID": branchId}; @@ -98,26 +103,57 @@ class ScheduleRepoImp implements ScheduleRepo { token: t, ); List serviceAppointmentScheduleModel = - List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index])); + List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index], isForAppointment: true)); return serviceAppointmentScheduleModel; } - Future createServiceAppointment({required List serviceItemIds, required int serviceSlotID}) async { + 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 ?? ""; - var queryParameters = { - "id": 0, + + final payload = { + "serviceAppointmentID": serviceAppointmentID, "serviceSlotID": serviceSlotID, - "appointmentStatusID": 0, - "serviceProviderID": 0, - "customerID": 0, - "isActive": true, - "serviceItemID": [11] + "appointmentScheduleAction": appointmentScheduleAction, }; + GenericRespModel adsGenericModel = await injector.get().postJsonForObject( (json) => GenericRespModel.fromJson(json), - ApiConsts.ServiceProvidersAppointmentCreate, - queryParameters, + ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment, + payload, token: t, ); + + return adsGenericModel; } } diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index e5a4d38..d87f3be 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,15 +1,14 @@ -import 'dart:developer'; - import 'package:car_customer_app/repositories/provider_repo.dart'; -import 'package:car_customer_app/repositories/schedule_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/widgets/appointment_service_pick_bottom_sheet.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_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'; @@ -23,21 +22,25 @@ 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 ScheduleRepo scheduleRepo; + 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 = []; @@ -50,22 +53,6 @@ class AppointmentsVM extends BaseVM { List serviceAppointmentScheduleList = []; - // Future getSchedulesByBranchId() async { - // availableSchedules = await scheduleRepo.getSchedules(selectedBranchModel!.id!.toString()); - // log("schedules: ${availableSchedules.toString()}"); - // notifyListeners(); - // } - - List servicesInSchedule = []; - - bool ifServiceAlreadyThere(int id) { - int index = servicesInSchedule.indexWhere((element) => element.id == id); - if (index == -1) { - return false; - } - return true; - } - bool ifItemAlreadySelected(int id) { int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id); if (indexFound != -1) { @@ -96,14 +83,73 @@ class AppointmentsVM extends BaseVM { Future onBookAppointmentPressed(BuildContext context) async { Utils.showLoading(context); + bool isSuccess = false; + List appointmentIdsList = []; try { - serviceAppointmentScheduleList.forEach((schedule) async { - List serviceItemIds = []; - // schedule.serviceItemList!.forEach((serviceItem) { - // serviceItemIds.add(serviceItem.id.toString()); - // }); - await scheduleRepo.createServiceAppointment(serviceItemIds: serviceItemIds, serviceSlotID: schedule.selectedCustomTimeDateSlotModel!.date!.slotId); - }); + 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 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()}"); } @@ -160,6 +206,11 @@ class AppointmentsVM extends BaseVM { currentServiceSelection = null; } + resetAfterBookingAppointment() { + servicesInCurrentAppointment.clear(); + allSelectedItemsInAppointments.clear(); + } + populateAppointmentsFilterList() { appointmentsFilterOptions.clear(); appointmentsFilterOptions = [ @@ -172,18 +223,29 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } - applyFilterOnAppointmentsVM({required int index}) { + applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) { if (appointmentsFilterOptions.isEmpty) return; for (var value in appointmentsFilterOptions) { value.isSelected = false; } - appointmentsFilterOptions[index].isSelected = true; + appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum() == -1 ? 0 : appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true; + + if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == -1) { + myFilteredAppointments = myAppointments; + notifyListeners(); + return; + } + + myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList(); notifyListeners(); } Future getMyAppointments() async { isFetchingLists = true; myAppointments = await commonRepo.getMyAppointments(); + myFilteredAppointments = myAppointments; + myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList(); + // applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); isFetchingLists = false; notifyListeners(); } @@ -259,7 +321,7 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } - populateProvidersFilterList() { + populateBranchesFilterList() { providersFilterOptions.clear(); providersFilterOptions = [ FilterListModel(title: "All Providers", isSelected: true, id: -1), @@ -455,7 +517,7 @@ class AppointmentsVM extends BaseVM { crossAxisAlignment: CrossAxisAlignment.end, children: [ (selectedService.isHomeSelected - ? "${(selectedService.currentTotalServicePrice ?? 0.0) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" + ? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" : "${selectedService.currentTotalServicePrice}") .toText(fontSize: 29, isBold: true), 2.width, @@ -515,10 +577,6 @@ class AppointmentsVM extends BaseVM { } }); - servicesInSchedule.clear(); - - //TODO: WE HAVE TO ADD PARAMETER IN THE allSelectedItemsInAppointments TO DECIDE WHETHER THE APPOINTMENT IS FOR HOME OR WORKSHOP - serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, @@ -529,16 +587,12 @@ class AppointmentsVM extends BaseVM { 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); - - schedule.servicesListInAppointment!.forEach((service) { - if (!ifServiceAlreadyThere(service.serviceProviderServiceId!)) { - servicesInSchedule.add(DropValue(service.serviceProviderServiceId!, service.providerServiceDescription!, "")); - } - }); + totalAmount = totalAmount + (schedule.amountTotal ?? 0.0); }, ); Utils.hideLoading(context); diff --git a/lib/views/appointments/appointment_detail_view.dart b/lib/views/appointments/appointment_detail_view.dart index 718d69d..5b8d01d 100644 --- a/lib/views/appointments/appointment_detail_view.dart +++ b/lib/views/appointments/appointment_detail_view.dart @@ -1,13 +1,18 @@ +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; @@ -21,6 +26,97 @@ class AppointmentDetailView extends StatelessWidget { "Oil Change", ]; + 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: () {}, 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(); + } + } + + 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) { return Scaffold( @@ -52,29 +148,42 @@ class AppointmentDetailView extends StatelessWidget { ], ), 13.height, - Row( - children: [ - MyAssets.maintenanceIcon.buildSvg( - height: 10, - width: 10, - fit: BoxFit.fill, - ), - 10.width, - "Maintenance".toText(fontSize: 18, isBold: true), - ], - ), - Column( - children: servicesList - .map((e) => e - .toText( - textAlign: TextAlign.start, - fontSize: 13, - isBold: true, - color: MyColors.lightTextColor, - ) - .paddingOnly(bottom: 5)) - .toList(), - ).paddingOnly(left: 15), + 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: 18, 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: 13, + isBold: true, + color: MyColors.lightTextColor, + ), + ), + ).paddingOnly(left: 15), + ], + ], + ); + }), + ), + ], 15.height, Row( children: [ @@ -83,43 +192,20 @@ class AppointmentDetailView extends StatelessWidget { onCardTapped: () {}, icon: MyAssets.scheduleAppointmentIcon.buildSvg(), ), - 10.width, - CardButtonWithIcon( - title: "Pay for Appointment", - onCardTapped: () {}, - icon: MyAssets.creditCardIcon.buildSvg(), - ), + if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[ + 10.width, + CardButtonWithIcon( + title: "Pay for Appointment", + onCardTapped: () {}, + icon: MyAssets.creditCardIcon.buildSvg(), + ), + ], ], ), 15.height, ], ).toWhiteContainer(width: double.infinity, allPading: 12), - Align( - alignment: Alignment.bottomCenter, - child: Row( - children: [ - Expanded( - child: ShowFillButton( - maxHeight: 55, - title: "Cancel", - onPressed: () {}, - backgroundColor: MyColors.redColor, - ), - ), - if (appointmentListModel.appointmentStatusID == 1) ...[ - 12.width, - Expanded( - child: ShowFillButton( - maxHeight: 55, - title: "Confirm", - onPressed: () {}, - backgroundColor: MyColors.greenColor, - ), - ), - ], - ], - ), - ), + 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 index 8b37974..d6614d7 100644 --- a/lib/views/appointments/book_appointment_schedules_view.dart +++ b/lib/views/appointments/book_appointment_schedules_view.dart @@ -1,22 +1,15 @@ import 'package:car_customer_app/view_models/appointments_view_model.dart'; -import 'package:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.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/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/service_schedule_model.dart'; -import 'package:mc_common_app/models/services/item_model.dart'; -import 'package:mc_common_app/models/widgets_models.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/navigator.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/common_widgets/info_bottom_sheet.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'; import 'package:provider/provider.dart'; @@ -70,13 +63,13 @@ class BookAppointmentSchedulesView extends StatelessWidget { ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, - itemCount: appointmentsVM.servicesInSchedule.length, + itemCount: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment!.length, itemBuilder: (BuildContext context, int serviceIndex) { - DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex]; + ServiceModel selectedService = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment![serviceIndex]; return Row( children: [ Expanded( - child: ("${serviceIndex + 1}. ${selectedService.value}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor), + child: ("${serviceIndex + 1}. ${selectedService.providerServiceDescription}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor), ), ], ); @@ -89,18 +82,7 @@ class BookAppointmentSchedulesView extends StatelessWidget { children: [ Column( children: [ - if (true) ...[ - // SizedBox( - // width: double.infinity, - // child: BuildDateSlotsForAppointment( - // customDateSlots: scheduleData.customTimeDateSlotList ?? [], - // onPressed: (dateIndex) { - // appointmentsVM.updateSelectedAppointmentDate(scheduleIndex: scheduleIndex, dateIndex: dateIndex); - // }, - // ), - // ), - CustomCalenderWidget(customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? []), - ], + CustomCalenderWidget(customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? [], scheduleIndex: scheduleIndex), if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[ 5.height, Row( @@ -135,7 +117,7 @@ class BookAppointmentSchedulesView extends StatelessWidget { txtColor: MyColors.black, maxHeight: 55, title: "Cancel", - onPressed: () {}, + onPressed: () => Navigator.pop(context), backgroundColor: MyColors.greyButtonColor, ), ), diff --git a/lib/views/appointments/book_appointment_services_view.dart b/lib/views/appointments/book_appointment_services_view.dart index cad86a8..c149114 100644 --- a/lib/views/appointments/book_appointment_services_view.dart +++ b/lib/views/appointments/book_appointment_services_view.dart @@ -104,7 +104,11 @@ class BookAppointmentServicesView extends StatelessWidget { txtColor: MyColors.black, maxHeight: 55, title: "Cancel", - onPressed: () {}, + onPressed: () { + appointmentsVM.servicesInCurrentAppointment.clear(); + appointmentsVM.allSelectedItemsInAppointments.clear(); + Navigator.pop(context); + }, backgroundColor: MyColors.greyButtonColor, ), ), diff --git a/lib/views/appointments/review_appointment_view.dart b/lib/views/appointments/review_appointment_view.dart index 5862e51..ff4d5ae 100644 --- a/lib/views/appointments/review_appointment_view.dart +++ b/lib/views/appointments/review_appointment_view.dart @@ -1,3 +1,5 @@ +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'; @@ -5,6 +7,7 @@ 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'; @@ -93,7 +96,7 @@ class ReviewAppointment extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: "Schedule: ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true), + child: "Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), ), ], ), @@ -103,7 +106,7 @@ class ReviewAppointment extends StatelessWidget { ListView.separated( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, - itemCount: appointmentsVM.servicesInSchedule.length, + itemCount: scheduleData.servicesListInAppointment!.length, itemBuilder: (BuildContext context, int serviceIndex) { String selectedTimeSlot = ""; if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) { @@ -111,33 +114,38 @@ class ReviewAppointment extends StatelessWidget { } return Column( children: [ - // Row( - // children: [ - // Expanded( - // child: selectedService.value.toText(fontSize: 14, isBold: true), - // ), - // ], - // ), - if (true) ...[ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - (appointmentsVM.isHomeTapped ? "Home" : "Workshop").toText(fontSize: 12, isBold: true).expand(), - ], - ), - 5.height, + if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[ Column( - children: List.generate(scheduleData.servicesListInAppointment!.length, (itemIndex) { - ServiceModel serviceData = scheduleData.servicesListInAppointment![itemIndex]; - return Row( - crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) { + ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex]; + return Column( children: [ - "${serviceData.providerServiceDescription}".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), + 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( @@ -145,7 +153,7 @@ class ReviewAppointment extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "Time & Location".toText(fontSize: 14, isBold: true), + "Time & Location".toText(fontSize: 16, isBold: true), 3.height, Row(children: [ "Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), @@ -153,11 +161,43 @@ class ReviewAppointment extends StatelessWidget { ]), Row(children: [ "Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, 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, + ], + ); + }), ], ); }, @@ -171,111 +211,60 @@ class ReviewAppointment extends StatelessWidget { ); } - Widget buildTimeAndLocationInfoCard() { - return SizedBox( - width: double.infinity, + Widget buildNextButtonFooter({required BuildContext context}) { + AppointmentsVM appointmentsVM = context.read(); + return Container( + color: MyColors.white, child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Time & Location".toText(fontSize: 16, isBold: true), - 3.height, - Row(children: [ - "Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "2nd Feb, 2023 at 09:30 AM".toText(fontSize: 12, isBold: true), - ]), - Row(children: [ - "Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, isBold: true), - ]), - ], - ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10)), - ); - } - - Widget buildChargesBreakDown({required BuildContext context}) { - AppointmentsVM appointmentsVM = context.read(); - List allSelectedItems = []; - double totalServicePrice = 0.0; - // appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) { - // schedule.servicesListInAppointment!.forEach((service) { - // allSelectedItems.add(item); - // totalServicePrice = totalServicePrice + double.parse(item.price!); - // }); - // }); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Services".toText(fontSize: 16, isBold: true), - Column( - children: List.generate( - allSelectedItems.length, - (index) => Row( + Divider(thickness: 0.7, height: 3), + 8.height, + if (appointmentsVM.amountToPayForAppointment > 0) ...[ + Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "${allSelectedItems[index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "${allSelectedItems[index].price} SAR".toText(fontSize: 12, isBold: true), + "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), + ], + ) ], - ), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - "${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true), + ).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), ], - ), - 10.height, - Divider(thickness: 0.7), - if (appointmentsVM.isHomeTapped) ...[ - "Home Location".toText(fontSize: 16, isBold: true), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "5 x 10".toText(fontSize: 12, isBold: true), - ], - ), - 8.height, - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - "50 SAR".toText(fontSize: 16, isBold: true), + "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), + ], + ) ], - ), - 10.height, - Divider(thickness: 0.7), - ], - 10.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Total Amount ".toText(fontSize: 16, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - totalServicePrice.toString().toText(fontSize: 29, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), - ], - ) - ], - ), - 10.height, - ], - ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21)); - } - - Widget buildNextButtonFooter({required BuildContext context}) { - AppointmentsVM appointmentsVM = context.read(); - return Container( - height: 90, - color: MyColors.white, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Divider(thickness: 0.7, height: 3), - 10.height, + ).paddingOnly(left: 21, right: 21), + 5.height, SizedBox( width: double.infinity, child: ShowFillButton( @@ -283,7 +272,7 @@ class ReviewAppointment extends StatelessWidget { backgroundColor: MyColors.darkPrimaryColor, title: "Book Appointment", onPressed: () { - // appointmentsVM.onBookAppointmentPressed(); + appointmentsVM.onBookAppointmentPressed(context); }, ).paddingOnly(bottom: 12, left: 21, right: 21), ), @@ -299,7 +288,6 @@ class ReviewAppointment extends StatelessWidget { title: "Review Appointment", isRemoveBackButton: false, isDrawerEnabled: false, - actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], onBackButtonTapped: () => Navigator.pop(context), ), body: Column( @@ -309,8 +297,6 @@ class ReviewAppointment extends StatelessWidget { children: [ buildBranchInfoCard(context: context), buildServicesInfoCard(context: context), - // buildTimeAndLocationInfoCard(), - buildChargesBreakDown(context: context), ], ).expand(), buildNextButtonFooter(context: context), diff --git a/lib/views/appointments/widgets/custom_calender_widget.dart b/lib/views/appointments/widgets/custom_calender_widget.dart index 7b86c0d..de5c9b5 100644 --- a/lib/views/appointments/widgets/custom_calender_widget.dart +++ b/lib/views/appointments/widgets/custom_calender_widget.dart @@ -2,7 +2,6 @@ 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/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/theme/colors.dart'; @@ -13,9 +12,10 @@ import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; class CustomCalenderWidget extends StatefulWidget { - final List? customTimeDateSlotList; + final List customTimeDateSlotList; + final int scheduleIndex; - const CustomCalenderWidget({super.key, required this.customTimeDateSlotList}); + const CustomCalenderWidget({super.key, required this.customTimeDateSlotList, required this.scheduleIndex}); @override State createState() => _CustomCalenderWidgetState(); @@ -41,22 +41,30 @@ class _CustomCalenderWidgetState extends State { } populateDateList() { - for (var value in widget.customTimeDateSlotList!) { + for (var value in widget.customTimeDateSlotList) { DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date); - // TODO: THIS COMPARISON NEEDS TO BE FIXED!!!!! - // TODO: BECAUSE WE CAN ONLY VALUE IN DROPDOWN, SO SUBVALUE IS OF NO USE!! - - DropValue dv = DropValue(dt.month, "${dt.month.getMonthNameByNumber()}, ${dt.year}", ""); + 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) { @@ -64,7 +72,6 @@ class _CustomCalenderWidgetState extends State { if (index == -1) { return false; } - return true; } @@ -73,7 +80,6 @@ class _CustomCalenderWidgetState extends State { if (index == -1) { return false; } - return true; } @@ -93,10 +99,12 @@ class _CustomCalenderWidgetState extends State { 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(1, "${selectedMonth.getMonthNameByNumber()}jhvk,", "${selectedYear}"), + dropdownValue: DropValue(selectedMonth, "${selectedMonth.getMonthNameByNumber()}, ${selectedYear}", "${selectedYear}"), hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear", errorValue: "", showAppointmentPickerVariant: true, @@ -125,22 +133,6 @@ class _CustomCalenderWidgetState extends State { weekendStyle: TextStyle(fontSize: 14, color: MyColors.black.withOpacity(0.5)), ), calendarBuilders: CalendarBuilders( - todayBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) { - return Container( - height: 50, - width: 50, - margin: EdgeInsets.all(5), - decoration: BoxDecoration( - color: Colors.blueAccent.withOpacity(0.4), - border: Border.all(color: Colors.orange, width: 2), - shape: BoxShape.circle, - ), - alignment: Alignment.center, - child: Text( - dateTime1.day.toString(), - ), - ); - }, selectedBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) { return Container( height: 50, @@ -158,6 +150,22 @@ class _CustomCalenderWidgetState extends State { ); }, 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, @@ -198,12 +206,28 @@ class _CustomCalenderWidgetState extends State { return isSameDay(_selectedDay, day); }, onDaySelected: (selectedDay, focusedDay) { + int index = datesInSelectedMonth.indexWhere((element) => isSameDay(selectedDay, element)); + + if (index == -1) { + return; + } if (!isSameDay(_selectedDay, selectedDay)) { - // Call `setState()` when updating the selected day setState(() { _selectedDay = selectedDay; - _focusedDay = 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 index 7cfb819..afcb0e5 100644 --- a/lib/views/appointments/widgets/customer_appointment_slider_widget.dart +++ b/lib/views/appointments/widgets/customer_appointment_slider_widget.dart @@ -1,3 +1,4 @@ +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'; @@ -8,7 +9,9 @@ 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; @@ -18,31 +21,41 @@ class CustomerAppointmentSliderWidget extends StatelessWidget { @override Widget build(BuildContext context) { if (myUpComingAppointments.isEmpty) { - return InkWell( - child: 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, + 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, + ), + ], ), - ).toWhiteContainer(width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10)); + ).onPress(() {}).toWhiteContainer(width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10)); } return CarouselSlider.builder( options: CarouselOptions( @@ -87,14 +100,14 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget { } List buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) { - if (appointmentListModel.serviceAppointmentItems == null || appointmentListModel.serviceAppointmentItems!.isEmpty) { + if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) { return [SizedBox()]; } - if (appointmentListModel.serviceAppointmentItems!.length == 1) { + if (appointmentListModel.appointmentServicesList!.length == 1) { return [ showServices( - appointmentListModel.serviceAppointmentItems![0].serviceItemName!, + appointmentListModel.appointmentServicesList![0].providerServiceDescription, MyAssets.modificationsIcon, ) ]; @@ -102,16 +115,13 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget { List servicesList = List.generate( 2, - (index) => showServices( - appointmentListModel.serviceAppointmentItems![index].serviceItemName!, - MyAssets.modificationsIcon, - ), + (index) => showServices(appointmentListModel.appointmentServicesList![index].providerServiceDescription, MyAssets.modificationsIcon), ); - if (appointmentListModel.serviceAppointmentItems!.length > 1) { + if (appointmentListModel.appointmentServicesList!.length > 1) { servicesList.add( showServices( - "+ ${appointmentListModel.serviceAppointmentItems!.length - 1} More", + "+ ${appointmentListModel.appointmentServicesList!.length - 1} More", "", isMoreText: true, ), diff --git a/lib/views/dashboard/dashboard_page.dart b/lib/views/dashboard/dashboard_page.dart index 7145d88..83ca892 100644 --- a/lib/views/dashboard/dashboard_page.dart +++ b/lib/views/dashboard/dashboard_page.dart @@ -34,30 +34,30 @@ class _DashboardPageState extends State { void initState() { super.initState(); // dashboardVM = Provider.of(context, listen: false); - fetchUsername(); scheduleMicrotask(() { context.read().populateAppointmentsFilterList(); - context.read().populateProvidersFilterList(); + context.read().populateBranchesFilterList(); context.read().populateAdsFilterList(); - context.read().getAllNearBranches(); _onRefresh(); }); } Future _onRefresh() async { - AdVM adVm = Provider.of(context, listen: false); + AdVM adVM = Provider.of(context, listen: false); AppointmentsVM appointmentsVM = Provider.of(context, listen: false); if (appointmentsVM.myAppointments.isEmpty) { await appointmentsVM.getMyAppointments(); } - if (adVm.myAds.isEmpty) { - await adVm.getMyAds(); + if (appointmentsVM.nearbyBranches.isEmpty) { + await appointmentsVM.getAllNearBranches(); } - if (adVm.exploreAds.isEmpty) { - await adVm.getExploreAds(); + if (adVM.myAds.isEmpty) { + await adVM.getMyAds(); + } + if (adVM.exploreAds.isEmpty) { + await adVM.getExploreAds(); } - final adVM = context.read(); if (adVM.vehicleTypes.isEmpty) { await adVM.getVehicleTypes(); } @@ -74,8 +74,6 @@ class _DashboardPageState extends State { ); } - fetchUsername() async {} - List fragments = [ const BranchesFragment(), const AppointmentsFragment(), @@ -106,7 +104,6 @@ class _DashboardPageState extends State { @override Widget build(BuildContext context) { bool isHomePage = context.watch().selectedNavbarBarIndex == 2; - bool isAdsPage = context.watch().selectedNavbarBarIndex == 3; return Scaffold( appBar: CustomAppBar( backgroundColor: null, diff --git a/lib/views/dashboard/fragments/appointments_fragment.dart b/lib/views/dashboard/fragments/appointments_fragment.dart index aff1704..deefa02 100644 --- a/lib/views/dashboard/fragments/appointments_fragment.dart +++ b/lib/views/dashboard/fragments/appointments_fragment.dart @@ -25,11 +25,11 @@ class AppointmentsFragment extends StatelessWidget { 16.height, FiltersList( filterList: appointmentsVM.appointmentsFilterOptions, - onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(index: index), + onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum()), ), 16.height, Expanded( - child: appointmentsVM.myAppointments.isEmpty + child: appointmentsVM.myFilteredAppointments.isEmpty ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -38,15 +38,15 @@ class AppointmentsFragment extends StatelessWidget { ) : ListView.builder( shrinkWrap: true, - itemCount: appointmentsVM.myAppointments.length, + itemCount: appointmentsVM.myFilteredAppointments.length, itemBuilder: (BuildContext context, int index) { return BuildAppointmentContainerForCustomer( onTapped: () => navigateWithName( context, AppRoutes.appointmentDetailView, - arguments: appointmentsVM.myAppointments[index], + arguments: appointmentsVM.myFilteredAppointments[index], ), - appointmentListModel: appointmentsVM.myAppointments[index], + appointmentListModel: appointmentsVM.myFilteredAppointments[index], ); }, ), diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index 6a219cc..8690b6d 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -32,20 +32,21 @@ class HomeFragment extends StatelessWidget { subTitle: "View All", onSubtitleTapped: () { context.read().onNavbarTapped(1); - context.read().applyFilterOnAppointmentsVM(index: 0); + context.read().applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); }, ).horPaddingMain(), - CustomerAppointmentSliderWidget(myUpComingAppointments: context.watch().myAppointments), + CustomerAppointmentSliderWidget(myUpComingAppointments: context.read().myUpComingAppointments), 7.height, ViewAllWidget( title: "My Recent Service Providers".toUpperCase(), subTitle: "View All", onSubtitleTapped: () { - print("value: ${AppState().getUser.data!.accessToken}"); context.read().onNavbarTapped(0); context.read().applyFilterOnProviders(index: 0); }).horPaddingMain(), - const ServiceProviderWidget().horPaddingMain(), + Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { + return ServiceProviderWidget(nearbyBranches: context.read().nearbyBranches).horPaddingMain(); + }), Consumer( builder: (BuildContext context, AdVM adVM, Widget? child) { return Column( diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index 0f26312..268ff39 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -94,13 +94,7 @@ class _BranchDetailPageState extends State { color: MyColors.primaryColor, ), ], - ) - .padding( - EdgeInsets.symmetric(vertical: 6, horizontal: 2), - ) - .onPress( - () {}, - ), + ).padding(EdgeInsets.symmetric(vertical: 6, horizontal: 2)), Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -119,14 +113,8 @@ class _BranchDetailPageState extends State { ), ], ) - .padding( - EdgeInsets.symmetric(vertical: 6, horizontal: 2), - ) - .onPress( - () { - navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchDetailModel.serviceProviderId); - }, - ), + .padding(EdgeInsets.symmetric(vertical: 6, horizontal: 2)) + .onPress(() => navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchDetailModel.serviceProviderId)), ], ), 20.height,