aDDED cUSTOM cALENDER

aamir_dev
Faiz Hashmi 2 years ago
parent 5bc5ca8954
commit 120dc86309

@ -1,4 +1,5 @@
import 'package:car_customer_app/views/appointments/appointment_detail_view.dart'; import 'package:car_customer_app/views/appointments/appointment_detail_view.dart';
import 'package:car_customer_app/views/appointments/book_appointment_schedules_view.dart';
import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart'; import 'package:car_customer_app/views/appointments/book_appointment_services_view.dart';
import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart'; import 'package:car_customer_app/views/appointments/book_appointments_item_view.dart';
import 'package:car_customer_app/views/appointments/pick_items_view.dart'; import 'package:car_customer_app/views/appointments/pick_items_view.dart';
@ -28,6 +29,7 @@ class CustomerAppRoutes {
AppRoutes.adsSearchFilterScreen: (context) => AdsSearchFilterView(), AppRoutes.adsSearchFilterScreen: (context) => AdsSearchFilterView(),
AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(isProvider: ModalRoute.of(context)!.settings.arguments as bool), AppRoutes.selectAdTypeView: (context) => SelectAdTypeView(isProvider: ModalRoute.of(context)!.settings.arguments as bool),
AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(),
AppRoutes.bookAppointmenSchedulesView: (context) => BookAppointmentSchedulesView(),
AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(), AppRoutes.bookAppointmentsItemView: (context) => BookAppointmentsItemView(),
AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(), AppRoutes.reviewAppointmentView: (context) => ReviewAppointment(),
AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes),

@ -26,6 +26,7 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart'; import 'package:provider/single_child_widget.dart';
import 'package:sizer/sizer.dart'; import 'package:sizer/sizer.dart';
import 'package:intl/date_symbol_data_local.dart';
//test commit //test commit
Future<void> main() async { Future<void> main() async {
@ -33,42 +34,41 @@ Future<void> main() async {
CustomerDependencies.addDependencies(); CustomerDependencies.addDependencies();
await EasyLocalization.ensureInitialized(); await EasyLocalization.ensureInitialized();
CustomerAppRoutes.routes.addAll(AppRoutes.routes); CustomerAppRoutes.routes.addAll(AppRoutes.routes);
initializeDateFormatting().then((_) => runApp(
runApp( MultiProvider(
MultiProvider( providers: <SingleChildWidget>[
providers: <SingleChildWidget>[ ChangeNotifierProvider<BaseVM>(create: (_) => BaseVM()),
ChangeNotifierProvider<BaseVM>(create: (_) => BaseVM()), ChangeNotifierProvider<DashboardVM>(
ChangeNotifierProvider<DashboardVM>( create: (_) => DashboardVM(
create: (_) => DashboardVM( commonServices: injector.get<CommonAppServices>(),
commonServices: injector.get<CommonAppServices>(), userRepo: injector.get<UserRepo>(),
userRepo: injector.get<UserRepo>(), ),
), ),
), ChangeNotifierProvider<UserVM>(
ChangeNotifierProvider<UserVM>( create: (_) => UserVM(userRepo: injector.get<UserRepo>()),
create: (_) => UserVM(userRepo: injector.get<UserRepo>()), ),
), ChangeNotifierProvider<AdVM>(
ChangeNotifierProvider<AdVM>( create: (_) => AdVM(
create: (_) => AdVM( commonServices: injector.get<CommonAppServices>(),
commonServices: injector.get<CommonAppServices>(), commonRepo: injector.get<CommonRepo>(),
commonRepo: injector.get<CommonRepo>(), adsRepo: injector.get<AdsRepo>(),
adsRepo: injector.get<AdsRepo>(), ),
), ),
), ChangeNotifierProvider<AppointmentsVM>(
ChangeNotifierProvider<AppointmentsVM>( create: (_) => AppointmentsVM(
create: (_) => AppointmentsVM( scheduleRepo: injector.get<ScheduleRepo>(),
scheduleRepo: injector.get<ScheduleRepo>(), providerRepo: injector.get<ProviderRepo>(),
providerRepo: injector.get<ProviderRepo>(), commonServices: injector.get<CommonAppServices>(),
commonServices: injector.get<CommonAppServices>(), commonRepo: injector.get<CommonRepo>(),
commonRepo: injector.get<CommonRepo>(), ),
), ),
), ChangeNotifierProvider<PaymentVM>(
ChangeNotifierProvider<PaymentVM>( create: (_) => PaymentVM(paymentService: injector.get<PaymentService>(), paymentRepo: injector.get<PaymentsRepo>()),
create: (_) => PaymentVM(paymentService: injector.get<PaymentService>(), paymentRepo: injector.get<PaymentsRepo>()), ),
), ],
], child: MyApp(),
child: const MyApp(), ).setupLocale(),
).setupLocale(), ));
);
} }
// todo terminal command to generate translation files // todo terminal command to generate translation files

@ -21,7 +21,10 @@ abstract class ScheduleRepo {
Future<MResponse> updateServicesInSchedule(Map map); Future<MResponse> updateServicesInSchedule(Map map);
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required int appointmentType, required List<String> serviceItemIds}); Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({
required List<String> serviceItemIdsForHome,
required List<String> serviceItemIdsForWorkshop,
});
Future<void> createServiceAppointment({required List<String> serviceItemIds, required int serviceSlotID}); Future<void> createServiceAppointment({required List<String> serviceItemIds, required int serviceSlotID});
} }
@ -73,12 +76,21 @@ class ScheduleRepoImp implements ScheduleRepo {
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t); return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t);
} }
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required int appointmentType, required List<String> serviceItemIds}) async { Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({
required List<String> serviceItemIdsForHome,
required List<String> serviceItemIdsForWorkshop,
}) async {
String t = AppState().getUser.data!.accessToken ?? ""; String t = AppState().getUser.data!.accessToken ?? "";
var queryParameters = { var queryParameters = [
"appointmentType": appointmentType, {
"ServiceItemIDs": serviceItemIds, "appointmentType": 2,
}; "ServiceItemIDs": serviceItemIdsForHome,
},
{
"appointmentType": 1,
"ServiceItemIDs": serviceItemIdsForWorkshop,
}
];
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject( GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json), (json) => GenericRespModel.fromJson(json),
ApiConsts.GetServiceItemAppointmentScheduleSlots, ApiConsts.GetServiceItemAppointmentScheduleSlots,

@ -1,8 +1,14 @@
import 'dart:developer';
import 'package:car_customer_app/repositories/provider_repo.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/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/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.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/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/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_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/models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.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/enums.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.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/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/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class AppointmentsVM extends BaseVM { class AppointmentsVM extends BaseVM {
final CommonRepo commonRepo; final CommonRepo commonRepo;
@ -49,45 +58,39 @@ class AppointmentsVM extends BaseVM {
List<DropValue> servicesInSchedule = []; List<DropValue> servicesInSchedule = [];
Future<void> mergeServiceIntoAvailableSchedules() async { bool ifServiceAlreadyThere(int id) {
List<String> serviceItemIds = []; int index = servicesInSchedule.indexWhere((element) => element.id == id);
currentServiceSelection!.serviceItems!.forEach((serviceItem) { if (index == -1) {
if (serviceItem.isUpdateOrSelected!) { return false;
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;
} }
return true;
}
serviceAppointmentScheduleList.forEach( bool ifItemAlreadySelected(int id) {
(schedule) { int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); if (indexFound != -1) {
return true;
schedule.serviceItemList!.forEach((item) { }
if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) { return false;
servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, ""));
}
});
},
);
notifyListeners();
} }
List<ItemData> allSelectedItemsInAppointments = [];
Future<void> onItemsSelectedInService() async { Future<void> onItemsSelectedInService() async {
if (currentServiceSelection != null) { 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 { try {
serviceAppointmentScheduleList.forEach((schedule) async { serviceAppointmentScheduleList.forEach((schedule) async {
List<String> serviceItemIds = []; List<String> serviceItemIds = [];
schedule.serviceItemList!.forEach((serviceItem) { // schedule.serviceItemList!.forEach((serviceItem) {
serviceItemIds.add(serviceItem.id.toString()); // serviceItemIds.add(serviceItem.id.toString());
}); // });
await scheduleRepo.createServiceAppointment(serviceItemIds: serviceItemIds, serviceSlotID: schedule.selectedCustomTimeDateSlotModel!.date!.slotId); await scheduleRepo.createServiceAppointment(serviceItemIds: serviceItemIds, serviceSlotID: schedule.selectedCustomTimeDateSlotModel!.date!.slotId);
}); });
} catch (e) { } 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) { void updateIsHomeTapped(bool value) {
isHomeTapped = value; isHomeTapped = value;
if (currentServiceSelection != null) {
currentServiceSelection!.isHomeSelected = value;
}
notifyListeners(); notifyListeners();
} }
@ -124,6 +122,9 @@ class AppointmentsVM extends BaseVM {
void updatePickedHomeLocation(String value) { void updatePickedHomeLocation(String value) {
pickedHomeLocation = value; pickedHomeLocation = value;
pickHomeLocationError = ""; pickHomeLocationError = "";
if (currentServiceSelection != null) {
currentServiceSelection!.homeLocation = value;
}
notifyListeners(); notifyListeners();
} }
@ -217,67 +218,43 @@ class AppointmentsVM extends BaseVM {
int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!; int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true; serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!; serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!;
print("here: ${serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].slotId}");
notifyListeners(); notifyListeners();
} }
double amountToPayForAppointment = 0.0; double amountToPayForAppointment = 0.0;
double totalAmount = 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<ItemData> serviceItemsFromApi = []; List<ItemData> serviceItemsFromApi = [];
ProviderProfileModel? providerProfileModel; ProviderProfileModel? providerProfileModel;
int selectedSubServicesCounter = 0; int selectedSubServicesCounter = 0;
updateSelectedSubServicesCounter(int value) {
selectedSubServicesCounter = value;
notifyListeners();
}
onItemUpdateOrSelected(int index, bool selected, int itemId) { onItemUpdateOrSelected(int index, bool selected, int itemId) {
int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
serviceItemsFromApi[index].isUpdateOrSelected = selected; serviceItemsFromApi[index].isUpdateOrSelected = selected;
serviceItemsFromApi[index].isHomeSelected = isHomeTapped;
if (selected) { if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1; selectedSubServicesCounter = selectedSubServicesCounter + 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
selectSubServicesError = ""; selectSubServicesError = "";
currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]); 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) { if (!selected) {
selectedSubServicesCounter = selectedSubServicesCounter - 1; selectedSubServicesCounter = selectedSubServicesCounter - 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId); 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(); notifyListeners();
} }
@ -315,6 +292,11 @@ class AppointmentsVM extends BaseVM {
Future<List<ItemData>> getServiceItems(int serviceId) async { Future<List<ItemData>> getServiceItems(int serviceId) async {
serviceItemsFromApi.clear(); serviceItemsFromApi.clear();
serviceItemsFromApi = await providerRepo.getServiceItems(serviceId); serviceItemsFromApi = await providerRepo.getServiceItems(serviceId);
serviceItemsFromApi.forEach((item) {
if (ifItemAlreadySelected(item.id!)) {
item.isUpdateOrSelected = true;
}
});
setState(ViewState.idle); setState(ViewState.idle);
return serviceItemsFromApi; return serviceItemsFromApi;
} }
@ -396,26 +378,173 @@ class AppointmentsVM extends BaseVM {
return false; return false;
} }
// void mergeServiceInAvailableSchedule() { String getTotalPrice(List<ServiceModel> serviceItems) {
// log("schedules: ${availableSchedules}"); var totalPrice = 0.0;
// for (var schedule in availableSchedules) { serviceItems.forEach((element) {
// for (var service in schedule.scheduleServices!) { totalPrice = totalPrice + (element.currentTotalServicePrice);
// if (branchSelectedServiceId.selectedId == service.serviceId) { });
// log("ID matched: ${service.serviceId}"); return totalPrice.toString();
// log("SelectedServices: ${schedule.selectedServices}"); }
//
// void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) {
// int isAlreadyThereIndex = schedule.selectedServices!.indexWhere((element) => element.serviceProviderServiceId == branchSelectedServiceId.selectedId); showModalBottomSheet(
// if (isAlreadyThereIndex != -1) { context: context,
// log("removing: ${service.serviceId}"); isScrollControlled: true,
// schedule.selectedServices!.removeAt(isAlreadyThereIndex); enableDrag: true,
// } builder: (BuildContext context) {
// schedule.selectedServices!.add(currentServiceSelection!); return AppointmentServicePickBottomSheet();
// notifyListeners(); },
// return; );
// } }
// }
// } void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) {
// notifyListeners(); 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<String> serviceItemIdsForHome = [];
List<String> 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();
}
} }

@ -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: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 { class BookAppointmentSchedulesView extends StatelessWidget {
const BookAppointmentSchedulesView({super.key}); BookAppointmentSchedulesView({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { 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)
],
);
},
));
} }
} }

@ -1,135 +1,20 @@
import 'package:car_customer_app/view_models/appointments_view_model.dart'; 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:flutter/material.dart';
import 'package:mc_common_app/classes/consts.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/int_extensions.dart';
import 'package:mc_common_app/extensions/string_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/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/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/views/advertisement/custom_add_button.dart';
import 'package:mc_common_app/widgets/button/show_fill_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/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:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class BookAppointmentServicesView extends StatelessWidget { class BookAppointmentServicesView extends StatelessWidget {
BookAppointmentServicesView({Key? key}) : super(key: key); 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<ItemData> serviceItems) {
var totalPrice = 0.0;
serviceItems.forEach((element) {
totalPrice = totalPrice + double.parse(element.price ?? "0.0");
});
return totalPrice.toString();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -149,7 +34,7 @@ class BookAppointmentServicesView extends StatelessWidget {
CustomAddButton( CustomAddButton(
needsBorder: true, needsBorder: true,
bgColor: MyColors.white, bgColor: MyColors.white,
onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM), onTap: () => appointmentsVM.openTheAddServiceBottomSheet(context, appointmentsVM),
text: "Add Services", text: "Add Services",
icon: Container( icon: Container(
height: 24, height: 24,
@ -162,70 +47,52 @@ class BookAppointmentServicesView extends StatelessWidget {
ListView.builder( ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: appointmentsVM.servicesInCurrentAppointment.length, itemCount: appointmentsVM.servicesInCurrentAppointment.length,
itemBuilder: (BuildContext context, int scheduleIndex) { itemBuilder: (BuildContext context, int serviceIndex) {
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; ServiceModel serviceData = appointmentsVM.servicesInCurrentAppointment[serviceIndex];
return Column( return Column(
children: [ children: [
Column( Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ListView.separated( Expanded(
physics: NeverScrollableScrollPhysics(), child: (serviceData.serviceDescription ?? "").toText(fontSize: 15, isBold: true),
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),
), ),
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)); ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
}, },
@ -245,9 +112,9 @@ class BookAppointmentServicesView extends StatelessWidget {
Expanded( Expanded(
child: ShowFillButton( child: ShowFillButton(
maxHeight: 55, maxHeight: 55,
title: "Review", title: "Next",
onPressed: () { onPressed: () {
appointmentsVM.onReviewButtonPressed(context); appointmentsVM.onServicesNextPressed(context);
}, },
backgroundColor: MyColors.darkPrimaryColor, backgroundColor: MyColors.darkPrimaryColor,
), ),

@ -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/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/service_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/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/theme/colors.dart';
import 'package:mc_common_app/widgets/button/show_fill_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/app_bar.dart';
@ -104,7 +105,6 @@ class ReviewAppointment extends StatelessWidget {
shrinkWrap: true, shrinkWrap: true,
itemCount: appointmentsVM.servicesInSchedule.length, itemCount: appointmentsVM.servicesInSchedule.length,
itemBuilder: (BuildContext context, int serviceIndex) { itemBuilder: (BuildContext context, int serviceIndex) {
DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex];
String selectedTimeSlot = ""; String selectedTimeSlot = "";
if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) { if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot; selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot;
@ -128,12 +128,12 @@ class ReviewAppointment extends StatelessWidget {
), ),
5.height, 5.height,
Column( Column(
children: List.generate(scheduleData.serviceItemList!.length, (itemIndex) { children: List.generate(scheduleData.servicesListInAppointment!.length, (itemIndex) {
ItemData itemData = scheduleData.serviceItemList![itemIndex]; ServiceModel serviceData = scheduleData.servicesListInAppointment![itemIndex];
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ 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<AppointmentsVM>(); AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
List<ItemData> allSelectedItems = []; List<ItemData> allSelectedItems = [];
double totalServicePrice = 0.0; double totalServicePrice = 0.0;
appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) { // appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) {
schedule.serviceItemList!.forEach((item) { // schedule.servicesListInAppointment!.forEach((service) {
allSelectedItems.add(item); // allSelectedItems.add(item);
totalServicePrice = totalServicePrice + double.parse(item.price!); // totalServicePrice = totalServicePrice + double.parse(item.price!);
}); // });
}); // });
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

@ -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<CustomTimeDateSlotModel>? customTimeDateSlotList;
const CustomCalenderWidget({super.key, required this.customTimeDateSlotList});
@override
State<CustomCalenderWidget> createState() => _CustomCalenderWidgetState();
}
class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
List<DateTime> allDates = [];
List<DropValue> allMonths = [];
List<DateTime> 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;
});
}
},
),
],
);
},
);
}
}

@ -179,7 +179,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
showItem("Charges per KM", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "SAR"), showItem("Charges per KM", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "SAR"),
8.height, 8.height,
((widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0) ((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") : "No" + " items")
.toText( .toText(
fontSize: 12, fontSize: 12,

@ -47,7 +47,7 @@ class _ItemsListSheetState extends State<ItemsListSheet> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
serviceItemModel.toString().toText(fontSize: 16, isBold: true), serviceItemModel.name.toString().toText(fontSize: 16, isBold: true),
4.height, 4.height,
showItem("Available for appointment:", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green), showItem("Available for appointment:", (serviceItemModel.isAllowAppointment ?? false) ? "Yes" : "No", valueColor: Colors.green),
showItem("Allowing Workshop service:", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green), showItem("Allowing Workshop service:", (serviceItemModel.isAppointmentCompanyLoc ?? false) ? "Yes" : "No", valueColor: Colors.green),

@ -34,6 +34,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
table_calendar: ^3.0.9
mc_common_app: mc_common_app:
path: /Volumes/Data/Projects/Flutter/car_common_app path: /Volumes/Data/Projects/Flutter/car_common_app

Loading…
Cancel
Save