diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index 5075082..1b55355 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -29,7 +29,9 @@ class CustomerAppRoutes { AppRoutes.adsSearchFilterScreen: (context) => AdsSearchFilterView(), AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(isProvider: ModalRoute.of(context)!.settings.arguments as bool), AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), - AppRoutes.bookAppointmenSchedulesView: (context) => BookAppointmentSchedulesView(), + AppRoutes.bookAppointmenSchedulesView: (context) => BookAppointmentSchedulesView( + screenArgumentsForAppointmentDetailPage: ModalRoute.of(context)!.settings.arguments as ScreenArgumentsForAppointmentDetailPage, + ), AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes), diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index d87f3be..ce6a26b 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,6 +1,7 @@ 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'; @@ -127,6 +128,11 @@ class AppointmentsVM extends BaseVM { } } + 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 { @@ -209,6 +215,7 @@ class AppointmentsVM extends BaseVM { resetAfterBookingAppointment() { servicesInCurrentAppointment.clear(); allSelectedItemsInAppointments.clear(); + serviceAppointmentScheduleList.clear(); } populateAppointmentsFilterList() { @@ -597,8 +604,70 @@ class AppointmentsVM extends BaseVM { ); Utils.hideLoading(context); - navigateWithName(context, AppRoutes.bookAppointmenSchedulesView); + 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/views/appointments/appointment_detail_view.dart b/lib/views/appointments/appointment_detail_view.dart index 5b8d01d..ac79906 100644 --- a/lib/views/appointments/appointment_detail_view.dart +++ b/lib/views/appointments/appointment_detail_view.dart @@ -19,13 +19,6 @@ class AppointmentDetailView extends StatelessWidget { AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key); - final List servicesList = [ - "Mechanic", - "Electrician", - " Car Denting", - "Oil Change", - ]; - Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) { return Expanded( child: ShowFillButton( @@ -48,7 +41,12 @@ class AppointmentDetailView extends StatelessWidget { children: [ getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), 12.width, - getBaseActionButtonWidget(color: MyColors.greenColor, onPressed: () {}, text: "Confirm"), + getBaseActionButtonWidget( + color: MyColors.greenColor, + onPressed: () { + context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); + }, + text: "Confirm"), ], ), ); @@ -119,6 +117,7 @@ class AppointmentDetailView extends StatelessWidget { @override Widget build(BuildContext context) { + AppointmentsVM appointmentsVM = context.read(); return Scaffold( appBar: CustomAppBar( title: "Appointment", @@ -134,16 +133,16 @@ class AppointmentDetailView extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - appointmentListModel.providerName!.toText(fontSize: 18, isBold: true), + appointmentListModel.providerName!.toText(fontSize: 16, isBold: true), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ MyAssets.miniClockDark.buildSvg( - height: 10, - width: 10, + height: 12, + width: 12, fit: BoxFit.fill, ), - 10.width, + 5.width, "${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor), ], ), @@ -163,7 +162,7 @@ class AppointmentDetailView extends StatelessWidget { // fit: BoxFit.fill, // ), // 10.width, - "${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 18, isBold: true), + "${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true), ], ), if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[ @@ -172,13 +171,25 @@ class AppointmentDetailView extends StatelessWidget { service.serviceItems!.length, (index) => "${service.serviceItems![index].name}".toText( textAlign: TextAlign.start, - fontSize: 13, - isBold: true, + 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)), ], ); }), @@ -189,14 +200,18 @@ class AppointmentDetailView extends StatelessWidget { children: [ CardButtonWithIcon( title: "Reschedule Appointment", - onCardTapped: () {}, + 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: () {}, + onCardTapped: () { + context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); + }, icon: MyAssets.creditCardIcon.buildSvg(), ), ], diff --git a/lib/views/appointments/book_appointment_schedules_view.dart b/lib/views/appointments/book_appointment_schedules_view.dart index d6614d7..9cccde3 100644 --- a/lib/views/appointments/book_appointment_schedules_view.dart +++ b/lib/views/appointments/book_appointment_schedules_view.dart @@ -13,8 +13,17 @@ 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 { - BookAppointmentSchedulesView({Key? key}) : super(key: key); + final ScreenArgumentsForAppointmentDetailPage screenArgumentsForAppointmentDetailPage; + + BookAppointmentSchedulesView({Key? key, required this.screenArgumentsForAppointmentDetailPage}) : super(key: key); @override Widget build(BuildContext context) { @@ -125,9 +134,17 @@ class BookAppointmentSchedulesView extends StatelessWidget { Expanded( child: ShowFillButton( maxHeight: 55, - title: "Review", + title: screenArgumentsForAppointmentDetailPage.routeFlag == 1 ? "Review" : "Confirm", onPressed: () { - appointmentsVM.onReviewButtonPressed(context); + 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, ), diff --git a/lib/views/dashboard/fragments/appointments_fragment.dart b/lib/views/dashboard/fragments/appointments_fragment.dart index deefa02..382d923 100644 --- a/lib/views/dashboard/fragments/appointments_fragment.dart +++ b/lib/views/dashboard/fragments/appointments_fragment.dart @@ -1,9 +1,12 @@ +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: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/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/widgets/common_widgets/categories_list.dart'; @@ -41,11 +44,17 @@ class AppointmentsFragment extends StatelessWidget { itemCount: appointmentsVM.myFilteredAppointments.length, itemBuilder: (BuildContext context, int index) { return BuildAppointmentContainerForCustomer( - onTapped: () => navigateWithName( - context, - AppRoutes.appointmentDetailView, - arguments: appointmentsVM.myFilteredAppointments[index], - ), + 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; + }); + navigateWithName(context, AppRoutes.appointmentDetailView, arguments: appointmentModel); + }, appointmentListModel: appointmentsVM.myFilteredAppointments[index], ); }, diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index 8690b6d..cf384cd 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -2,7 +2,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:flutter/material.dart'; -import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/view_models/ad_view_model.dart'; diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index 268ff39..142aee8 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -38,6 +38,10 @@ class _BranchDetailPageState extends State { return Scaffold( appBar: CustomAppBar( title: "Branch Detail", + onBackButtonTapped: () { + context.read().resetCategorySelectionBottomSheet(); + Navigator.pop(context); + }, ), body: Column( children: [