Started changing the Appointment Structure

aamir_dev
Faiz Hashmi 2 years ago
parent fa35392611
commit 5bc5ca8954

@ -18,7 +18,7 @@ import 'package:mc_common_app/views/advertisement/select_ad_type_view.dart';
import 'package:mc_common_app/views/payments/payment_methods_view.dart'; import 'package:mc_common_app/views/payments/payment_methods_view.dart';
import 'package:mc_common_app/views/advertisement/ads_search_filter_view.dart'; import 'package:mc_common_app/views/advertisement/ads_search_filter_view.dart';
class CustomerAppRoutes { class CustomerAppRoutes {
static final Map<String, WidgetBuilder> routes = { static final Map<String, WidgetBuilder> routes = {
AppRoutes.dashboard: (context) => DashboardPage(), AppRoutes.dashboard: (context) => DashboardPage(),
AppRoutes.bookProviderAppView: (context) => BookProviderAppView(), AppRoutes.bookProviderAppView: (context) => BookProviderAppView(),
@ -30,7 +30,7 @@ import 'package:mc_common_app/views/advertisement/ads_search_filter_view.dart';
AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(), AppRoutes.bookAppointmenServicesView: (context) => BookAppointmentServicesView(),
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 PaymentTypesEnum), AppRoutes.paymentMethodsView: (context) => PaymentMethodsView(paymentType: ModalRoute.of(context)!.settings.arguments as PaymentTypes),
AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel), AppRoutes.branchDetailPage: (context) => BranchDetailPage(branchDetailModel: ModalRoute.of(context)!.settings.arguments as BranchDetailModel),
AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int), AppRoutes.providerProfilePage: (context) => ProviderProfilePage(providerId: ModalRoute.of(context)!.settings.arguments as int),
}; };

@ -21,7 +21,9 @@ abstract class ScheduleRepo {
Future<MResponse> updateServicesInSchedule(Map map); Future<MResponse> updateServicesInSchedule(Map map);
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required List<String> serviceItemIds}); Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required int appointmentType, required List<String> serviceItemIds});
Future<void> createServiceAppointment({required List<String> serviceItemIds, required int serviceSlotID});
} }
class ScheduleRepoImp implements ScheduleRepo { class ScheduleRepoImp implements ScheduleRepo {
@ -71,18 +73,39 @@ 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 List<String> serviceItemIds}) async { Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({required int appointmentType, required List<String> serviceItemIds}) async {
String t = AppState().getUser.data!.accessToken ?? ""; String t = AppState().getUser.data!.accessToken ?? "";
var dummyServiceIds = ["3", "2"]; var queryParameters = {
var queryParameters = {"ServiceItemIDs": dummyServiceIds}; "appointmentType": appointmentType,
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject( "ServiceItemIDs": serviceItemIds,
};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json), (json) => GenericRespModel.fromJson(json),
ApiConsts.GetServiceItemAppointmentScheduleSlots, ApiConsts.GetServiceItemAppointmentScheduleSlots,
queryParameters,
token: t, token: t,
queryParameters: queryParameters,
); );
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleModel = List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleModel =
List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index])); List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index]));
return serviceAppointmentScheduleModel; return serviceAppointmentScheduleModel;
} }
Future<void> createServiceAppointment({required List<String> serviceItemIds, required int serviceSlotID}) async {
String t = AppState().getUser.data!.accessToken ?? "";
var queryParameters = {
"id": 0,
"serviceSlotID": serviceSlotID,
"appointmentStatusID": 0,
"serviceProviderID": 0,
"customerID": 0,
"isActive": true,
"serviceItemID": [11]
};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.ServiceProvidersAppointmentCreate,
queryParameters,
token: t,
);
}
} }

@ -1,6 +1,8 @@
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:flutter/cupertino.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/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';
@ -11,6 +13,8 @@ import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/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/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/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/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
@ -47,24 +51,61 @@ class AppointmentsVM extends BaseVM {
Future<void> mergeServiceIntoAvailableSchedules() async { Future<void> mergeServiceIntoAvailableSchedules() async {
List<String> serviceItemIds = []; List<String> serviceItemIds = [];
serviceItems.forEach((serviceItem) { currentServiceSelection!.serviceItems!.forEach((serviceItem) {
if (serviceItem.isUpdateOrSelected!) { if (serviceItem.isUpdateOrSelected!) {
serviceItemIds.add(serviceItem.id!.toString()); serviceItemIds.add(serviceItem.id!.toString());
} }
}); });
var scheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(serviceItemIds: serviceItemIds);
serviceAppointmentScheduleList.addAll(scheduleList); servicesInCurrentAppointment.add(currentServiceSelection!);
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceItemIds: serviceItemIds,
appointmentType: isHomeTapped ? 2 : 1, // AppointmentType 1 for workshop and 2 for Home based schedule.
);
servicesInSchedule.clear(); servicesInSchedule.clear();
serviceAppointmentScheduleList.forEach((schedule) {
schedule.serviceItemList!.forEach((item) { if (serviceAppointmentScheduleList.isEmpty) {
if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) { Utils.showToast("There are no available appointments for selected Items.");
servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, "")); return;
} }
});
}); serviceAppointmentScheduleList.forEach(
(schedule) {
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
schedule.serviceItemList!.forEach((item) {
if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) {
servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, ""));
}
});
},
);
notifyListeners(); notifyListeners();
} }
Future<void> onItemsSelectedInService() async {
if (currentServiceSelection != null) {
servicesInCurrentAppointment.add(currentServiceSelection!);
}
}
Future<void> onBookAppointmentPressed(BuildContext context) async {
Utils.showLoading(context);
try {
serviceAppointmentScheduleList.forEach((schedule) async {
List<String> serviceItemIds = [];
schedule.serviceItemList!.forEach((serviceItem) {
serviceItemIds.add(serviceItem.id.toString());
});
await scheduleRepo.createServiceAppointment(serviceItemIds: serviceItemIds, serviceSlotID: schedule.selectedCustomTimeDateSlotModel!.date!.slotId);
});
} catch (e) {
Utils.showToast("${e.toString()}");
}
}
bool ifItemAlreadyThere(int id) { bool ifItemAlreadyThere(int id) {
int index = servicesInSchedule.indexWhere((element) => element.id == id); int index = servicesInSchedule.indexWhere((element) => element.id == id);
if (index == -1) { if (index == -1) {
@ -99,6 +140,8 @@ class AppointmentsVM extends BaseVM {
BranchDetailModel? selectedBranchModel; BranchDetailModel? selectedBranchModel;
List<ServiceModel> branchServices = []; List<ServiceModel> branchServices = [];
List<ServiceModel> servicesInCurrentAppointment = [];
ServiceModel? currentServiceSelection; ServiceModel? currentServiceSelection;
void updateBranchServiceId(SelectionModel id) async { void updateBranchServiceId(SelectionModel id) async {
@ -150,8 +193,70 @@ class AppointmentsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
List<ItemData> serviceItems = []; updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
List<ItemData> selectedServiceItems = []; serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) {
element.date!.isSelected = false;
});
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
final date = TimeSlotModel(
date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date,
slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId,
isSelected: true,
slot: "",
);
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
notifyListeners();
}
updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) {
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) {
element.availableSlots!.forEach((element) => element.isSelected = false);
});
int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!;
print("here: ${serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].slotId}");
notifyListeners();
}
double amountToPayForAppointment = 0.0;
double totalAmount = 0.0;
void onReviewButtonPressed(BuildContext context) {
bool isValidated = false;
for (int i = 0; i < serviceAppointmentScheduleList.length; i++) {
final schedule = serviceAppointmentScheduleList[i];
if (schedule.selectedCustomTimeDateSlotModel == null) {
isValidated = false;
break;
}
if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
isValidated = false;
break;
} else {
if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) {
isValidated = true;
break;
} else {
TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected);
if (slot.date.isNotEmpty) {
isValidated = true;
break;
}
}
}
}
if (!isValidated) {
Utils.showToast("You must select appointment time for each schedule's appointment.");
return;
}
navigateWithName(context, AppRoutes.reviewAppointmentView);
}
List<ItemData> serviceItemsFromApi = [];
ProviderProfileModel? providerProfileModel; ProviderProfileModel? providerProfileModel;
int selectedSubServicesCounter = 0; int selectedSubServicesCounter = 0;
@ -162,12 +267,12 @@ class AppointmentsVM extends BaseVM {
} }
onItemUpdateOrSelected(int index, bool selected, int itemId) { onItemUpdateOrSelected(int index, bool selected, int itemId) {
serviceItems[index].isUpdateOrSelected = selected; serviceItemsFromApi[index].isUpdateOrSelected = selected;
if (selected) { if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1; selectedSubServicesCounter = selectedSubServicesCounter + 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter); updateSelectedSubServicesCounter(selectedSubServicesCounter);
selectSubServicesError = ""; selectSubServicesError = "";
currentServiceSelection!.serviceItems!.add(serviceItems[index]); currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]);
} }
if (!selected) { if (!selected) {
selectedSubServicesCounter = selectedSubServicesCounter - 1; selectedSubServicesCounter = selectedSubServicesCounter - 1;
@ -208,10 +313,10 @@ class AppointmentsVM extends BaseVM {
} }
Future<List<ItemData>> getServiceItems(int serviceId) async { Future<List<ItemData>> getServiceItems(int serviceId) async {
serviceItems.clear(); serviceItemsFromApi.clear();
serviceItems = await providerRepo.getServiceItems(serviceId); serviceItemsFromApi = await providerRepo.getServiceItems(serviceId);
setState(ViewState.idle); setState(ViewState.idle);
return serviceItems; return serviceItemsFromApi;
} }
getBranchAndServices(int providerId) async { getBranchAndServices(int providerId) async {
@ -263,7 +368,7 @@ class AppointmentsVM extends BaseVM {
void updatePickHomeLocationError(String value) { void updatePickHomeLocationError(String value) {
pickHomeLocationError = value; pickHomeLocationError = value;
notifyListeners(); // notifyListeners();
} }
bool isServiceSelectionValidated() { bool isServiceSelectionValidated() {
@ -280,8 +385,8 @@ class AppointmentsVM extends BaseVM {
return true; return true;
} }
bool onSubServicesNextPressed() { bool validateItemsSelection() {
for (var value in serviceItems) { for (var value in serviceItemsFromApi) {
if (value.isUpdateOrSelected!) { if (value.isUpdateOrSelected!) {
return true; return true;
} }

@ -10,7 +10,7 @@ import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart'
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class AppointmentDetailView extends StatelessWidget { class AppointmentDetailView extends StatelessWidget {
AppointmentListModel appointmentListModel; final AppointmentListModel appointmentListModel;
AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key); AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key);

@ -0,0 +1,9 @@
import 'package:flutter/material.dart';
class BookAppointmentSchedulesView extends StatelessWidget {
const BookAppointmentSchedulesView({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

@ -62,7 +62,7 @@ class BookAppointmentServicesView extends StatelessWidget {
enableDrag: true, enableDrag: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return InfoBottomSheet( return InfoBottomSheet(
title: "Charges Breakdown", title: "Charges Breakdown".toText(fontSize: 24, isBold: true),
description: Column( description: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -151,7 +151,7 @@ class BookAppointmentServicesView extends StatelessWidget {
bgColor: MyColors.white, bgColor: MyColors.white,
onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM), onTap: () => openTheAddServiceBottomSheet(context, appointmentsVM),
text: "Add Services", text: "Add Services",
icon: Container( icon: Container(
height: 24, height: 24,
width: 24, width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
@ -161,61 +161,11 @@ class BookAppointmentServicesView extends StatelessWidget {
10.height, 10.height,
ListView.builder( ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: appointmentsVM.serviceAppointmentScheduleList.length, itemCount: appointmentsVM.servicesInCurrentAppointment.length,
itemBuilder: (BuildContext context, int scheduleIndex) { itemBuilder: (BuildContext context, int scheduleIndex) {
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]; ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
return Column( return Column(
children: [ children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: "Schedule: ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
),
Align(
alignment: Alignment.topRight,
child: Icon(
Icons.delete_outline,
size: 28,
),
).onPress(() {}),
],
),
if (true) ...[
5.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
("Available Dates").toText(fontSize: 14, isBold: true),
],
),
5.height,
SizedBox(
width: double.infinity,
child: BuildTimeSlots(
timeSlots: scheduleData.availableDates!,
onPressed: (index) => null,
),
),
],
if (scheduleData.selectedDate!.isNotEmpty) ...[
5.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
("Available Slots").toText(fontSize: 14, isBold: true),
],
),
5.height,
SizedBox(
width: double.infinity,
child: BuildTimeSlots(
timeSlots: _dummySlots,
onPressed: (index) => null,
),
),
],
20.height,
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -297,7 +247,7 @@ class BookAppointmentServicesView extends StatelessWidget {
maxHeight: 55, maxHeight: 55,
title: "Review", title: "Review",
onPressed: () { onPressed: () {
navigateWithName(context, AppRoutes.reviewAppointmentView); appointmentsVM.onReviewButtonPressed(context);
}, },
backgroundColor: MyColors.darkPrimaryColor, backgroundColor: MyColors.darkPrimaryColor,
), ),

@ -57,18 +57,19 @@ class BookAppointmentsItemView extends StatelessWidget {
Divider(), Divider(),
], ],
).horPaddingMain(), ).horPaddingMain(),
appointmentsVM.serviceItems.isEmpty appointmentsVM.serviceItemsFromApi.isEmpty
? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor))) ? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor)))
: ListView.separated( : ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider(), separatorBuilder: (BuildContext context, int index) => Divider(),
itemCount: appointmentsVM.serviceItems.length, itemCount: appointmentsVM.serviceItemsFromApi.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
ItemData itemData = appointmentsVM.serviceItems[index]; ItemData itemData = appointmentsVM.serviceItemsFromApi[index];
return ServiceItemWithPriceCheckBox( return ServiceItemWithPriceCheckBox(
description: "Some description about the sub-services", description: itemData.description ?? "Some description about the sub-services",
title: itemData.name!, title: itemData.name!,
isSelected: itemData.isUpdateOrSelected!, isSelected: itemData.isUpdateOrSelected!,
onSelection: (bool value) { onSelection: (bool value) {
print("itemId: ${itemData.id}");
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!); appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!);
}, },
priceWidget: Row( priceWidget: Row(
@ -119,17 +120,21 @@ class BookAppointmentsItemView extends StatelessWidget {
maxHeight: 55, maxHeight: 55,
title: "Next", title: "Next",
onPressed: () async { onPressed: () async {
bool resp = appointmentsVM.onSubServicesNextPressed(); bool resp = appointmentsVM.validateItemsSelection();
if (resp) { if (resp) {
Utils.showLoading(context); appointmentsVM.onItemsSelectedInService();
await appointmentsVM.mergeServiceIntoAvailableSchedules(); Navigator.pop(context);
appointmentsVM.resetCategorySelectionBottomSheet();
Navigator.of(context).pushNamedAndRemoveUntil(AppRoutes.bookAppointmenServicesView, (Route<dynamic> route) => false);
// appointmentsVM.mergeServiceInAvailableSchedule();
} }
// bool resp = appointmentsVM.validateItemsSelection();
// if (resp) {
// Utils.showLoading(context);
// await appointmentsVM.mergeServiceIntoAvailableSchedules();
// appointmentsVM.resetCategorySelectionBottomSheet();
// Utils.hideLoading(context);
// Navigator.of(context).pushReplacementNamed(AppRoutes.bookAppointmenServicesView);
// }
}, },
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor, backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
); );
}, },
), ),

@ -96,7 +96,6 @@ class ReviewAppointment extends StatelessWidget {
), ),
], ],
), ),
10.height,
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -106,21 +105,25 @@ class ReviewAppointment extends StatelessWidget {
itemCount: appointmentsVM.servicesInSchedule.length, itemCount: appointmentsVM.servicesInSchedule.length,
itemBuilder: (BuildContext context, int serviceIndex) { itemBuilder: (BuildContext context, int serviceIndex) {
DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex]; DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex];
String selectedTimeSlot = "";
if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
selectedTimeSlot = scheduleData.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected).slot;
}
return Column( return Column(
children: [ children: [
Row( // Row(
children: [ // children: [
Expanded( // Expanded(
child: selectedService.value.toText(fontSize: 15, isBold: true), // child: selectedService.value.toText(fontSize: 14, isBold: true),
), // ),
], // ],
), // ),
if (true) ...[ if (true) ...[
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
("Home").toText(fontSize: 12, isBold: true).expand(), (appointmentsVM.isHomeTapped ? "Home" : "Workshop").toText(fontSize: 12, isBold: true).expand(),
], ],
), ),
5.height, 5.height,
@ -130,12 +133,31 @@ class ReviewAppointment extends StatelessWidget {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true), "${itemData.name}: ${itemData.price} SAR".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
], ],
); );
}), }),
), ),
], ],
5.height,
SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Time & Location".toText(fontSize: 14, isBold: true),
3.height,
Row(children: [
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${scheduleData.selectedCustomTimeDateSlotModel!.date!.date} at ${selectedTimeSlot}".toText(fontSize: 12, isBold: true),
]),
Row(children: [
"Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, isBold: true),
]),
],
),
)
], ],
); );
}, },
@ -144,35 +166,9 @@ class ReviewAppointment extends StatelessWidget {
], ],
), ),
], ],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 0));
}, },
); );
// AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
// return SizedBox(
// width: double.infinity,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: List.generate(
// appointmentsVM.servicesInSchedule.length,
// (serviceIndex) => Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// appointmentsVM.servicesInSchedule[serviceIndex].value.toText(fontSize: 16, isBold: true),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: List.generate(
// appointmentsVM,
// (index) => itemList[index].toText(
// fontSize: 12,
// color: MyColors.lightTextColor,
// isBold: true,
// )),
// ),
// ],
// ).paddingOnly(bottom: 14),
// ),
// ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.symmetric(horizontal: 21)),
// );
} }
Widget buildTimeAndLocationInfoCard() { Widget buildTimeAndLocationInfoCard() {
@ -231,25 +227,25 @@ class ReviewAppointment extends StatelessWidget {
), ),
10.height, 10.height,
Divider(thickness: 0.7), Divider(thickness: 0.7),
"Home Location".toText(fontSize: 16, isBold: true), if (appointmentsVM.isHomeTapped) ...[
Row( "Home Location".toText(fontSize: 16, isBold: true),
mainAxisAlignment: MainAxisAlignment.spaceBetween, Row(
children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
"10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), children: [
"5 x 10".toText(fontSize: 12, isBold: true), "10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
], "5 x 10".toText(fontSize: 12, isBold: true),
), ],
8.height, ),
Row( 8.height,
mainAxisAlignment: MainAxisAlignment.end, Row(
children: [ mainAxisAlignment: MainAxisAlignment.end,
"50 SAR".toText(fontSize: 16, isBold: true), children: [
], "50 SAR".toText(fontSize: 16, isBold: true),
), ],
10.height, ),
Divider( 10.height,
thickness: 0.7, Divider(thickness: 0.7),
), ],
10.height, 10.height,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -258,7 +254,7 @@ class ReviewAppointment extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
"120".toText(fontSize: 29, isBold: true), totalServicePrice.toString().toText(fontSize: 29, isBold: true),
2.width, 2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
], ],
@ -270,12 +266,13 @@ class ReviewAppointment extends StatelessWidget {
).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21)); ).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21));
} }
Widget buildNextButtonFooter() { Widget buildNextButtonFooter({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Container( return Container(
height: 90, height: 90,
color: MyColors.white, color: MyColors.white,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Divider(thickness: 0.7, height: 3), Divider(thickness: 0.7, height: 3),
10.height, 10.height,
@ -283,9 +280,11 @@ class ReviewAppointment extends StatelessWidget {
width: double.infinity, width: double.infinity,
child: ShowFillButton( child: ShowFillButton(
maxHeight: 55, maxHeight: 55,
backgroundColor: MyColors.primaryColor, backgroundColor: MyColors.darkPrimaryColor,
title: "Book Appointment", title: "Book Appointment",
onPressed: () {}, onPressed: () {
// appointmentsVM.onBookAppointmentPressed();
},
).paddingOnly(bottom: 12, left: 21, right: 21), ).paddingOnly(bottom: 12, left: 21, right: 21),
), ),
], ],
@ -303,21 +302,18 @@ class ReviewAppointment extends StatelessWidget {
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)], actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
onBackButtonTapped: () => Navigator.pop(context), onBackButtonTapped: () => Navigator.pop(context),
), ),
body: Stack( body: Column(
alignment: Alignment.bottomCenter, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SingleChildScrollView( ListView(
child: Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, buildBranchInfoCard(context: context),
children: [ buildServicesInfoCard(context: context),
buildBranchInfoCard(context: context), // buildTimeAndLocationInfoCard(),
buildServicesInfoCard(context: context), buildChargesBreakDown(context: context),
buildTimeAndLocationInfoCard(), ],
buildChargesBreakDown(context: context), ).expand(),
], buildNextButtonFooter(context: context),
),
),
buildNextButtonFooter(),
], ],
), ),
); );

@ -174,12 +174,13 @@ class AppointmentServicePickBottomSheet extends StatelessWidget {
width: double.infinity, width: double.infinity,
child: ShowFillButton( child: ShowFillButton(
maxHeight: 55, maxHeight: 55,
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor, backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
title: "Next", title: "Next",
onPressed: () { onPressed: () {
bool isValidated = appointmentsVM.isServiceSelectionValidated(); bool isValidated = appointmentsVM.isServiceSelectionValidated();
if (isValidated) { if (isValidated) {
appointmentsVM.getServiceItems(appointmentsVM.branchSelectedServiceId.selectedId); appointmentsVM.getServiceItems(appointmentsVM.branchSelectedServiceId.selectedId);
Navigator.pop(context);
navigateWithName(context, AppRoutes.bookAppointmentsItemView); navigateWithName(context, AppRoutes.bookAppointmentsItemView);
} }
}, },

@ -178,7 +178,10 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
showItem("Home service range", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "KM"), showItem("Home service range", widget.branchDetailModel.branchServices![index].customerLocationRange.toString() + "KM"),
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.toString() + "+ items").toText( ((widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0)
? widget.branchDetailModel.branchServices![index].itemsCount.toString() + " items"
: "No" + " items")
.toText(
fontSize: 12, fontSize: 12,
isBold: true, isBold: true,
color: MyColors.primaryColor, color: MyColors.primaryColor,
@ -187,7 +190,9 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
20.height, 20.height,
], ],
).onPress(() { ).onPress(() {
showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].serviceProviderServiceId ?? 0)); if (widget.branchDetailModel.branchServices![index].itemsCount != null && widget.branchDetailModel.branchServices![index].itemsCount! > 0) {
showMyBottomSheet(context, child: ItemsListSheet(widget.branchDetailModel.branchServices![index].serviceProviderServiceId ?? 0));
}
}), }),
], ],
onExpansionChanged: (value) { onExpansionChanged: (value) {

@ -30,12 +30,12 @@ class _ItemsListSheetState extends State<ItemsListSheet> {
height: MediaQuery.of(context).size.height / 1.2, height: MediaQuery.of(context).size.height / 1.2,
child: Consumer<AppointmentsVM>( child: Consumer<AppointmentsVM>(
builder: (context, appointmentsVM, _) { builder: (context, appointmentsVM, _) {
return appointmentsVM.serviceItems.isEmpty return appointmentsVM.serviceItemsFromApi.isEmpty
? const EmptyWidget() ? const EmptyWidget()
: ListView.separated( : ListView.separated(
itemCount: appointmentsVM.serviceItems.length, itemCount: appointmentsVM.serviceItemsFromApi.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
ItemData serviceItemModel = appointmentsVM.serviceItems[index]; ItemData serviceItemModel = appointmentsVM.serviceItemsFromApi[index];
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: Row( child: Row(

@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.17.0 <3.0.0"
# Dependencies specify other packages that your package needs in order to work. # Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions # To automatically upgrade your package dependencies to the latest versions

Loading…
Cancel
Save