diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index 6cca179..e2823e5 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -18,7 +18,7 @@ import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart'; import 'package:mc_common_app/views/payments/payment_methods_view.dart'; import 'package:mc_common_app/views/advertisement/ads_search_filter_view.dart'; - class CustomerAppRoutes { +class CustomerAppRoutes { static final Map routes = { AppRoutes.dashboard: (context) => DashboardPage(), AppRoutes.bookProviderAppView: (context) => BookProviderAppView(), @@ -30,7 +30,7 @@ import 'package:mc_common_app/views/advertisement/ads_search_filter_view.dart'; AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(), - AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypesEnum), + AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes), AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel), AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int), }; diff --git a/lib/repositories/schedule_repo.dart b/lib/repositories/schedule_repo.dart index 7938095..8fbe9e3 100644 --- a/lib/repositories/schedule_repo.dart +++ b/lib/repositories/schedule_repo.dart @@ -21,7 +21,9 @@ abstract class ScheduleRepo { Future updateServicesInSchedule(Map map); - Future> mergeServiceIntoAvailableSchedules({required List serviceItemIds}); + Future> mergeServiceIntoAvailableSchedules({required int appointmentType, required List serviceItemIds}); + + Future createServiceAppointment({required List serviceItemIds, required int serviceSlotID}); } class ScheduleRepoImp implements ScheduleRepo { @@ -71,18 +73,39 @@ class ScheduleRepoImp implements ScheduleRepo { return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t); } - Future> mergeServiceIntoAvailableSchedules({required List serviceItemIds}) async { + Future> mergeServiceIntoAvailableSchedules({required int appointmentType, required List serviceItemIds}) async { String t = AppState().getUser.data!.accessToken ?? ""; - var dummyServiceIds = ["3", "2"]; - var queryParameters = {"ServiceItemIDs": dummyServiceIds}; - GenericRespModel adsGenericModel = await injector.get().getJsonForObject( + var queryParameters = { + "appointmentType": appointmentType, + "ServiceItemIDs": serviceItemIds, + }; + GenericRespModel adsGenericModel = await injector.get().postJsonForObject( (json) => GenericRespModel.fromJson(json), ApiConsts.GetServiceItemAppointmentScheduleSlots, + queryParameters, token: t, - queryParameters: queryParameters, ); List serviceAppointmentScheduleModel = List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index])); return serviceAppointmentScheduleModel; } + + Future createServiceAppointment({required List serviceItemIds, required int serviceSlotID}) async { + String t = AppState().getUser.data!.accessToken ?? ""; + var queryParameters = { + "id": 0, + "serviceSlotID": serviceSlotID, + "appointmentStatusID": 0, + "serviceProviderID": 0, + "customerID": 0, + "isActive": true, + "serviceItemID": [11] + }; + GenericRespModel adsGenericModel = await injector.get().postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.ServiceProvidersAppointmentCreate, + queryParameters, + token: t, + ); + } } diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index 08889a9..f3b3deb 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,6 +1,8 @@ import 'package:car_customer_app/repositories/provider_repo.dart'; import 'package:car_customer_app/repositories/schedule_repo.dart'; +import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_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'; @@ -11,6 +13,8 @@ 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/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/widgets/dropdown/dropdow_field.dart'; @@ -47,24 +51,61 @@ class AppointmentsVM extends BaseVM { Future mergeServiceIntoAvailableSchedules() async { List serviceItemIds = []; - serviceItems.forEach((serviceItem) { + currentServiceSelection!.serviceItems!.forEach((serviceItem) { if (serviceItem.isUpdateOrSelected!) { serviceItemIds.add(serviceItem.id!.toString()); } }); - var scheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(serviceItemIds: serviceItemIds); - serviceAppointmentScheduleList.addAll(scheduleList); + + servicesInCurrentAppointment.add(currentServiceSelection!); + + serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( + serviceItemIds: serviceItemIds, + appointmentType: isHomeTapped ? 2 : 1, // AppointmentType 1 for workshop and 2 for Home based schedule. + ); + servicesInSchedule.clear(); - serviceAppointmentScheduleList.forEach((schedule) { - schedule.serviceItemList!.forEach((item) { - if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) { - servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, "")); - } - }); - }); + + if (serviceAppointmentScheduleList.isEmpty) { + Utils.showToast("There are no available appointments for selected Items."); + return; + } + + serviceAppointmentScheduleList.forEach( + (schedule) { + amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); + + schedule.serviceItemList!.forEach((item) { + if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) { + servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, "")); + } + }); + }, + ); notifyListeners(); } + Future onItemsSelectedInService() async { + if (currentServiceSelection != null) { + servicesInCurrentAppointment.add(currentServiceSelection!); + } + } + + Future onBookAppointmentPressed(BuildContext context) async { + Utils.showLoading(context); + 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); + }); + } catch (e) { + Utils.showToast("${e.toString()}"); + } + } + bool ifItemAlreadyThere(int id) { int index = servicesInSchedule.indexWhere((element) => element.id == id); if (index == -1) { @@ -99,6 +140,8 @@ class AppointmentsVM extends BaseVM { BranchDetailModel? selectedBranchModel; List branchServices = []; + + List servicesInCurrentAppointment = []; ServiceModel? currentServiceSelection; void updateBranchServiceId(SelectionModel id) async { @@ -150,8 +193,70 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } - List serviceItems = []; - List selectedServiceItems = []; + 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!; + print("here: ${serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].slotId}"); + notifyListeners(); + } + + double amountToPayForAppointment = 0.0; + double totalAmount = 0.0; + + 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); + } + + List serviceItemsFromApi = []; ProviderProfileModel? providerProfileModel; int selectedSubServicesCounter = 0; @@ -162,12 +267,12 @@ class AppointmentsVM extends BaseVM { } onItemUpdateOrSelected(int index, bool selected, int itemId) { - serviceItems[index].isUpdateOrSelected = selected; + serviceItemsFromApi[index].isUpdateOrSelected = selected; if (selected) { selectedSubServicesCounter = selectedSubServicesCounter + 1; updateSelectedSubServicesCounter(selectedSubServicesCounter); selectSubServicesError = ""; - currentServiceSelection!.serviceItems!.add(serviceItems[index]); + currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]); } if (!selected) { selectedSubServicesCounter = selectedSubServicesCounter - 1; @@ -208,10 +313,10 @@ class AppointmentsVM extends BaseVM { } Future> getServiceItems(int serviceId) async { - serviceItems.clear(); - serviceItems = await providerRepo.getServiceItems(serviceId); + serviceItemsFromApi.clear(); + serviceItemsFromApi = await providerRepo.getServiceItems(serviceId); setState(ViewState.idle); - return serviceItems; + return serviceItemsFromApi; } getBranchAndServices(int providerId) async { @@ -263,7 +368,7 @@ class AppointmentsVM extends BaseVM { void updatePickHomeLocationError(String value) { pickHomeLocationError = value; - notifyListeners(); + // notifyListeners(); } bool isServiceSelectionValidated() { @@ -280,8 +385,8 @@ class AppointmentsVM extends BaseVM { return true; } - bool onSubServicesNextPressed() { - for (var value in serviceItems) { + bool validateItemsSelection() { + for (var value in serviceItemsFromApi) { if (value.isUpdateOrSelected!) { return true; } diff --git a/lib/views/appointments/appointment_detail_view.dart b/lib/views/appointments/appointment_detail_view.dart index 86e2dec..718d69d 100644 --- a/lib/views/appointments/appointment_detail_view.dart +++ b/lib/views/appointments/appointment_detail_view.dart @@ -10,7 +10,7 @@ import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart' import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class AppointmentDetailView extends StatelessWidget { - AppointmentListModel appointmentListModel; + final AppointmentListModel appointmentListModel; AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key); diff --git a/lib/views/appointments/book_appointment_schedules_view.dart b/lib/views/appointments/book_appointment_schedules_view.dart new file mode 100644 index 0000000..644b5e6 --- /dev/null +++ b/lib/views/appointments/book_appointment_schedules_view.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; +class BookAppointmentSchedulesView extends StatelessWidget { + const BookAppointmentSchedulesView({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/lib/views/appointments/book_appointment_services_view.dart b/lib/views/appointments/book_appointment_services_view.dart index 2212426..afe8f67 100644 --- a/lib/views/appointments/book_appointment_services_view.dart +++ b/lib/views/appointments/book_appointment_services_view.dart @@ -62,7 +62,7 @@ class BookAppointmentServicesView extends StatelessWidget { enableDrag: true, builder: (BuildContext context) { return InfoBottomSheet( - title: "Charges Breakdown", + title: "Charges Breakdown".toText(fontSize: 24, isBold: true), description: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -151,7 +151,7 @@ class BookAppointmentServicesView extends StatelessWidget { bgColor: MyColors.white, onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM), text: "Add Services", - icon: Container( + icon: Container( height: 24, width: 24, decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), @@ -161,61 +161,11 @@ class BookAppointmentServicesView extends StatelessWidget { 10.height, ListView.builder( shrinkWrap: true, - itemCount: appointmentsVM.serviceAppointmentScheduleList.length, + itemCount: appointmentsVM.servicesInCurrentAppointment.length, itemBuilder: (BuildContext context, int scheduleIndex) { ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; return Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: "Schedule: ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true), - ), - Align( - alignment: Alignment.topRight, - child: Icon( - Icons.delete_outline, - size: 28, - ), - ).onPress(() {}), - ], - ), - if (true) ...[ - 5.height, - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - ("Available Dates").toText(fontSize: 14, isBold: true), - ], - ), - 5.height, - SizedBox( - width: double.infinity, - child: BuildTimeSlots( - timeSlots: scheduleData.availableDates!, - onPressed: (index) => null, - ), - ), - ], - if (scheduleData.selectedDate!.isNotEmpty) ...[ - 5.height, - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - ("Available Slots").toText(fontSize: 14, isBold: true), - ], - ), - 5.height, - SizedBox( - width: double.infinity, - child: BuildTimeSlots( - timeSlots: _dummySlots, - onPressed: (index) => null, - ), - ), - ], - 20.height, Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -297,7 +247,7 @@ class BookAppointmentServicesView extends StatelessWidget { maxHeight: 55, title: "Review", onPressed: () { - navigateWithName(context, AppRoutes.reviewAppointmentView); + appointmentsVM.onReviewButtonPressed(context); }, backgroundColor: MyColors.darkPrimaryColor, ), diff --git a/lib/views/appointments/book_appointments_item_view.dart b/lib/views/appointments/book_appointments_item_view.dart index 2620166..8f5baeb 100644 --- a/lib/views/appointments/book_appointments_item_view.dart +++ b/lib/views/appointments/book_appointments_item_view.dart @@ -57,18 +57,19 @@ class BookAppointmentsItemView extends StatelessWidget { Divider(), ], ).horPaddingMain(), - appointmentsVM.serviceItems.isEmpty + 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.serviceItems.length, + itemCount: appointmentsVM.serviceItemsFromApi.length, itemBuilder: (BuildContext context, int index) { - ItemData itemData = appointmentsVM.serviceItems[index]; + ItemData itemData = appointmentsVM.serviceItemsFromApi[index]; return ServiceItemWithPriceCheckBox( - description: "Some description about the sub-services", + 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( @@ -119,17 +120,21 @@ class BookAppointmentsItemView extends StatelessWidget { maxHeight: 55, title: "Next", onPressed: () async { - bool resp = appointmentsVM.onSubServicesNextPressed(); + bool resp = appointmentsVM.validateItemsSelection(); if (resp) { - Utils.showLoading(context); - await appointmentsVM.mergeServiceIntoAvailableSchedules(); - appointmentsVM.resetCategorySelectionBottomSheet(); - Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.bookAppointmenServicesView, (Route route) => false); - - // appointmentsVM.mergeServiceInAvailableSchedule(); + 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.primaryColor, + backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor, ); }, ), diff --git a/lib/views/appointments/review_appointment_view.dart b/lib/views/appointments/review_appointment_view.dart index 841f4c0..c60f84f 100644 --- a/lib/views/appointments/review_appointment_view.dart +++ b/lib/views/appointments/review_appointment_view.dart @@ -96,7 +96,6 @@ class ReviewAppointment extends StatelessWidget { ), ], ), - 10.height, Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -106,21 +105,25 @@ class ReviewAppointment extends StatelessWidget { itemCount: appointmentsVM.servicesInSchedule.length, itemBuilder: (BuildContext context, int serviceIndex) { DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex]; + String selectedTimeSlot = ""; + if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) { + selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot; + } return Column( children: [ - Row( - children: [ - Expanded( - child: selectedService.value.toText(fontSize: 15, isBold: true), - ), - ], - ), + // 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), - ("Home").toText(fontSize: 12, isBold: true).expand(), + (appointmentsVM.isHomeTapped ? "Home" : "Workshop").toText(fontSize: 12, isBold: true).expand(), ], ), 5.height, @@ -130,12 +133,31 @@ class ReviewAppointment extends StatelessWidget { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), + "${itemData.name}: ${itemData.price} SAR".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), ], ); }), ), ], + 5.height, + SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Time & Location".toText(fontSize: 14, 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), + "PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, isBold: true), + ]), + ], + ), + ) ], ); }, @@ -144,35 +166,9 @@ class ReviewAppointment extends StatelessWidget { ], ), ], - ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 0)); }, ); - // AppointmentsVM appointmentsVM = context.read(); - // return SizedBox( - // width: double.infinity, - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: List.generate( - // appointmentsVM.servicesInSchedule.length, - // (serviceIndex) => Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // appointmentsVM.servicesInSchedule[serviceIndex].value.toText(fontSize: 16, isBold: true), - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: List.generate( - // appointmentsVM, - // (index) => itemList[index].toText( - // fontSize: 12, - // color: MyColors.lightTextColor, - // isBold: true, - // )), - // ), - // ], - // ).paddingOnly(bottom: 14), - // ), - // ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.symmetric(horizontal: 21)), - // ); } Widget buildTimeAndLocationInfoCard() { @@ -231,25 +227,25 @@ class ReviewAppointment extends StatelessWidget { ), 10.height, Divider(thickness: 0.7), - "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), - ], - ), - 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), + ], + ), + 10.height, + Divider(thickness: 0.7), + ], 10.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -258,7 +254,7 @@ class ReviewAppointment extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - "120".toText(fontSize: 29, isBold: true), + totalServicePrice.toString().toText(fontSize: 29, isBold: true), 2.width, "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), ], @@ -270,12 +266,13 @@ class ReviewAppointment extends StatelessWidget { ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21)); } - Widget buildNextButtonFooter() { + Widget buildNextButtonFooter({required BuildContext context}) { + AppointmentsVM appointmentsVM = context.read(); return Container( height: 90, color: MyColors.white, child: Column( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Divider(thickness: 0.7, height: 3), 10.height, @@ -283,9 +280,11 @@ class ReviewAppointment extends StatelessWidget { width: double.infinity, child: ShowFillButton( maxHeight: 55, - backgroundColor: MyColors.primaryColor, + backgroundColor: MyColors.darkPrimaryColor, title: "Book Appointment", - onPressed: () {}, + onPressed: () { + // appointmentsVM.onBookAppointmentPressed(); + }, ).paddingOnly(bottom: 12, left: 21, right: 21), ), ], @@ -303,21 +302,18 @@ class ReviewAppointment extends StatelessWidget { actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], onBackButtonTapped: () => Navigator.pop(context), ), - body: Stack( - alignment: Alignment.bottomCenter, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - buildBranchInfoCard(context: context), - buildServicesInfoCard(context: context), - buildTimeAndLocationInfoCard(), - buildChargesBreakDown(context: context), - ], - ), - ), - buildNextButtonFooter(), + ListView( + children: [ + buildBranchInfoCard(context: context), + buildServicesInfoCard(context: context), + // buildTimeAndLocationInfoCard(), + buildChargesBreakDown(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 index 4bab6e6..a13af5d 100644 --- a/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart +++ b/lib/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart @@ -174,12 +174,13 @@ class AppointmentServicePickBottomSheet extends StatelessWidget { width: double.infinity, child: ShowFillButton( maxHeight: 55, - backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor, + 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); } }, diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index 34092a3..e49cf16 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -178,7 +178,10 @@ class _BranchDetailPageState extends State { showItem("Home service range", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "KM"), showItem("Charges per KM", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "SAR"), 8.height, - (widget.branchDetailModel.branchServices![index].itemsCount.toString() + "+ items").toText( + ((widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0) + ? widget.branchDetailModel.branchServices![index].itemsCount.toString() + " items" + : "No" + " items") + .toText( fontSize: 12, isBold: true, color: MyColors.primaryColor, @@ -187,7 +190,9 @@ class _BranchDetailPageState extends State { 20.height, ], ).onPress(() { - showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].serviceProviderServiceId ?? 0)); + if (widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0) { + showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].serviceProviderServiceId ?? 0)); + } }), ], onExpansionChanged: (value) { diff --git a/lib/views/provider/sheet/items_list_sheet.dart b/lib/views/provider/sheet/items_list_sheet.dart index 4738e2d..0525c79 100644 --- a/lib/views/provider/sheet/items_list_sheet.dart +++ b/lib/views/provider/sheet/items_list_sheet.dart @@ -30,12 +30,12 @@ class _ItemsListSheetState extends State { height: MediaQuery.of(context).size.height / 1.2, child: Consumer( builder: (context, appointmentsVM, _) { - return appointmentsVM.serviceItems.isEmpty + return appointmentsVM.serviceItemsFromApi.isEmpty ? const EmptyWidget() : ListView.separated( - itemCount: appointmentsVM.serviceItems.length, + itemCount: appointmentsVM.serviceItemsFromApi.length, itemBuilder: (BuildContext context, int index) { - ItemData serviceItemModel = appointmentsVM.serviceItems[index]; + ItemData serviceItemModel = appointmentsVM.serviceItemsFromApi[index]; return SizedBox( width: double.infinity, child: Row( diff --git a/pubspec.yaml b/pubspec.yaml index 3c4aa16..a7d4453 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions