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

@ -21,7 +21,9 @@ abstract class ScheduleRepo {
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 {
@ -71,18 +73,39 @@ class ScheduleRepoImp implements ScheduleRepo {
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 ?? "";
var dummyServiceIds = ["3", "2"];
var queryParameters = {"ServiceItemIDs": dummyServiceIds};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject(
var queryParameters = {
"appointmentType": appointmentType,
"ServiceItemIDs": serviceItemIds,
};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.GetServiceItemAppointmentScheduleSlots,
queryParameters,
token: t,
queryParameters: queryParameters,
);
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleModel =
List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index]));
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/schedule_repo.dart';
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
@ -11,6 +13,8 @@ import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
@ -47,24 +51,61 @@ class AppointmentsVM extends BaseVM {
Future<void> mergeServiceIntoAvailableSchedules() async {
List<String> serviceItemIds = [];
serviceItems.forEach((serviceItem) {
currentServiceSelection!.serviceItems!.forEach((serviceItem) {
if (serviceItem.isUpdateOrSelected!) {
serviceItemIds.add(serviceItem.id!.toString());
}
});
var scheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(serviceItemIds: serviceItemIds);
serviceAppointmentScheduleList.addAll(scheduleList);
servicesInCurrentAppointment.add(currentServiceSelection!);
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceItemIds: serviceItemIds,
appointmentType: isHomeTapped ? 2 : 1, // AppointmentType 1 for workshop and 2 for Home based schedule.
);
servicesInSchedule.clear();
serviceAppointmentScheduleList.forEach((schedule) {
schedule.serviceItemList!.forEach((item) {
if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) {
servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, ""));
}
});
});
if (serviceAppointmentScheduleList.isEmpty) {
Utils.showToast("There are no available appointments for selected Items.");
return;
}
serviceAppointmentScheduleList.forEach(
(schedule) {
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
schedule.serviceItemList!.forEach((item) {
if (!ifItemAlreadyThere(item.serviceProviderServiceId!)) {
servicesInSchedule.add(DropValue(item.serviceProviderServiceId!, item.description!, ""));
}
});
},
);
notifyListeners();
}
Future<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) {
int index = servicesInSchedule.indexWhere((element) => element.id == id);
if (index == -1) {
@ -99,6 +140,8 @@ class AppointmentsVM extends BaseVM {
BranchDetailModel? selectedBranchModel;
List<ServiceModel> branchServices = [];
List<ServiceModel> servicesInCurrentAppointment = [];
ServiceModel? currentServiceSelection;
void updateBranchServiceId(SelectionModel id) async {
@ -150,8 +193,70 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
List<ItemData> serviceItems = [];
List<ItemData> selectedServiceItems = [];
updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) {
element.date!.isSelected = false;
});
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
final date = TimeSlotModel(
date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date,
slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId,
isSelected: true,
slot: "",
);
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
notifyListeners();
}
updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) {
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!.forEach((element) {
element.availableSlots!.forEach((element) => element.isSelected = false);
});
int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true;
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!;
print("here: ${serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].slotId}");
notifyListeners();
}
double amountToPayForAppointment = 0.0;
double totalAmount = 0.0;
void onReviewButtonPressed(BuildContext context) {
bool isValidated = false;
for (int i = 0; i < serviceAppointmentScheduleList.length; i++) {
final schedule = serviceAppointmentScheduleList[i];
if (schedule.selectedCustomTimeDateSlotModel == null) {
isValidated = false;
break;
}
if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
isValidated = false;
break;
} else {
if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) {
isValidated = true;
break;
} else {
TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected);
if (slot.date.isNotEmpty) {
isValidated = true;
break;
}
}
}
}
if (!isValidated) {
Utils.showToast("You must select appointment time for each schedule's appointment.");
return;
}
navigateWithName(context, AppRoutes.reviewAppointmentView);
}
List<ItemData> serviceItemsFromApi = [];
ProviderProfileModel? providerProfileModel;
int selectedSubServicesCounter = 0;
@ -162,12 +267,12 @@ class AppointmentsVM extends BaseVM {
}
onItemUpdateOrSelected(int index, bool selected, int itemId) {
serviceItems[index].isUpdateOrSelected = selected;
serviceItemsFromApi[index].isUpdateOrSelected = selected;
if (selected) {
selectedSubServicesCounter = selectedSubServicesCounter + 1;
updateSelectedSubServicesCounter(selectedSubServicesCounter);
selectSubServicesError = "";
currentServiceSelection!.serviceItems!.add(serviceItems[index]);
currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]);
}
if (!selected) {
selectedSubServicesCounter = selectedSubServicesCounter - 1;
@ -208,10 +313,10 @@ class AppointmentsVM extends BaseVM {
}
Future<List<ItemData>> getServiceItems(int serviceId) async {
serviceItems.clear();
serviceItems = await providerRepo.getServiceItems(serviceId);
serviceItemsFromApi.clear();
serviceItemsFromApi = await providerRepo.getServiceItems(serviceId);
setState(ViewState.idle);
return serviceItems;
return serviceItemsFromApi;
}
getBranchAndServices(int providerId) async {
@ -263,7 +368,7 @@ class AppointmentsVM extends BaseVM {
void updatePickHomeLocationError(String value) {
pickHomeLocationError = value;
notifyListeners();
// notifyListeners();
}
bool isServiceSelectionValidated() {
@ -280,8 +385,8 @@ class AppointmentsVM extends BaseVM {
return true;
}
bool onSubServicesNextPressed() {
for (var value in serviceItems) {
bool validateItemsSelection() {
for (var value in serviceItemsFromApi) {
if (value.isUpdateOrSelected!) {
return true;
}

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

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

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

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

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

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

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

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

Loading…
Cancel
Save