Completed the Appointment Flow

aamir_dev
Faiz Hashmi 2 years ago
parent 120dc86309
commit 2dd1952b20

@ -1,12 +1,12 @@
import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:car_customer_app/repositories/appointment_repo.dart';
import 'package:mc_common_app/config/dependencies.dart';
class CustomerDependencies {
static void addDependencies() {
AppDependencies.addDependencies();
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp());
injector.registerSingleton<ScheduleRepo>(() => ScheduleRepoImp());
injector.registerSingleton<AppointmentRepo>(() => ScheduleRepoImp());
}
}

@ -1,7 +1,7 @@
import 'package:car_customer_app/config/customer_dependencies.dart';
import 'package:car_customer_app/config/customer_routes.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/appointment_repo.dart';
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/view_models/dashboard_view_model.dart';
import 'package:easy_localization/easy_localization.dart';
@ -56,7 +56,7 @@ Future<void> main() async {
),
ChangeNotifierProvider<AppointmentsVM>(
create: (_) => AppointmentsVM(
scheduleRepo: injector.get<ScheduleRepo>(),
scheduleRepo: injector.get<AppointmentRepo>(),
providerRepo: injector.get<ProviderRepo>(),
commonServices: injector.get<CommonAppServices>(),
commonRepo: injector.get<CommonRepo>(),

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
@ -7,8 +9,9 @@ import 'package:mc_common_app/models/m_response.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/schedule_model.dart';
import 'package:mc_common_app/models/service_schedule_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class ScheduleRepo {
abstract class AppointmentRepo {
Future<Services> getAllServices(String branchId);
Future<MResponse> createSchedule(Map map);
@ -26,10 +29,12 @@ abstract class ScheduleRepo {
required List<String> serviceItemIdsForWorkshop,
});
Future<void> createServiceAppointment({required List<String> serviceItemIds, required int serviceSlotID});
Future<GenericRespModel> createServiceAppointment({required List<ServiceAppointmentScheduleModel> schedules, required int serviceProviderID});
Future<GenericRespModel> cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction});
}
class ScheduleRepoImp implements ScheduleRepo {
class ScheduleRepoImp implements AppointmentRepo {
@override
Future<Services> getAllServices(String branchId) async {
Map<String, dynamic> map = {"ProviderBranchID": branchId};
@ -98,26 +103,57 @@ class ScheduleRepoImp implements ScheduleRepo {
token: t,
);
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], isForAppointment: true));
return serviceAppointmentScheduleModel;
}
Future<void> createServiceAppointment({required List<String> serviceItemIds, required int serviceSlotID}) async {
Future<GenericRespModel> createServiceAppointment({required List<ServiceAppointmentScheduleModel> schedules, required int serviceProviderID}) async {
String t = AppState().getUser.data!.accessToken ?? "";
int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;
List<Map<String, dynamic>> mapList = [];
schedules.forEach((schedule) {
List<int> serviceItemIds = [];
schedule.servicesListInAppointment!.forEach((service) {
service.serviceItems!.forEach((item) {
serviceItemIds.add(item.id!);
});
});
mapList.add({
"serviceSlotID": schedule.selectedCustomTimeDateSlotModel!.date!.slotId,
"serviceProviderID": serviceProviderID,
"customerID": customerId,
"serviceItemID": serviceItemIds,
});
});
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.ServiceProvidersAppointmentCreate,
mapList,
token: t,
);
return adsGenericModel;
}
@override
Future<GenericRespModel> cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}) async {
String t = AppState().getUser.data!.accessToken ?? "";
var queryParameters = {
"id": 0,
final payload = {
"serviceAppointmentID": serviceAppointmentID,
"serviceSlotID": serviceSlotID,
"appointmentStatusID": 0,
"serviceProviderID": 0,
"customerID": 0,
"isActive": true,
"serviceItemID": [11]
"appointmentScheduleAction": appointmentScheduleAction,
};
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.ServiceProvidersAppointmentCreate,
queryParameters,
ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment,
payload,
token: t,
);
return adsGenericModel;
}
}

@ -1,15 +1,14 @@
import 'dart:developer';
import 'package:car_customer_app/repositories/provider_repo.dart';
import 'package:car_customer_app/repositories/schedule_repo.dart';
import 'package:car_customer_app/repositories/appointment_repo.dart';
import 'package:car_customer_app/view_models/dashboard_view_model.dart';
import 'package:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/generic_resp_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/service_schedule_model.dart';
@ -23,21 +22,25 @@ 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/payment_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AppointmentsVM extends BaseVM {
final CommonRepo commonRepo;
final CommonAppServices commonServices;
final ProviderRepo providerRepo;
final ScheduleRepo scheduleRepo;
final AppointmentRepo scheduleRepo;
AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
bool isFetchingLists = false;
List<AppointmentListModel> myAppointments = [];
List<AppointmentListModel> myUpComingAppointments = [];
List<AppointmentListModel> myFilteredAppointments = [];
List<FilterListModel> appointmentsFilterOptions = [];
// List<ScheduleData> availableSchedules = [];
@ -50,22 +53,6 @@ class AppointmentsVM extends BaseVM {
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];
// Future<void> getSchedulesByBranchId() async {
// availableSchedules = await scheduleRepo.getSchedules(selectedBranchModel!.id!.toString());
// log("schedules: ${availableSchedules.toString()}");
// notifyListeners();
// }
List<DropValue> servicesInSchedule = [];
bool ifServiceAlreadyThere(int id) {
int index = servicesInSchedule.indexWhere((element) => element.id == id);
if (index == -1) {
return false;
}
return true;
}
bool ifItemAlreadySelected(int id) {
int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
if (indexFound != -1) {
@ -96,14 +83,73 @@ class AppointmentsVM extends BaseVM {
Future<void> onBookAppointmentPressed(BuildContext context) async {
Utils.showLoading(context);
bool isSuccess = false;
List<int> appointmentIdsList = [];
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);
});
GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment(
schedules: serviceAppointmentScheduleList,
serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0,
);
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data != null) {
genericRespModel.data.forEach((element) {
if (element['appointmentID'] != 0) {
appointmentIdsList.add(element['appointmentID']);
isSuccess = true;
} else {
isSuccess = false;
return;
}
});
}
context.read<DashboardVM>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked);
Utils.hideLoading(context);
resetAfterBookingAppointment();
if (isSuccess) {
if (amountToPayForAppointment > 0) {
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: appointmentIdsList);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
} else {
Utils.showToast("Your appointment has been booked successfully!");
getMyAppointments();
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
}
} catch (e) {
Utils.showToast("${e.toString()}");
}
}
Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
Utils.showLoading(context);
try {
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
serviceAppointmentID: appointmentListModel.id ?? 0,
serviceSlotID: appointmentListModel.serviceSlotID ?? 0,
appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel
);
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
Utils.hideLoading(context);
Utils.showToast("${genericRespModel.message.toString()}");
return;
}
if (genericRespModel.data == 1) {
context.read<DashboardVM>().onNavbarTapped(1);
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
Utils.showToast("${genericRespModel.message.toString()}");
await getMyAppointments();
Utils.hideLoading(context);
getMyAppointments();
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
} catch (e) {
Utils.showToast("${e.toString()}");
}
@ -160,6 +206,11 @@ class AppointmentsVM extends BaseVM {
currentServiceSelection = null;
}
resetAfterBookingAppointment() {
servicesInCurrentAppointment.clear();
allSelectedItemsInAppointments.clear();
}
populateAppointmentsFilterList() {
appointmentsFilterOptions.clear();
appointmentsFilterOptions = [
@ -172,18 +223,29 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
applyFilterOnAppointmentsVM({required int index}) {
applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) {
if (appointmentsFilterOptions.isEmpty) return;
for (var value in appointmentsFilterOptions) {
value.isSelected = false;
}
appointmentsFilterOptions[index].isSelected = true;
appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum() == -1 ? 0 : appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true;
if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == -1) {
myFilteredAppointments = myAppointments;
notifyListeners();
return;
}
myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList();
notifyListeners();
}
Future<void> getMyAppointments() async {
isFetchingLists = true;
myAppointments = await commonRepo.getMyAppointments();
myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList();
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
isFetchingLists = false;
notifyListeners();
}
@ -259,7 +321,7 @@ class AppointmentsVM extends BaseVM {
notifyListeners();
}
populateProvidersFilterList() {
populateBranchesFilterList() {
providersFilterOptions.clear();
providersFilterOptions = [
FilterListModel(title: "All Providers", isSelected: true, id: -1),
@ -455,7 +517,7 @@ class AppointmentsVM extends BaseVM {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(selectedService.isHomeSelected
? "${(selectedService.currentTotalServicePrice ?? 0.0) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}")
.toText(fontSize: 29, isBold: true),
2.width,
@ -515,10 +577,6 @@ class AppointmentsVM extends BaseVM {
}
});
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,
@ -529,16 +587,12 @@ class AppointmentsVM extends BaseVM {
Utils.showToast("There are no available appointments for selected Items.");
return;
}
totalAmount = 0.0;
amountToPayForAppointment = 0.0;
serviceAppointmentScheduleList.forEach(
(schedule) {
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
schedule.servicesListInAppointment!.forEach((service) {
if (!ifServiceAlreadyThere(service.serviceProviderServiceId!)) {
servicesInSchedule.add(DropValue(service.serviceProviderServiceId!, service.providerServiceDescription!, ""));
}
});
totalAmount = totalAmount + (schedule.amountTotal ?? 0.0);
},
);
Utils.hideLoading(context);

@ -1,13 +1,18 @@
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.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/services/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
import 'package:mc_common_app/utils/enums.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/card_button_with_icon.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AppointmentDetailView extends StatelessWidget {
final AppointmentListModel appointmentListModel;
@ -21,6 +26,97 @@ class AppointmentDetailView extends StatelessWidget {
"Oil Change",
];
Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) {
return Expanded(
child: ShowFillButton(
maxHeight: 55,
title: text,
onPressed: onPressed,
backgroundColor: color,
txtColor: textColor,
fontSize: 18,
),
);
}
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) {
switch (appointmentStatusEnum) {
case AppointmentStatusEnum.booked:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
12.width,
getBaseActionButtonWidget(color: MyColors.greenColor, onPressed: () {}, text: "Confirm"),
],
),
);
case AppointmentStatusEnum.confirmed:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
],
),
);
case AppointmentStatusEnum.arrived:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "In Progress"),
],
),
);
case AppointmentStatusEnum.cancelled:
return Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"),
],
),
);
case AppointmentStatusEnum.allAppointments:
return SizedBox();
}
}
void appointmentCancelConfirmationSheet(BuildContext context) {
final appointmentsVm = context.read<AppointmentsVM>();
return actionConfirmationBottomSheet(
context: context,
title: "Do you want to cancel this appointment?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: "Your appointment will be cancelled and you cannot undo this action.",
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Yes",
fontSize: 15,
onPressed: () {
Navigator.pop(context);
appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: "No",
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -52,29 +148,42 @@ class AppointmentDetailView extends StatelessWidget {
],
),
13.height,
Row(
children: [
MyAssets.maintenanceIcon.buildSvg(
height: 10,
width: 10,
fit: BoxFit.fill,
),
10.width,
"Maintenance".toText(fontSize: 18, isBold: true),
],
),
Column(
children: servicesList
.map((e) => e
.toText(
textAlign: TextAlign.start,
fontSize: 13,
isBold: true,
color: MyColors.lightTextColor,
)
.paddingOnly(bottom: 5))
.toList(),
).paddingOnly(left: 15),
if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[
Column(
children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
ServiceModel service = appointmentListModel.appointmentServicesList![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
// MyAssets.maintenanceIcon.buildSvg(
// height: 10,
// width: 10,
// fit: BoxFit.fill,
// ),
// 10.width,
"${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 18, isBold: true),
],
),
if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
Column(
children: List.generate(
service.serviceItems!.length,
(index) => "${service.serviceItems![index].name}".toText(
textAlign: TextAlign.start,
fontSize: 13,
isBold: true,
color: MyColors.lightTextColor,
),
),
).paddingOnly(left: 15),
],
],
);
}),
),
],
15.height,
Row(
children: [
@ -83,43 +192,20 @@ class AppointmentDetailView extends StatelessWidget {
onCardTapped: () {},
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
),
10.width,
CardButtonWithIcon(
title: "Pay for Appointment",
onCardTapped: () {},
icon: MyAssets.creditCardIcon.buildSvg(),
),
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[
10.width,
CardButtonWithIcon(
title: "Pay for Appointment",
onCardTapped: () {},
icon: MyAssets.creditCardIcon.buildSvg(),
),
],
],
),
15.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12),
Align(
alignment: Alignment.bottomCenter,
child: Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Cancel",
onPressed: () {},
backgroundColor: MyColors.redColor,
),
),
if (appointmentListModel.appointmentStatusID == 1) ...[
12.width,
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Confirm",
onPressed: () {},
backgroundColor: MyColors.greenColor,
),
),
],
],
),
),
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context),
],
),
),

@ -1,22 +1,15 @@
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart';
import 'package:car_customer_app/views/appointments/widgets/custom_calender_widget.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/service_schedule_model.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/models/services/service_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/views/advertisement/custom_add_button.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
@ -70,13 +63,13 @@ class BookAppointmentSchedulesView extends StatelessWidget {
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: appointmentsVM.servicesInSchedule.length,
itemCount: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) {
DropValue selectedService = appointmentsVM.servicesInSchedule[serviceIndex];
ServiceModel selectedService = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment![serviceIndex];
return Row(
children: [
Expanded(
child: ("${serviceIndex + 1}. ${selectedService.value}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor),
child: ("${serviceIndex + 1}. ${selectedService.providerServiceDescription}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor),
),
],
);
@ -89,18 +82,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
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 ?? []),
],
CustomCalenderWidget(customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? [], scheduleIndex: scheduleIndex),
if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[
5.height,
Row(
@ -135,7 +117,7 @@ class BookAppointmentSchedulesView extends StatelessWidget {
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () {},
onPressed: () => Navigator.pop(context),
backgroundColor: MyColors.greyButtonColor,
),
),

@ -104,7 +104,11 @@ class BookAppointmentServicesView extends StatelessWidget {
txtColor: MyColors.black,
maxHeight: 55,
title: "Cancel",
onPressed: () {},
onPressed: () {
appointmentsVM.servicesInCurrentAppointment.clear();
appointmentsVM.allSelectedItemsInAppointments.clear();
Navigator.pop(context);
},
backgroundColor: MyColors.greyButtonColor,
),
),

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -5,6 +7,7 @@ import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/models/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/service_model.dart';
@ -93,7 +96,7 @@ class ReviewAppointment extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: "Schedule: ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
child: "Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
),
],
),
@ -103,7 +106,7 @@ class ReviewAppointment extends StatelessWidget {
ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: appointmentsVM.servicesInSchedule.length,
itemCount: scheduleData.servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) {
String selectedTimeSlot = "";
if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
@ -111,33 +114,38 @@ class ReviewAppointment extends StatelessWidget {
}
return Column(
children: [
// 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),
(appointmentsVM.isHomeTapped ? "Home" : "Workshop").toText(fontSize: 12, isBold: true).expand(),
],
),
5.height,
if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[
Column(
children: List.generate(scheduleData.servicesListInAppointment!.length, (itemIndex) {
ServiceModel serviceData = scheduleData.servicesListInAppointment![itemIndex];
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) {
ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex];
return Column(
children: [
"${serviceData.providerServiceDescription}".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"${serviceData.providerServiceDescription}".toText(fontSize: 16, isBold: true),
],
),
Column(
children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
ItemData itemData = serviceData.serviceItems![itemIndex];
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"${itemData.name}: ${itemData.price} SAR".toText(fontSize: 13, isBold: true, color: MyColors.lightTextColor),
],
),
],
);
}),
),
],
);
}),
),
).paddingOnly(bottom: 10),
],
5.height,
SizedBox(
@ -145,7 +153,7 @@ class ReviewAppointment extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Time & Location".toText(fontSize: 14, isBold: true),
"Time & Location".toText(fontSize: 16, isBold: true),
3.height,
Row(children: [
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
@ -153,11 +161,43 @@ class ReviewAppointment extends StatelessWidget {
]),
Row(children: [
"Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"PM58+F97, Al Olaya, Riyadh 12333".toText(fontSize: 12, isBold: true),
(scheduleData.appointmentType == 2 ? "Home" : "Workshop").toText(fontSize: 12, isBold: true),
]),
],
),
)
),
10.height,
Divider(thickness: 0.7),
Builder(builder: (BuildContext context) {
double totalServicePrice = 0.0;
double totalKms = 15.3;
double rangePricePerKm = 5;
totalServicePrice = rangePricePerKm * totalKms;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Amount".toText(fontSize: 16, isBold: true),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Service Charges".toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true),
"${scheduleData.amountTotal.toString()} SAR".toText(fontSize: 16, isBold: true),
],
),
if (scheduleData.appointmentType == 1) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Location Charges ($rangePricePerKm x $totalKms )".toText(fontSize: 14, color: MyColors.lightTextColor, isBold: true),
"${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true),
],
),
],
10.height,
],
);
}),
],
);
},
@ -171,111 +211,60 @@ class ReviewAppointment extends StatelessWidget {
);
}
Widget buildTimeAndLocationInfoCard() {
return SizedBox(
width: double.infinity,
Widget buildNextButtonFooter({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Container(
color: MyColors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Time & Location".toText(fontSize: 16, isBold: true),
3.height,
Row(children: [
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"2nd Feb, 2023 at 09:30 AM".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),
]),
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10)),
);
}
Widget buildChargesBreakDown({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
List<ItemData> allSelectedItems = [];
double totalServicePrice = 0.0;
// appointmentsVM.serviceAppointmentScheduleList.forEach((schedule) {
// schedule.servicesListInAppointment!.forEach((service) {
// allSelectedItems.add(item);
// totalServicePrice = totalServicePrice + double.parse(item.price!);
// });
// });
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Services".toText(fontSize: 16, isBold: true),
Column(
children: List.generate(
allSelectedItems.length,
(index) => Row(
Divider(thickness: 0.7, height: 3),
8.height,
if (appointmentsVM.amountToPayForAppointment > 0) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${allSelectedItems[index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
"${allSelectedItems[index].price} SAR".toText(fontSize: 12, isBold: true),
"Payable now".toText(fontSize: 14, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appointmentsVM.amountToPayForAppointment.toString().toText(fontSize: 16, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
],
)
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
"${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true),
).paddingOnly(left: 21, right: 21),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Remaining Amount".toText(fontSize: 14, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
(appointmentsVM.totalAmount - appointmentsVM.amountToPayForAppointment).toString().toText(fontSize: 16, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 2),
],
)
],
).paddingOnly(left: 21, right: 21),
],
),
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),
"Total Amount ".toText(fontSize: 18, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
appointmentsVM.totalAmount.toString().toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
),
10.height,
Divider(thickness: 0.7),
],
10.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Total Amount ".toText(fontSize: 16, isBold: true),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
totalServicePrice.toString().toText(fontSize: 29, isBold: true),
2.width,
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
],
)
],
),
10.height,
],
).toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.only(left: 21, right: 21, top: 10, bottom: 21));
}
Widget buildNextButtonFooter({required BuildContext context}) {
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
return Container(
height: 90,
color: MyColors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Divider(thickness: 0.7, height: 3),
10.height,
).paddingOnly(left: 21, right: 21),
5.height,
SizedBox(
width: double.infinity,
child: ShowFillButton(
@ -283,7 +272,7 @@ class ReviewAppointment extends StatelessWidget {
backgroundColor: MyColors.darkPrimaryColor,
title: "Book Appointment",
onPressed: () {
// appointmentsVM.onBookAppointmentPressed();
appointmentsVM.onBookAppointmentPressed(context);
},
).paddingOnly(bottom: 12, left: 21, right: 21),
),
@ -299,7 +288,6 @@ class ReviewAppointment extends StatelessWidget {
title: "Review Appointment",
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
onBackButtonTapped: () => Navigator.pop(context),
),
body: Column(
@ -309,8 +297,6 @@ class ReviewAppointment extends StatelessWidget {
children: [
buildBranchInfoCard(context: context),
buildServicesInfoCard(context: context),
// buildTimeAndLocationInfoCard(),
buildChargesBreakDown(context: context),
],
).expand(),
buildNextButtonFooter(context: context),

@ -2,7 +2,6 @@ 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';
@ -13,9 +12,10 @@ import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
class CustomCalenderWidget extends StatefulWidget {
final List<CustomTimeDateSlotModel>? customTimeDateSlotList;
final List<CustomTimeDateSlotModel> customTimeDateSlotList;
final int scheduleIndex;
const CustomCalenderWidget({super.key, required this.customTimeDateSlotList});
const CustomCalenderWidget({super.key, required this.customTimeDateSlotList, required this.scheduleIndex});
@override
State<CustomCalenderWidget> createState() => _CustomCalenderWidgetState();
@ -41,22 +41,30 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
}
populateDateList() {
for (var value in widget.customTimeDateSlotList!) {
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}", "");
DropValue dv = DropValue(dt.month, "${dt.month.getMonthNameByNumber()}, ${dt.year}", "${dt.year}");
allDates.add(dt);
if (!ifMonthAlreadyThere(dv)) {
allMonths.add(dv);
}
}
selectedMonth = allDates.first.month;
selectedYear = allDates.first.year;
final appointmentsVM = context.read<AppointmentsVM>();
if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel != null) {
DateTime alreadySelectedDate = DateFormat('dd MMMM, yyyy').parse(appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel!.date!.date);
_selectedDay = alreadySelectedDate;
_focusedDay = alreadySelectedDate;
selectedMonth = alreadySelectedDate.month;
selectedYear = alreadySelectedDate.year;
}
datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList();
if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel == null) {
_focusedDay = datesInSelectedMonth.first;
}
}
bool ifMonthAlreadyThere(DropValue monthDate) {
@ -64,7 +72,6 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
if (index == -1) {
return false;
}
return true;
}
@ -73,7 +80,6 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
if (index == -1) {
return false;
}
return true;
}
@ -93,10 +99,12 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
setState(() {
selectedYear = int.parse(value.value.split(',')[1]);
selectedMonth = value.value.split(',')[0].getMonthNumberByName();
datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList();
_focusedDay = datesInSelectedMonth.first;
});
},
list: allMonths,
// dropdownValue: DropValue(1, "${selectedMonth.getMonthNameByNumber()}jhvk,", "${selectedYear}"),
dropdownValue: DropValue(selectedMonth, "${selectedMonth.getMonthNameByNumber()}, ${selectedYear}", "${selectedYear}"),
hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear",
errorValue: "",
showAppointmentPickerVariant: true,
@ -125,22 +133,6 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
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,
@ -158,6 +150,22 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
);
},
defaultBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) {
int index = datesInSelectedMonth.indexWhere((element) => isSameDay(dateTime1, element));
if (index == -1) {
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(),
),
);
}
return Container(
height: 50,
width: 50,
@ -198,12 +206,28 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
return isSameDay(_selectedDay, day);
},
onDaySelected: (selectedDay, focusedDay) {
int index = datesInSelectedMonth.indexWhere((element) => isSameDay(selectedDay, element));
if (index == -1) {
return;
}
if (!isSameDay(_selectedDay, selectedDay)) {
// Call `setState()` when updating the selected day
setState(() {
_selectedDay = selectedDay;
_focusedDay = selectedDay;
_focusedDay = focusedDay;
});
int dateIndex = widget.customTimeDateSlotList.indexWhere((element) {
DateTime dateFromList = DateFormat('dd MMMM, yyyy').parse(element.date!.date);
if (isSameDay(dateFromList, selectedDay)) {
return true;
}
return false;
});
if (dateIndex != -1) {
appointmentsVM.updateSelectedAppointmentDate(scheduleIndex: widget.scheduleIndex, dateIndex: dateIndex);
}
}
},
),

@ -1,3 +1,4 @@
import 'package:car_customer_app/view_models/dashboard_view_model.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
@ -8,7 +9,9 @@ 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/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/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class CustomerAppointmentSliderWidget extends StatelessWidget {
final List<AppointmentListModel> myUpComingAppointments;
@ -18,31 +21,41 @@ class CustomerAppointmentSliderWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (myUpComingAppointments.isEmpty) {
return InkWell(
child: Container(
height: 86,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 24,
width: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: Icon(
Icons.add,
color: MyColors.white,
),
),
SizedBox(width: 10),
"Add New Appointment".toText(
fontSize: 15,
isBold: true,
color: MyColors.lightTextColor,
return CustomAddButton(
needsBorder: true,
bgColor: MyColors.white,
onTap: () => context.read<DashboardVM>().onNavbarTapped(1),
text: "Add New Appointment",
icon: Container(
height: 24,
width: 24,
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: const Icon(Icons.add, color: MyColors.white),
),
).padding(EdgeInsets.symmetric(vertical: 10, horizontal: 21));
return Container(
height: 86,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 24,
width: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
child: Icon(
Icons.add,
color: MyColors.white,
),
],
),
),
SizedBox(width: 10),
"Add New Appointment".toText(
fontSize: 15,
isBold: true,
color: MyColors.lightTextColor,
),
],
),
).toWhiteContainer(width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10));
).onPress(() {}).toWhiteContainer(width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10));
}
return CarouselSlider.builder(
options: CarouselOptions(
@ -87,14 +100,14 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget {
}
List<Widget> buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) {
if (appointmentListModel.serviceAppointmentItems == null || appointmentListModel.serviceAppointmentItems!.isEmpty) {
if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) {
return [SizedBox()];
}
if (appointmentListModel.serviceAppointmentItems!.length == 1) {
if (appointmentListModel.appointmentServicesList!.length == 1) {
return [
showServices(
appointmentListModel.serviceAppointmentItems![0].serviceItemName!,
appointmentListModel.appointmentServicesList![0].providerServiceDescription,
MyAssets.modificationsIcon,
)
];
@ -102,16 +115,13 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget {
List<Widget> servicesList = List.generate(
2,
(index) => showServices(
appointmentListModel.serviceAppointmentItems![index].serviceItemName!,
MyAssets.modificationsIcon,
),
(index) => showServices(appointmentListModel.appointmentServicesList![index].providerServiceDescription, MyAssets.modificationsIcon),
);
if (appointmentListModel.serviceAppointmentItems!.length > 1) {
if (appointmentListModel.appointmentServicesList!.length > 1) {
servicesList.add(
showServices(
"+ ${appointmentListModel.serviceAppointmentItems!.length - 1} More",
"+ ${appointmentListModel.appointmentServicesList!.length - 1} More",
"",
isMoreText: true,
),

@ -34,30 +34,30 @@ class _DashboardPageState extends State<DashboardPage> {
void initState() {
super.initState();
// dashboardVM = Provider.of<DashboardVM>(context, listen: false);
fetchUsername();
scheduleMicrotask(() {
context.read<AppointmentsVM>().populateAppointmentsFilterList();
context.read<AppointmentsVM>().populateProvidersFilterList();
context.read<AppointmentsVM>().populateBranchesFilterList();
context.read<AdVM>().populateAdsFilterList();
context.read<AppointmentsVM>().getAllNearBranches();
_onRefresh();
});
}
Future<void> _onRefresh() async {
AdVM adVm = Provider.of<AdVM>(context, listen: false);
AdVM adVM = Provider.of<AdVM>(context, listen: false);
AppointmentsVM appointmentsVM = Provider.of<AppointmentsVM>(context, listen: false);
if (appointmentsVM.myAppointments.isEmpty) {
await appointmentsVM.getMyAppointments();
}
if (adVm.myAds.isEmpty) {
await adVm.getMyAds();
if (appointmentsVM.nearbyBranches.isEmpty) {
await appointmentsVM.getAllNearBranches();
}
if (adVm.exploreAds.isEmpty) {
await adVm.getExploreAds();
if (adVM.myAds.isEmpty) {
await adVM.getMyAds();
}
if (adVM.exploreAds.isEmpty) {
await adVM.getExploreAds();
}
final adVM = context.read<AdVM>();
if (adVM.vehicleTypes.isEmpty) {
await adVM.getVehicleTypes();
}
@ -74,8 +74,6 @@ class _DashboardPageState extends State<DashboardPage> {
);
}
fetchUsername() async {}
List<Widget> fragments = [
const BranchesFragment(),
const AppointmentsFragment(),
@ -106,7 +104,6 @@ class _DashboardPageState extends State<DashboardPage> {
@override
Widget build(BuildContext context) {
bool isHomePage = context.watch<DashboardVM>().selectedNavbarBarIndex == 2;
bool isAdsPage = context.watch<DashboardVM>().selectedNavbarBarIndex == 3;
return Scaffold(
appBar: CustomAppBar(
backgroundColor: null,

@ -25,11 +25,11 @@ class AppointmentsFragment extends StatelessWidget {
16.height,
FiltersList(
filterList: appointmentsVM.appointmentsFilterOptions,
onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(index: index),
onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum()),
),
16.height,
Expanded(
child: appointmentsVM.myAppointments.isEmpty
child: appointmentsVM.myFilteredAppointments.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -38,15 +38,15 @@ class AppointmentsFragment extends StatelessWidget {
)
: ListView.builder(
shrinkWrap: true,
itemCount: appointmentsVM.myAppointments.length,
itemCount: appointmentsVM.myFilteredAppointments.length,
itemBuilder: (BuildContext context, int index) {
return BuildAppointmentContainerForCustomer(
onTapped: () => navigateWithName(
context,
AppRoutes.appointmentDetailView,
arguments: appointmentsVM.myAppointments[index],
arguments: appointmentsVM.myFilteredAppointments[index],
),
appointmentListModel: appointmentsVM.myAppointments[index],
appointmentListModel: appointmentsVM.myFilteredAppointments[index],
);
},
),

@ -32,20 +32,21 @@ class HomeFragment extends StatelessWidget {
subTitle: "View All",
onSubtitleTapped: () {
context.read<DashboardVM>().onNavbarTapped(1);
context.read<AppointmentsVM>().applyFilterOnAppointmentsVM(index: 0);
context.read<AppointmentsVM>().applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
},
).horPaddingMain(),
CustomerAppointmentSliderWidget(myUpComingAppointments: context.watch<AppointmentsVM>().myAppointments),
CustomerAppointmentSliderWidget(myUpComingAppointments: context.read<AppointmentsVM>().myUpComingAppointments),
7.height,
ViewAllWidget(
title: "My Recent Service Providers".toUpperCase(),
subTitle: "View All",
onSubtitleTapped: () {
print("value: ${AppState().getUser.data!.accessToken}");
context.read<DashboardVM>().onNavbarTapped(0);
context.read<AppointmentsVM>().applyFilterOnProviders(index: 0);
}).horPaddingMain(),
const ServiceProviderWidget().horPaddingMain(),
Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
return ServiceProviderWidget(nearbyBranches: context.read<AppointmentsVM>().nearbyBranches).horPaddingMain();
}),
Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column(

@ -94,13 +94,7 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
color: MyColors.primaryColor,
),
],
)
.padding(
EdgeInsets.symmetric(vertical: 6, horizontal: 2),
)
.onPress(
() {},
),
).padding(EdgeInsets.symmetric(vertical: 6, horizontal: 2)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
@ -119,14 +113,8 @@ class _BranchDetailPageState extends State<BranchDetailPage> {
),
],
)
.padding(
EdgeInsets.symmetric(vertical: 6, horizontal: 2),
)
.onPress(
() {
navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchDetailModel.serviceProviderId);
},
),
.padding(EdgeInsets.symmetric(vertical: 6, horizontal: 2))
.onPress(() => navigateWithName(context, AppRoutes.providerProfilePage, arguments: widget.branchDetailModel.serviceProviderId)),
],
),
20.height,

Loading…
Cancel
Save