diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index e2823e5..5075082 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -1,4 +1,5 @@ import 'package:car_customer_app/views/appointments/appointment_detail_view.dart'; +import 'package:car_customer_app/views/appointments/book_appointment_schedules_view.dart'; import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart'; import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart'; import 'package:car_customer_app/views/appointments/pick_items_view.dart'; @@ -28,6 +29,7 @@ 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.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes), diff --git a/lib/main.dart b/lib/main.dart index 966f089..bd7ca33 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,6 +26,7 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; import 'package:sizer/sizer.dart'; +import 'package:intl/date_symbol_data_local.dart'; //test commit Future main() async { @@ -33,42 +34,41 @@ Future main() async { CustomerDependencies.addDependencies(); await EasyLocalization.ensureInitialized(); CustomerAppRoutes.routes.addAll(AppRoutes.routes); - - runApp( - MultiProvider( - providers: [ - ChangeNotifierProvider(create: (_) => BaseVM()), - ChangeNotifierProvider( - create: (_) => DashboardVM( - commonServices: injector.get(), - userRepo: injector.get(), - ), - ), - ChangeNotifierProvider( - create: (_) => UserVM(userRepo: injector.get()), - ), - ChangeNotifierProvider( - create: (_) => AdVM( - commonServices: injector.get(), - commonRepo: injector.get(), - adsRepo: injector.get(), - ), - ), - ChangeNotifierProvider( - create: (_) => AppointmentsVM( - scheduleRepo: injector.get(), - providerRepo: injector.get(), - commonServices: injector.get(), - commonRepo: injector.get(), - ), - ), - ChangeNotifierProvider( - create: (_) => PaymentVM(paymentService: injector.get(), paymentRepo: injector.get()), - ), - ], - child: const MyApp(), - ).setupLocale(), - ); + initializeDateFormatting().then((_) => runApp( + MultiProvider( + providers: [ + ChangeNotifierProvider(create: (_) => BaseVM()), + ChangeNotifierProvider( + create: (_) => DashboardVM( + commonServices: injector.get(), + userRepo: injector.get(), + ), + ), + ChangeNotifierProvider( + create: (_) => UserVM(userRepo: injector.get()), + ), + ChangeNotifierProvider( + create: (_) => AdVM( + commonServices: injector.get(), + commonRepo: injector.get(), + adsRepo: injector.get(), + ), + ), + ChangeNotifierProvider( + create: (_) => AppointmentsVM( + scheduleRepo: injector.get(), + providerRepo: injector.get(), + commonServices: injector.get(), + commonRepo: injector.get(), + ), + ), + ChangeNotifierProvider( + create: (_) => PaymentVM(paymentService: injector.get(), paymentRepo: injector.get()), + ), + ], + child: MyApp(), + ).setupLocale(), + )); } // todo terminal command to generate translation files diff --git a/lib/repositories/schedule_repo.dart b/lib/repositories/schedule_repo.dart index 8fbe9e3..3ea0083 100644 --- a/lib/repositories/schedule_repo.dart +++ b/lib/repositories/schedule_repo.dart @@ -21,7 +21,10 @@ abstract class ScheduleRepo { Future updateServicesInSchedule(Map map); - Future> mergeServiceIntoAvailableSchedules({required int appointmentType, required List serviceItemIds}); + Future> mergeServiceIntoAvailableSchedules({ + required List serviceItemIdsForHome, + required List serviceItemIdsForWorkshop, + }); Future createServiceAppointment({required List serviceItemIds, required int serviceSlotID}); } @@ -73,12 +76,21 @@ class ScheduleRepoImp implements ScheduleRepo { return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t); } - Future> mergeServiceIntoAvailableSchedules({required int appointmentType, required List serviceItemIds}) async { + Future> mergeServiceIntoAvailableSchedules({ + required List serviceItemIdsForHome, + required List serviceItemIdsForWorkshop, + }) async { String t = AppState().getUser.data!.accessToken ?? ""; - var queryParameters = { - "appointmentType": appointmentType, - "ServiceItemIDs": serviceItemIds, - }; + var queryParameters = [ + { + "appointmentType": 2, + "ServiceItemIDs": serviceItemIdsForHome, + }, + { + "appointmentType": 1, + "ServiceItemIDs": serviceItemIdsForWorkshop, + } + ]; GenericRespModel adsGenericModel = await injector.get().postJsonForObject( (json) => GenericRespModel.fromJson(json), ApiConsts.GetServiceItemAppointmentScheduleSlots, diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index f3b3deb..e5a4d38 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -1,8 +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/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/provider_branches_models/branch_detail_model.dart'; import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart'; @@ -12,11 +18,14 @@ import 'package:mc_common_app/models/services/service_model.dart'; import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; +import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/base_view_model.dart'; +import 'package:mc_common_app/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'; class AppointmentsVM extends BaseVM { final CommonRepo commonRepo; @@ -49,45 +58,39 @@ class AppointmentsVM extends BaseVM { List servicesInSchedule = []; - Future mergeServiceIntoAvailableSchedules() async { - List serviceItemIds = []; - currentServiceSelection!.serviceItems!.forEach((serviceItem) { - if (serviceItem.isUpdateOrSelected!) { - serviceItemIds.add(serviceItem.id!.toString()); - } - }); - - 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(); - - if (serviceAppointmentScheduleList.isEmpty) { - Utils.showToast("There are no available appointments for selected Items."); - return; + bool ifServiceAlreadyThere(int id) { + int index = servicesInSchedule.indexWhere((element) => element.id == id); + if (index == -1) { + return false; } + return true; + } - 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(); + bool ifItemAlreadySelected(int id) { + int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id); + if (indexFound != -1) { + return true; + } + return false; } + List allSelectedItemsInAppointments = []; + Future onItemsSelectedInService() async { if (currentServiceSelection != null) { - servicesInCurrentAppointment.add(currentServiceSelection!); + int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); + + if (index == -1) { + double totalPrice = 0.0; + currentServiceSelection!.serviceItems!.forEach((element) { + totalPrice = totalPrice + double.parse(element.price ?? "0.0"); + }); + currentServiceSelection!.currentTotalServicePrice = totalPrice; + servicesInCurrentAppointment.insert(0, currentServiceSelection!); + } + + resetCategorySelectionBottomSheet(); + notifyListeners(); } } @@ -96,9 +99,9 @@ class AppointmentsVM extends BaseVM { try { serviceAppointmentScheduleList.forEach((schedule) async { List serviceItemIds = []; - schedule.serviceItemList!.forEach((serviceItem) { - serviceItemIds.add(serviceItem.id.toString()); - }); + // schedule.serviceItemList!.forEach((serviceItem) { + // serviceItemIds.add(serviceItem.id.toString()); + // }); await scheduleRepo.createServiceAppointment(serviceItemIds: serviceItemIds, serviceSlotID: schedule.selectedCustomTimeDateSlotModel!.date!.slotId); }); } catch (e) { @@ -106,16 +109,11 @@ class AppointmentsVM extends BaseVM { } } - bool ifItemAlreadyThere(int id) { - int index = servicesInSchedule.indexWhere((element) => element.id == id); - if (index == -1) { - return false; - } - return true; - } - void updateIsHomeTapped(bool value) { isHomeTapped = value; + if (currentServiceSelection != null) { + currentServiceSelection!.isHomeSelected = value; + } notifyListeners(); } @@ -124,6 +122,9 @@ class AppointmentsVM extends BaseVM { void updatePickedHomeLocation(String value) { pickedHomeLocation = value; pickHomeLocationError = ""; + if (currentServiceSelection != null) { + currentServiceSelection!.homeLocation = value; + } notifyListeners(); } @@ -217,67 +218,43 @@ class AppointmentsVM extends BaseVM { 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; - updateSelectedSubServicesCounter(int value) { - selectedSubServicesCounter = value; - notifyListeners(); - } - onItemUpdateOrSelected(int index, bool selected, int itemId) { + int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); + serviceItemsFromApi[index].isUpdateOrSelected = selected; + serviceItemsFromApi[index].isHomeSelected = isHomeTapped; if (selected) { selectedSubServicesCounter = selectedSubServicesCounter + 1; - updateSelectedSubServicesCounter(selectedSubServicesCounter); selectSubServicesError = ""; currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]); + allSelectedItemsInAppointments.add(serviceItemsFromApi[index]); + allSelectedItemsInAppointments.forEach((element) { + if (!ifItemAlreadySelected(element.id!)) { + servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]); + servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = + servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0"); + } + }); } if (!selected) { selectedSubServicesCounter = selectedSubServicesCounter - 1; - updateSelectedSubServicesCounter(selectedSubServicesCounter); currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId); + allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId); + servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = + servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0"); + servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId); } notifyListeners(); } @@ -315,6 +292,11 @@ class AppointmentsVM extends BaseVM { Future> getServiceItems(int serviceId) async { serviceItemsFromApi.clear(); serviceItemsFromApi = await providerRepo.getServiceItems(serviceId); + serviceItemsFromApi.forEach((item) { + if (ifItemAlreadySelected(item.id!)) { + item.isUpdateOrSelected = true; + } + }); setState(ViewState.idle); return serviceItemsFromApi; } @@ -396,26 +378,173 @@ class AppointmentsVM extends BaseVM { return false; } -// void mergeServiceInAvailableSchedule() { -// log("schedules: ${availableSchedules}"); -// for (var schedule in availableSchedules) { -// for (var service in schedule.scheduleServices!) { -// if (branchSelectedServiceId.selectedId == service.serviceId) { -// log("ID matched: ${service.serviceId}"); -// log("SelectedServices: ${schedule.selectedServices}"); -// -// -// int isAlreadyThereIndex = schedule.selectedServices!.indexWhere((element) => element.serviceProviderServiceId == branchSelectedServiceId.selectedId); -// if (isAlreadyThereIndex != -1) { -// log("removing: ${service.serviceId}"); -// schedule.selectedServices!.removeAt(isAlreadyThereIndex); -// } -// schedule.selectedServices!.add(currentServiceSelection!); -// notifyListeners(); -// return; -// } -// } -// } -// notifyListeners(); -// } + String getTotalPrice(List serviceItems) { + var totalPrice = 0.0; + serviceItems.forEach((element) { + totalPrice = totalPrice + (element.currentTotalServicePrice); + }); + return totalPrice.toString(); + } + + void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + return AppointmentServicePickBottomSheet(); + }, + ); + } + + void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + double totalKms = 15.3; + return InfoBottomSheet( + title: "Charges Breakdown".toText(fontSize: 24, isBold: true), + description: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Services".toText(fontSize: 16, isBold: true), + Column( + children: List.generate( + selectedService.serviceItems!.length, + (index) => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true), + ], + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + "${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true), + ], + ), + if (selectedService.isHomeSelected) ...[ + 20.height, + "Home Location".toText(fontSize: 16, isBold: true), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true), + ], + ), + 8.height, + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + "${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true), + ], + ), + ], + 30.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Total Amount ".toText(fontSize: 16, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + (selectedService.isHomeSelected + ? "${(selectedService.currentTotalServicePrice ?? 0.0) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" + : "${selectedService.currentTotalServicePrice}") + .toText(fontSize: 29, isBold: true), + 2.width, + "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + ], + ) + ], + ), + 30.height, + ], + )); + }); + } + + void onReviewButtonPressed(BuildContext context) { + bool isValidated = false; + + for (int i = 0; i < serviceAppointmentScheduleList.length; i++) { + final schedule = serviceAppointmentScheduleList[i]; + if (schedule.selectedCustomTimeDateSlotModel == null) { + isValidated = false; + break; + } + if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) { + isValidated = false; + break; + } else { + if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) { + isValidated = true; + break; + } else { + TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected); + if (slot.date.isNotEmpty) { + isValidated = true; + break; + } + } + } + } + if (!isValidated) { + Utils.showToast("You must select appointment time for each schedule's appointment."); + return; + } + navigateWithName(context, AppRoutes.reviewAppointmentView); + } + + void onServicesNextPressed(BuildContext context) async { + Utils.showLoading(context); + + List serviceItemIdsForHome = []; + List serviceItemIdsForWorkshop = []; + allSelectedItemsInAppointments.forEach((serviceItem) { + if (serviceItem.isHomeSelected!) { + serviceItemIdsForHome.add(serviceItem.id!.toString()); + } else { + serviceItemIdsForWorkshop.add(serviceItem.id!.toString()); + } + }); + + 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, + ); + + if (serviceAppointmentScheduleList.isEmpty) { + Utils.hideLoading(context); + Utils.showToast("There are no available appointments for selected Items."); + return; + } + + serviceAppointmentScheduleList.forEach( + (schedule) { + amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); + + schedule.servicesListInAppointment!.forEach((service) { + if (!ifServiceAlreadyThere(service.serviceProviderServiceId!)) { + servicesInSchedule.add(DropValue(service.serviceProviderServiceId!, service.providerServiceDescription!, "")); + } + }); + }, + ); + Utils.hideLoading(context); + + navigateWithName(context, AppRoutes.bookAppointmenSchedulesView); + + notifyListeners(); + } } diff --git a/lib/views/appointments/book_appointment_schedules_view.dart b/lib/views/appointments/book_appointment_schedules_view.dart index 644b5e6..8b37974 100644 --- a/lib/views/appointments/book_appointment_schedules_view.dart +++ b/lib/views/appointments/book_appointment_schedules_view.dart @@ -1,9 +1,160 @@ +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/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'; + class BookAppointmentSchedulesView extends StatelessWidget { - const BookAppointmentSchedulesView({super.key}); + BookAppointmentSchedulesView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return const Placeholder(); + return Scaffold( + appBar: CustomAppBar( + title: "Book Appointment", + isRemoveBackButton: false, + isDrawerEnabled: false, + actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], + onBackButtonTapped: () => Navigator.pop(context), + ), + body: Consumer( + builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 21.height, + ListView.builder( + shrinkWrap: true, + itemCount: appointmentsVM.serviceAppointmentScheduleList.length, + itemBuilder: (BuildContext context, int scheduleIndex) { + ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; + return ExpansionTile( + tilePadding: EdgeInsets.symmetric(horizontal: 21, vertical: 10), + childrenPadding: EdgeInsets.only(left: 16, bottom: 10, right: 16), + title: Column( + children: [ + Row( + children: [ + Expanded( + child: "Schedule ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true), + ), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + ("${scheduleData.appointmentType == 2 ? "Home" : "Workshop"}").toText(fontSize: 12, isBold: true).expand(), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 5.height, + ListView.builder( + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: appointmentsVM.servicesInSchedule.length, + itemBuilder: (BuildContext context, int serviceIndex) { + DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex]; + return Row( + children: [ + Expanded( + child: ("${serviceIndex + 1}. ${selectedService.value}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor), + ), + ], + ); + }, + ), + ], + ), + ], + ), + 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 ?? []), + ], + if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[ + 5.height, + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ("Available Slots").toText(fontSize: 14, isBold: true), + ], + ), + 5.height, + SizedBox( + width: double.infinity, + child: BuildTimeSlots( + timeSlots: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList![appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!].availableSlots ?? + [], + onPressed: (slotIndex) { + appointmentsVM.updateSelectedAppointmentSlotByDate(scheduleIndex: scheduleIndex, slotIndex: slotIndex); + }, + ), + ), + ], + ], + ), + ], + ).toWhiteContainer(width: double.infinity, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); + }, + ).expand(), + Row( + children: [ + Expanded( + child: ShowFillButton( + txtColor: MyColors.black, + maxHeight: 55, + title: "Cancel", + onPressed: () {}, + backgroundColor: MyColors.greyButtonColor, + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Review", + onPressed: () { + appointmentsVM.onReviewButtonPressed(context); + }, + backgroundColor: MyColors.darkPrimaryColor, + ), + ) + ], + ).paddingAll(21) + ], + ); + }, + )); } } diff --git a/lib/views/appointments/book_appointment_services_view.dart b/lib/views/appointments/book_appointment_services_view.dart index afe8f67..cad86a8 100644 --- a/lib/views/appointments/book_appointment_services_view.dart +++ b/lib/views/appointments/book_appointment_services_view.dart @@ -1,135 +1,20 @@ 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: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'; class BookAppointmentServicesView extends StatelessWidget { BookAppointmentServicesView({Key? key}) : super(key: key); - void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - enableDrag: true, - builder: (BuildContext context) { - return AppointmentServicePickBottomSheet(); - }, - ); - } - - final _dummySlots = [ - TimeSlotModel(isSelected: false, slotId: 1, slot: "11:00"), - TimeSlotModel(isSelected: false, slotId: 2, slot: "12:00"), - TimeSlotModel(isSelected: true, slotId: 3, slot: "13:00"), - TimeSlotModel(isSelected: false, slotId: 4, slot: "14:00"), - TimeSlotModel(isSelected: false, slotId: 5, slot: "15:00"), - TimeSlotModel(isSelected: false, slotId: 6, slot: "16:00"), - TimeSlotModel(isSelected: false, slotId: 7, slot: "17:00"), - TimeSlotModel(isSelected: false, slotId: 8, slot: "18:00"), - TimeSlotModel(isSelected: false, slotId: 9, slot: "19:00"), - TimeSlotModel(isSelected: false, slotId: 10, slot: "20:00"), - TimeSlotModel(isSelected: false, slotId: 11, slot: "21:00"), - TimeSlotModel(isSelected: false, slotId: 12, slot: "22:00"), - TimeSlotModel(isSelected: false, slotId: 13, slot: "23:00"), - TimeSlotModel(isSelected: false, slotId: 14, slot: "24:00"), - TimeSlotModel(isSelected: false, slotId: 15, slot: "25:00"), - TimeSlotModel(isSelected: false, slotId: 16, slot: "26:00"), - TimeSlotModel(isSelected: false, slotId: 17, slot: "27:00"), - TimeSlotModel(isSelected: false, slotId: 18, slot: "28:00"), - TimeSlotModel(isSelected: false, slotId: 19, slot: "29:00"), - ]; - - void priceBreakDownClicked(BuildContext context) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - enableDrag: true, - builder: (BuildContext context) { - return InfoBottomSheet( - title: "Charges Breakdown".toText(fontSize: 24, isBold: true), - description: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Services".toText(fontSize: 16, isBold: true), - Column( - children: List.generate( - 5, - (index) => Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Gear Kit".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "200 SAR".toText(fontSize: 12, isBold: true), - ], - ), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - "1149 SAR".toText(fontSize: 16, isBold: true), - ], - ), - 20.height, - "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), - ], - ), - 30.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Total Amount ".toText(fontSize: 16, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - "120".toText(fontSize: 29, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), - ], - ) - ], - ), - 30.height, - ], - )); - }); - } - - String getTotalPrice(List serviceItems) { - var totalPrice = 0.0; - serviceItems.forEach((element) { - totalPrice = totalPrice + double.parse(element.price ?? "0.0"); - }); - return totalPrice.toString(); - } - @override Widget build(BuildContext context) { return Scaffold( @@ -149,7 +34,7 @@ class BookAppointmentServicesView extends StatelessWidget { CustomAddButton( needsBorder: true, bgColor: MyColors.white, - onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM), + onTap: () => appointmentsVM.openTheAddServiceBottomSheet(context, appointmentsVM), text: "Add Services", icon: Container( height: 24, @@ -162,70 +47,52 @@ class BookAppointmentServicesView extends StatelessWidget { ListView.builder( shrinkWrap: true, itemCount: appointmentsVM.servicesInCurrentAppointment.length, - itemBuilder: (BuildContext context, int scheduleIndex) { - ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; + itemBuilder: (BuildContext context, int serviceIndex) { + ServiceModel serviceData = appointmentsVM.servicesInCurrentAppointment[serviceIndex]; return Column( children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ - ListView.separated( - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: appointmentsVM.servicesInSchedule.length, - itemBuilder: (BuildContext context, int serviceIndex) { - DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex]; - return Column( - children: [ - Row( - children: [ - Expanded( - child: selectedService.value.toText(fontSize: 15, 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(), - ], - ), - 5.height, - Column( - children: List.generate(scheduleData.serviceItemList!.length, (itemIndex) { - ItemData itemData = scheduleData.serviceItemList![itemIndex]; - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), - ("${itemData.price}").toText(fontSize: 13, isBold: true).expand(), - ], - ); - }), - ), - ], - ], - ); - }, - separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2), + Expanded( + child: (serviceData.serviceDescription ?? "").toText(fontSize: 15, isBold: true), ), - 8.height, - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - getTotalPrice(appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].serviceItemList ?? []).toText(fontSize: 32, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), - Icon( - Icons.arrow_drop_down, - size: 30, - ) - ], - ).onPress(() => priceBreakDownClicked(context)), ], ), + if (true) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + (serviceData.isHomeSelected ? serviceData.homeLocation : "Workshop").toText(fontSize: 12, isBold: true).expand(), + ], + ), + 5.height, + Column( + children: List.generate(serviceData.serviceItems!.length, (itemIndex) { + ItemData itemData = serviceData.serviceItems![itemIndex]; + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), + ("${itemData.price}").toText(fontSize: 13, isBold: true).expand(), + ], + ); + }), + ), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + ((appointmentsVM.servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true), + 2.width, + "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + Icon( + Icons.arrow_drop_down, + size: 30, + ) + ], + ).onPress(() => appointmentsVM.priceBreakDownClicked(context, appointmentsVM.servicesInCurrentAppointment[serviceIndex])), + ], ], ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); }, @@ -245,9 +112,9 @@ class BookAppointmentServicesView extends StatelessWidget { Expanded( child: ShowFillButton( maxHeight: 55, - title: "Review", + title: "Next", onPressed: () { - appointmentsVM.onReviewButtonPressed(context); + appointmentsVM.onServicesNextPressed(context); }, backgroundColor: MyColors.darkPrimaryColor, ), diff --git a/lib/views/appointments/review_appointment_view.dart b/lib/views/appointments/review_appointment_view.dart index c60f84f..5862e51 100644 --- a/lib/views/appointments/review_appointment_view.dart +++ b/lib/views/appointments/review_appointment_view.dart @@ -7,6 +7,7 @@ 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/service_schedule_model.dart'; import 'package:mc_common_app/models/services/item_model.dart'; +import 'package:mc_common_app/models/services/service_model.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; @@ -104,7 +105,6 @@ class ReviewAppointment extends StatelessWidget { shrinkWrap: true, 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; @@ -128,12 +128,12 @@ class ReviewAppointment extends StatelessWidget { ), 5.height, Column( - children: List.generate(scheduleData.serviceItemList!.length, (itemIndex) { - ItemData itemData = scheduleData.serviceItemList![itemIndex]; + children: List.generate(scheduleData.servicesListInAppointment!.length, (itemIndex) { + ServiceModel serviceData = scheduleData.servicesListInAppointment![itemIndex]; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "${itemData.name}: ${itemData.price} SAR".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), + "${serviceData.providerServiceDescription}".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), ], ); }), @@ -196,12 +196,12 @@ class ReviewAppointment extends StatelessWidget { AppointmentsVM appointmentsVM = context.read(); List allSelectedItems = []; double totalServicePrice = 0.0; - appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) { - schedule.serviceItemList!.forEach((item) { - allSelectedItems.add(item); - totalServicePrice = totalServicePrice + double.parse(item.price!); - }); - }); + // appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) { + // schedule.servicesListInAppointment!.forEach((service) { + // allSelectedItems.add(item); + // totalServicePrice = totalServicePrice + double.parse(item.price!); + // }); + // }); return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/views/appointments/widgets/custom_calender_widget.dart b/lib/views/appointments/widgets/custom_calender_widget.dart new file mode 100644 index 0000000..7b86c0d --- /dev/null +++ b/lib/views/appointments/widgets/custom_calender_widget.dart @@ -0,0 +1,215 @@ +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'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:provider/provider.dart'; +import 'package:intl/intl.dart'; + +class CustomCalenderWidget extends StatefulWidget { + final List? customTimeDateSlotList; + + const CustomCalenderWidget({super.key, required this.customTimeDateSlotList}); + + @override + State createState() => _CustomCalenderWidgetState(); +} + +class _CustomCalenderWidgetState extends State { + List allDates = []; + List allMonths = []; + List datesInSelectedMonth = []; + CalendarFormat _calendarFormat = CalendarFormat.month; + + late int selectedMonth; + late int selectedYear; + + DateTime? _selectedDay; + + DateTime _focusedDay = DateTime.now(); + + @override + void initState() { + super.initState(); + populateDateList(); + } + + populateDateList() { + for (var value in widget.customTimeDateSlotList!) { + DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date); + // 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}", ""); + allDates.add(dt); + + if (!ifMonthAlreadyThere(dv)) { + allMonths.add(dv); + } + } + + selectedMonth = allDates.first.month; + selectedYear = allDates.first.year; + datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList(); + } + + bool ifMonthAlreadyThere(DropValue monthDate) { + int index = allMonths.indexWhere((element) => element.id == monthDate.id && element.subValue == monthDate.subValue); + if (index == -1) { + return false; + } + + return true; + } + + bool ifDateAlreadyThere(DateTime dt) { + int index = allDates.indexWhere((element) => dt.month == element.month && dt.year == element.year); + if (index == -1) { + return false; + } + + return true; + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Builder(builder: (context) { + return DropdownField( + (DropValue value) { + setState(() { + selectedYear = int.parse(value.value.split(',')[1]); + selectedMonth = value.value.split(',')[0].getMonthNumberByName(); + }); + }, + list: allMonths, + // dropdownValue: DropValue(1, "${selectedMonth.getMonthNameByNumber()}jhvk,", "${selectedYear}"), + hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear", + errorValue: "", + showAppointmentPickerVariant: true, + ); + }), + ), + Spacer(), + Icon( + Icons.calendar_today, + color: Colors.black, + size: 18, + ).paddingOnly(right: 10) + ], + ).paddingOnly(left: 6, right: 0), + TableCalendar( + headerVisible: false, + firstDay: datesInSelectedMonth.first, + lastDay: datesInSelectedMonth.last, + focusedDay: _focusedDay, + calendarFormat: _calendarFormat, + weekendDays: [DateTime.friday, DateTime.saturday], + daysOfWeekHeight: 30, + availableGestures: AvailableGestures.none, + daysOfWeekStyle: DaysOfWeekStyle( + weekdayStyle: TextStyle(fontSize: 14, color: MyColors.black), + weekendStyle: TextStyle(fontSize: 14, color: MyColors.black.withOpacity(0.5)), + ), + calendarBuilders: CalendarBuilders( + 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, + width: 50, + margin: EdgeInsets.all(5), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: MyColors.darkIconColor, + ), + alignment: Alignment.center, + child: Text( + dateTime2.day.toString(), + style: TextStyle(color: MyColors.white), + ), + ); + }, + defaultBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) { + return Container( + height: 50, + width: 50, + margin: EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border.all(color: Colors.orange, width: 2), + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + dateTime1.day.toString(), + ), + ); + }, + disabledBuilder: (BuildContext context, DateTime dateTime1, DateTime selectedDt) { + return Container( + height: 50, + width: 50, + margin: EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + dateTime1.day.toString(), + ), + ); + }, + ), + headerStyle: HeaderStyle(formatButtonVisible: false), + selectedDayPredicate: (day) { + // Use `selectedDayPredicate` to determine which day is currently selected. + // If this returns true, then `day` will be marked as selected. + + // Using `isSameDay` is recommended to disregard + // the time-part of compared DateTime objects. + return isSameDay(_selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + if (!isSameDay(_selectedDay, selectedDay)) { + // Call `setState()` when updating the selected day + setState(() { + _selectedDay = selectedDay; + _focusedDay = selectedDay; + }); + } + }, + ), + ], + ); + }, + ); + } +} diff --git a/lib/views/provider/branch_detail_page.dart b/lib/views/provider/branch_detail_page.dart index e49cf16..0f26312 100644 --- a/lib/views/provider/branch_detail_page.dart +++ b/lib/views/provider/branch_detail_page.dart @@ -179,7 +179,7 @@ class _BranchDetailPageState extends State { showItem("Charges per KM", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "SAR"), 8.height, ((widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0) - ? widget.branchDetailModel.branchServices![index].itemsCount.toString() + " items" + ? widget.branchDetailModel.branchServices![index].itemsCount.toString() + " items" : "No" + " items") .toText( fontSize: 12, diff --git a/lib/views/provider/sheet/items_list_sheet.dart b/lib/views/provider/sheet/items_list_sheet.dart index 0525c79..2ab4dc7 100644 --- a/lib/views/provider/sheet/items_list_sheet.dart +++ b/lib/views/provider/sheet/items_list_sheet.dart @@ -47,7 +47,7 @@ class _ItemsListSheetState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - serviceItemModel.toString().toText(fontSize: 16, isBold: true), + serviceItemModel.name.toString().toText(fontSize: 16, isBold: true), 4.height, showItem("Available for appointment:", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), showItem("Allowing Workshop service:", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), diff --git a/pubspec.yaml b/pubspec.yaml index a7d4453..6d94c35 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + table_calendar: ^3.0.9 mc_common_app: path: /Volumes/Data/Projects/Flutter/car_common_app