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/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'; import 'package:mc_common_app/config/dependencies.dart';
class CustomerDependencies { class CustomerDependencies {
static void addDependencies() { static void addDependencies() {
AppDependencies.addDependencies(); AppDependencies.addDependencies();
injector.registerSingleton<ProviderRepo>(() => ProviderRepoImp()); 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_dependencies.dart';
import 'package:car_customer_app/config/customer_routes.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/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/appointments_view_model.dart';
import 'package:car_customer_app/view_models/dashboard_view_model.dart'; import 'package:car_customer_app/view_models/dashboard_view_model.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -56,7 +56,7 @@ Future<void> main() async {
), ),
ChangeNotifierProvider<AppointmentsVM>( ChangeNotifierProvider<AppointmentsVM>(
create: (_) => AppointmentsVM( create: (_) => AppointmentsVM(
scheduleRepo: injector.get<ScheduleRepo>(), scheduleRepo: injector.get<AppointmentRepo>(),
providerRepo: injector.get<ProviderRepo>(), providerRepo: injector.get<ProviderRepo>(),
commonServices: injector.get<CommonAppServices>(), commonServices: injector.get<CommonAppServices>(),
commonRepo: injector.get<CommonRepo>(), 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/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.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/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/schedule_model.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/service_schedule_model.dart';
import 'package:mc_common_app/utils/enums.dart';
abstract class ScheduleRepo { abstract class AppointmentRepo {
Future<Services> getAllServices(String branchId); Future<Services> getAllServices(String branchId);
Future<MResponse> createSchedule(Map map); Future<MResponse> createSchedule(Map map);
@ -26,10 +29,12 @@ abstract class ScheduleRepo {
required List<String> serviceItemIdsForWorkshop, 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 @override
Future<Services> getAllServices(String branchId) async { Future<Services> getAllServices(String branchId) async {
Map<String, dynamic> map = {"ProviderBranchID": branchId}; Map<String, dynamic> map = {"ProviderBranchID": branchId};
@ -98,26 +103,57 @@ class ScheduleRepoImp implements ScheduleRepo {
token: t, token: t,
); );
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], isForAppointment: true));
return serviceAppointmentScheduleModel; 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 ?? ""; String t = AppState().getUser.data!.accessToken ?? "";
var queryParameters = {
"id": 0, final payload = {
"serviceAppointmentID": serviceAppointmentID,
"serviceSlotID": serviceSlotID, "serviceSlotID": serviceSlotID,
"appointmentStatusID": 0, "appointmentScheduleAction": appointmentScheduleAction,
"serviceProviderID": 0,
"customerID": 0,
"isActive": true,
"serviceItemID": [11]
}; };
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject( GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
(json) => GenericRespModel.fromJson(json), (json) => GenericRespModel.fromJson(json),
ApiConsts.ServiceProvidersAppointmentCreate, ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment,
queryParameters, payload,
token: t, 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/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:car_customer_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.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/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';
import 'package:mc_common_app/models/service_schedule_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/navigator.dart';
import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart'; import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart'; import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AppointmentsVM extends BaseVM { class AppointmentsVM extends BaseVM {
final CommonRepo commonRepo; final CommonRepo commonRepo;
final CommonAppServices commonServices; final CommonAppServices commonServices;
final ProviderRepo providerRepo; final ProviderRepo providerRepo;
final ScheduleRepo scheduleRepo; final AppointmentRepo scheduleRepo;
AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo}); AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
bool isFetchingLists = false; bool isFetchingLists = false;
List<AppointmentListModel> myAppointments = []; List<AppointmentListModel> myAppointments = [];
List<AppointmentListModel> myUpComingAppointments = [];
List<AppointmentListModel> myFilteredAppointments = [];
List<FilterListModel> appointmentsFilterOptions = []; List<FilterListModel> appointmentsFilterOptions = [];
// List<ScheduleData> availableSchedules = []; // List<ScheduleData> availableSchedules = [];
@ -50,22 +53,6 @@ class AppointmentsVM extends BaseVM {
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = []; 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) { bool ifItemAlreadySelected(int id) {
int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id); int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
if (indexFound != -1) { if (indexFound != -1) {
@ -96,14 +83,73 @@ class AppointmentsVM extends BaseVM {
Future<void> onBookAppointmentPressed(BuildContext context) async { Future<void> onBookAppointmentPressed(BuildContext context) async {
Utils.showLoading(context); Utils.showLoading(context);
bool isSuccess = false;
List<int> appointmentIdsList = [];
try { try {
serviceAppointmentScheduleList.forEach((schedule) async { GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment(
List<String> serviceItemIds = []; schedules: serviceAppointmentScheduleList,
// schedule.serviceItemList!.forEach((serviceItem) { serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0,
// serviceItemIds.add(serviceItem.id.toString()); );
// });
await scheduleRepo.createServiceAppointment(serviceItemIds: serviceItemIds, serviceSlotID: schedule.selectedCustomTimeDateSlotModel!.date!.slotId); 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) { } catch (e) {
Utils.showToast("${e.toString()}"); Utils.showToast("${e.toString()}");
} }
@ -160,6 +206,11 @@ class AppointmentsVM extends BaseVM {
currentServiceSelection = null; currentServiceSelection = null;
} }
resetAfterBookingAppointment() {
servicesInCurrentAppointment.clear();
allSelectedItemsInAppointments.clear();
}
populateAppointmentsFilterList() { populateAppointmentsFilterList() {
appointmentsFilterOptions.clear(); appointmentsFilterOptions.clear();
appointmentsFilterOptions = [ appointmentsFilterOptions = [
@ -172,18 +223,29 @@ class AppointmentsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
applyFilterOnAppointmentsVM({required int index}) { applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) {
if (appointmentsFilterOptions.isEmpty) return; if (appointmentsFilterOptions.isEmpty) return;
for (var value in appointmentsFilterOptions) { for (var value in appointmentsFilterOptions) {
value.isSelected = false; 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(); notifyListeners();
} }
Future<void> getMyAppointments() async { Future<void> getMyAppointments() async {
isFetchingLists = true; isFetchingLists = true;
myAppointments = await commonRepo.getMyAppointments(); myAppointments = await commonRepo.getMyAppointments();
myFilteredAppointments = myAppointments;
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList();
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
isFetchingLists = false; isFetchingLists = false;
notifyListeners(); notifyListeners();
} }
@ -259,7 +321,7 @@ class AppointmentsVM extends BaseVM {
notifyListeners(); notifyListeners();
} }
populateProvidersFilterList() { populateBranchesFilterList() {
providersFilterOptions.clear(); providersFilterOptions.clear();
providersFilterOptions = [ providersFilterOptions = [
FilterListModel(title: "All Providers", isSelected: true, id: -1), FilterListModel(title: "All Providers", isSelected: true, id: -1),
@ -455,7 +517,7 @@ class AppointmentsVM extends BaseVM {
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
(selectedService.isHomeSelected (selectedService.isHomeSelected
? "${(selectedService.currentTotalServicePrice ?? 0.0) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" ? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
: "${selectedService.currentTotalServicePrice}") : "${selectedService.currentTotalServicePrice}")
.toText(fontSize: 29, isBold: true), .toText(fontSize: 29, isBold: true),
2.width, 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( serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
serviceItemIdsForHome: serviceItemIdsForHome, serviceItemIdsForHome: serviceItemIdsForHome,
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
@ -529,16 +587,12 @@ class AppointmentsVM extends BaseVM {
Utils.showToast("There are no available appointments for selected Items."); Utils.showToast("There are no available appointments for selected Items.");
return; return;
} }
totalAmount = 0.0;
amountToPayForAppointment = 0.0;
serviceAppointmentScheduleList.forEach( serviceAppointmentScheduleList.forEach(
(schedule) { (schedule) {
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
totalAmount = totalAmount + (schedule.amountTotal ?? 0.0);
schedule.servicesListInAppointment!.forEach((service) {
if (!ifServiceAlreadyThere(service.serviceProviderServiceId!)) {
servicesInSchedule.add(DropValue(service.serviceProviderServiceId!, service.providerServiceDescription!, ""));
}
});
}, },
); );
Utils.hideLoading(context); 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:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.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/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/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.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:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AppointmentDetailView extends StatelessWidget { class AppointmentDetailView extends StatelessWidget {
final AppointmentListModel appointmentListModel; final AppointmentListModel appointmentListModel;
@ -21,6 +26,97 @@ class AppointmentDetailView extends StatelessWidget {
"Oil Change", "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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -52,29 +148,42 @@ class AppointmentDetailView extends StatelessWidget {
], ],
), ),
13.height, 13.height,
Row( if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[
children: [ Column(
MyAssets.maintenanceIcon.buildSvg( children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
height: 10, ServiceModel service = appointmentListModel.appointmentServicesList![index];
width: 10, return Column(
fit: BoxFit.fill, crossAxisAlignment: CrossAxisAlignment.start,
), children: [
10.width, Row(
"Maintenance".toText(fontSize: 18, isBold: true), children: [
], // MyAssets.maintenanceIcon.buildSvg(
), // height: 10,
Column( // width: 10,
children: servicesList // fit: BoxFit.fill,
.map((e) => e // ),
.toText( // 10.width,
textAlign: TextAlign.start, "${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 18, isBold: true),
fontSize: 13, ],
isBold: true, ),
color: MyColors.lightTextColor, if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
) Column(
.paddingOnly(bottom: 5)) children: List.generate(
.toList(), service.serviceItems!.length,
).paddingOnly(left: 15), (index) => "${service.serviceItems![index].name}".toText(
textAlign: TextAlign.start,
fontSize: 13,
isBold: true,
color: MyColors.lightTextColor,
),
),
).paddingOnly(left: 15),
],
],
);
}),
),
],
15.height, 15.height,
Row( Row(
children: [ children: [
@ -83,43 +192,20 @@ class AppointmentDetailView extends StatelessWidget {
onCardTapped: () {}, onCardTapped: () {},
icon: MyAssets.scheduleAppointmentIcon.buildSvg(), icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
), ),
10.width, if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[
CardButtonWithIcon( 10.width,
title: "Pay for Appointment", CardButtonWithIcon(
onCardTapped: () {}, title: "Pay for Appointment",
icon: MyAssets.creditCardIcon.buildSvg(), onCardTapped: () {},
), icon: MyAssets.creditCardIcon.buildSvg(),
),
],
], ],
), ),
15.height, 15.height,
], ],
).toWhiteContainer(width: double.infinity, allPading: 12), ).toWhiteContainer(width: double.infinity, allPading: 12),
Align( buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context),
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,
),
),
],
],
),
),
], ],
), ),
), ),

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

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

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:car_customer_app/view_models/appointments_view_model.dart'; import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.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/service_schedule_model.dart';
import 'package:mc_common_app/models/services/item_model.dart'; import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/services/service_model.dart'; import 'package:mc_common_app/models/services/service_model.dart';
@ -93,7 +96,7 @@ class ReviewAppointment extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( 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( ListView.separated(
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: appointmentsVM.servicesInSchedule.length, itemCount: scheduleData.servicesListInAppointment!.length,
itemBuilder: (BuildContext context, int serviceIndex) { itemBuilder: (BuildContext context, int serviceIndex) {
String selectedTimeSlot = ""; String selectedTimeSlot = "";
if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) { if (scheduleData.selectedCustomTimeDateSlotModel!.availableSlots != null) {
@ -111,33 +114,38 @@ class ReviewAppointment extends StatelessWidget {
} }
return Column( return Column(
children: [ children: [
// Row( if (scheduleData.servicesListInAppointment!.isNotEmpty) ...[
// 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,
Column( Column(
children: List.generate(scheduleData.servicesListInAppointment!.length, (itemIndex) { children: List.generate(scheduleData.servicesListInAppointment!.length, (serviceIndex) {
ServiceModel serviceData = scheduleData.servicesListInAppointment![itemIndex]; ServiceModel serviceData = scheduleData.servicesListInAppointment![serviceIndex];
return Row( return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ 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, 5.height,
SizedBox( SizedBox(
@ -145,7 +153,7 @@ class ReviewAppointment extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
"Time & Location".toText(fontSize: 14, isBold: true), "Time & Location".toText(fontSize: 16, isBold: true),
3.height, 3.height,
Row(children: [ Row(children: [
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
@ -153,11 +161,43 @@ class ReviewAppointment extends StatelessWidget {
]), ]),
Row(children: [ Row(children: [
"Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "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() { Widget buildNextButtonFooter({required BuildContext context}) {
return SizedBox( AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
width: double.infinity, return Container(
color: MyColors.white,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"Time & Location".toText(fontSize: 16, isBold: true), Divider(thickness: 0.7, height: 3),
3.height, 8.height,
Row(children: [ if (appointmentsVM.amountToPayForAppointment > 0) ...[
"Date & Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), Row(
"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(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"${allSelectedItems[index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "Payable now".toText(fontSize: 14, isBold: true),
"${allSelectedItems[index].price} SAR".toText(fontSize: 12, 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),
],
)
], ],
), ).paddingOnly(left: 21, right: 21),
), Row(
), mainAxisAlignment: MainAxisAlignment.spaceBetween,
Row( children: [
mainAxisAlignment: MainAxisAlignment.end, "Remaining Amount".toText(fontSize: 14, isBold: true),
children: [ Row(
"${totalServicePrice.toString()} SAR".toText(fontSize: 16, isBold: true), 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( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"10km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), "Total Amount ".toText(fontSize: 18, isBold: true),
"5 x 10".toText(fontSize: 12, isBold: true), Row(
], crossAxisAlignment: CrossAxisAlignment.end,
), children: [
8.height, appointmentsVM.totalAmount.toString().toText(fontSize: 29, isBold: true),
Row( 2.width,
mainAxisAlignment: MainAxisAlignment.end, "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
children: [ ],
"50 SAR".toText(fontSize: 16, isBold: true), )
], ],
), ).paddingOnly(left: 21, right: 21),
10.height, 5.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,
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ShowFillButton( child: ShowFillButton(
@ -283,7 +272,7 @@ class ReviewAppointment extends StatelessWidget {
backgroundColor: MyColors.darkPrimaryColor, backgroundColor: MyColors.darkPrimaryColor,
title: "Book Appointment", title: "Book Appointment",
onPressed: () { onPressed: () {
// appointmentsVM.onBookAppointmentPressed(); appointmentsVM.onBookAppointmentPressed(context);
}, },
).paddingOnly(bottom: 12, left: 21, right: 21), ).paddingOnly(bottom: 12, left: 21, right: 21),
), ),
@ -299,7 +288,6 @@ class ReviewAppointment extends StatelessWidget {
title: "Review Appointment", title: "Review Appointment",
isRemoveBackButton: false, isRemoveBackButton: false,
isDrawerEnabled: false, isDrawerEnabled: false,
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
onBackButtonTapped: () => Navigator.pop(context), onBackButtonTapped: () => Navigator.pop(context),
), ),
body: Column( body: Column(
@ -309,8 +297,6 @@ class ReviewAppointment extends StatelessWidget {
children: [ children: [
buildBranchInfoCard(context: context), buildBranchInfoCard(context: context),
buildServicesInfoCard(context: context), buildServicesInfoCard(context: context),
// buildTimeAndLocationInfoCard(),
buildChargesBreakDown(context: context),
], ],
).expand(), ).expand(),
buildNextButtonFooter(context: context), buildNextButtonFooter(context: context),

@ -2,7 +2,6 @@ import 'dart:developer';
import 'package:car_customer_app/view_models/appointments_view_model.dart'; import 'package:car_customer_app/view_models/appointments_view_model.dart';
import 'package:flutter/material.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/extensions/string_extensions.dart';
import 'package:mc_common_app/models/service_schedule_model.dart'; import 'package:mc_common_app/models/service_schedule_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
@ -13,9 +12,10 @@ import 'package:provider/provider.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
class CustomCalenderWidget extends StatefulWidget { 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 @override
State<CustomCalenderWidget> createState() => _CustomCalenderWidgetState(); State<CustomCalenderWidget> createState() => _CustomCalenderWidgetState();
@ -41,22 +41,30 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
} }
populateDateList() { populateDateList() {
for (var value in widget.customTimeDateSlotList!) { for (var value in widget.customTimeDateSlotList) {
DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date); DateTime dt = DateFormat('dd MMMM, yyyy').parse(value.date!.date);
// TODO: THIS COMPARISON NEEDS TO BE FIXED!!!!! DropValue dv = DropValue(dt.month, "${dt.month.getMonthNameByNumber()}, ${dt.year}", "${dt.year}");
// TODO: BECAUSE WE CAN ONLY VALUE IN DROPDOWN, SO SUBVALUE IS OF NO USE!!
DropValue dv = DropValue(dt.month, "${dt.month.getMonthNameByNumber()}, ${dt.year}", "");
allDates.add(dt); allDates.add(dt);
if (!ifMonthAlreadyThere(dv)) { if (!ifMonthAlreadyThere(dv)) {
allMonths.add(dv); allMonths.add(dv);
} }
} }
selectedMonth = allDates.first.month; selectedMonth = allDates.first.month;
selectedYear = allDates.first.year; 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(); datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList();
if (appointmentsVM.serviceAppointmentScheduleList[widget.scheduleIndex].selectedCustomTimeDateSlotModel == null) {
_focusedDay = datesInSelectedMonth.first;
}
} }
bool ifMonthAlreadyThere(DropValue monthDate) { bool ifMonthAlreadyThere(DropValue monthDate) {
@ -64,7 +72,6 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
if (index == -1) { if (index == -1) {
return false; return false;
} }
return true; return true;
} }
@ -73,7 +80,6 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
if (index == -1) { if (index == -1) {
return false; return false;
} }
return true; return true;
} }
@ -93,10 +99,12 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
setState(() { setState(() {
selectedYear = int.parse(value.value.split(',')[1]); selectedYear = int.parse(value.value.split(',')[1]);
selectedMonth = value.value.split(',')[0].getMonthNumberByName(); selectedMonth = value.value.split(',')[0].getMonthNumberByName();
datesInSelectedMonth = allDates.where((element) => element.month == selectedMonth).toList();
_focusedDay = datesInSelectedMonth.first;
}); });
}, },
list: allMonths, list: allMonths,
// dropdownValue: DropValue(1, "${selectedMonth.getMonthNameByNumber()}jhvk,", "${selectedYear}"), dropdownValue: DropValue(selectedMonth, "${selectedMonth.getMonthNameByNumber()}, ${selectedYear}", "${selectedYear}"),
hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear", hint: "${selectedMonth.getMonthNameByNumber()}, $selectedYear",
errorValue: "", errorValue: "",
showAppointmentPickerVariant: true, showAppointmentPickerVariant: true,
@ -125,22 +133,6 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
weekendStyle: TextStyle(fontSize: 14, color: MyColors.black.withOpacity(0.5)), weekendStyle: TextStyle(fontSize: 14, color: MyColors.black.withOpacity(0.5)),
), ),
calendarBuilders: CalendarBuilders( 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) { selectedBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) {
return Container( return Container(
height: 50, height: 50,
@ -158,6 +150,22 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
); );
}, },
defaultBuilder: (BuildContext context, DateTime dateTime1, DateTime dateTime2) { 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( return Container(
height: 50, height: 50,
width: 50, width: 50,
@ -198,12 +206,28 @@ class _CustomCalenderWidgetState extends State<CustomCalenderWidget> {
return isSameDay(_selectedDay, day); return isSameDay(_selectedDay, day);
}, },
onDaySelected: (selectedDay, focusedDay) { onDaySelected: (selectedDay, focusedDay) {
int index = datesInSelectedMonth.indexWhere((element) => isSameDay(selectedDay, element));
if (index == -1) {
return;
}
if (!isSameDay(_selectedDay, selectedDay)) { if (!isSameDay(_selectedDay, selectedDay)) {
// Call `setState()` when updating the selected day
setState(() { setState(() {
_selectedDay = selectedDay; _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:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.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/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/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:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class CustomerAppointmentSliderWidget extends StatelessWidget { class CustomerAppointmentSliderWidget extends StatelessWidget {
final List<AppointmentListModel> myUpComingAppointments; final List<AppointmentListModel> myUpComingAppointments;
@ -18,31 +21,41 @@ class CustomerAppointmentSliderWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (myUpComingAppointments.isEmpty) { if (myUpComingAppointments.isEmpty) {
return InkWell( return CustomAddButton(
child: Container( needsBorder: true,
height: 86, bgColor: MyColors.white,
child: Row( onTap: () => context.read<DashboardVM>().onNavbarTapped(1),
mainAxisAlignment: MainAxisAlignment.center, text: "Add New Appointment",
children: [ icon: Container(
Container( height: 24,
height: 24, width: 24,
width: 24, decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), child: const Icon(Icons.add, color: MyColors.white),
child: Icon( ),
Icons.add, ).padding(EdgeInsets.symmetric(vertical: 10, horizontal: 21));
color: MyColors.white, return Container(
), height: 86,
), child: Row(
SizedBox(width: 10), mainAxisAlignment: MainAxisAlignment.center,
"Add New Appointment".toText( children: [
fontSize: 15, Container(
isBold: true, height: 24,
color: MyColors.lightTextColor, 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( return CarouselSlider.builder(
options: CarouselOptions( options: CarouselOptions(
@ -87,14 +100,14 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget {
} }
List<Widget> buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) { List<Widget> buildServicesFromAppointment({required AppointmentListModel appointmentListModel}) {
if (appointmentListModel.serviceAppointmentItems == null || appointmentListModel.serviceAppointmentItems!.isEmpty) { if (appointmentListModel.appointmentServicesList == null || appointmentListModel.appointmentServicesList!.isEmpty) {
return [SizedBox()]; return [SizedBox()];
} }
if (appointmentListModel.serviceAppointmentItems!.length == 1) { if (appointmentListModel.appointmentServicesList!.length == 1) {
return [ return [
showServices( showServices(
appointmentListModel.serviceAppointmentItems![0].serviceItemName!, appointmentListModel.appointmentServicesList![0].providerServiceDescription,
MyAssets.modificationsIcon, MyAssets.modificationsIcon,
) )
]; ];
@ -102,16 +115,13 @@ class BuildAppointmentContainerForCustomer extends StatelessWidget {
List<Widget> servicesList = List.generate( List<Widget> servicesList = List.generate(
2, 2,
(index) => showServices( (index) => showServices(appointmentListModel.appointmentServicesList![index].providerServiceDescription, MyAssets.modificationsIcon),
appointmentListModel.serviceAppointmentItems![index].serviceItemName!,
MyAssets.modificationsIcon,
),
); );
if (appointmentListModel.serviceAppointmentItems!.length > 1) { if (appointmentListModel.appointmentServicesList!.length > 1) {
servicesList.add( servicesList.add(
showServices( showServices(
"+ ${appointmentListModel.serviceAppointmentItems!.length - 1} More", "+ ${appointmentListModel.appointmentServicesList!.length - 1} More",
"", "",
isMoreText: true, isMoreText: true,
), ),

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

@ -25,11 +25,11 @@ class AppointmentsFragment extends StatelessWidget {
16.height, 16.height,
FiltersList( FiltersList(
filterList: appointmentsVM.appointmentsFilterOptions, filterList: appointmentsVM.appointmentsFilterOptions,
onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(index: index), onFilterTapped: (index, selectedFilterId) => appointmentsVM.applyFilterOnAppointmentsVM(appointmentStatusEnum: selectedFilterId.toAppointmentStatusEnum()),
), ),
16.height, 16.height,
Expanded( Expanded(
child: appointmentsVM.myAppointments.isEmpty child: appointmentsVM.myFilteredAppointments.isEmpty
? Column( ? Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -38,15 +38,15 @@ class AppointmentsFragment extends StatelessWidget {
) )
: ListView.builder( : ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: appointmentsVM.myAppointments.length, itemCount: appointmentsVM.myFilteredAppointments.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return BuildAppointmentContainerForCustomer( return BuildAppointmentContainerForCustomer(
onTapped: () => navigateWithName( onTapped: () => navigateWithName(
context, context,
AppRoutes.appointmentDetailView, 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", subTitle: "View All",
onSubtitleTapped: () { onSubtitleTapped: () {
context.read<DashboardVM>().onNavbarTapped(1); context.read<DashboardVM>().onNavbarTapped(1);
context.read<AppointmentsVM>().applyFilterOnAppointmentsVM(index: 0); context.read<AppointmentsVM>().applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
}, },
).horPaddingMain(), ).horPaddingMain(),
CustomerAppointmentSliderWidget(myUpComingAppointments: context.watch<AppointmentsVM>().myAppointments), CustomerAppointmentSliderWidget(myUpComingAppointments: context.read<AppointmentsVM>().myUpComingAppointments),
7.height, 7.height,
ViewAllWidget( ViewAllWidget(
title: "My Recent Service Providers".toUpperCase(), title: "My Recent Service Providers".toUpperCase(),
subTitle: "View All", subTitle: "View All",
onSubtitleTapped: () { onSubtitleTapped: () {
print("value: ${AppState().getUser.data!.accessToken}");
context.read<DashboardVM>().onNavbarTapped(0); context.read<DashboardVM>().onNavbarTapped(0);
context.read<AppointmentsVM>().applyFilterOnProviders(index: 0); context.read<AppointmentsVM>().applyFilterOnProviders(index: 0);
}).horPaddingMain(), }).horPaddingMain(),
const ServiceProviderWidget().horPaddingMain(), Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
return ServiceProviderWidget(nearbyBranches: context.read<AppointmentsVM>().nearbyBranches).horPaddingMain();
}),
Consumer( Consumer(
builder: (BuildContext context, AdVM adVM, Widget? child) { builder: (BuildContext context, AdVM adVM, Widget? child) {
return Column( return Column(

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

Loading…
Cancel
Save