|
|
|
|
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/general_models/enums_model.dart';
|
|
|
|
|
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
|
|
|
|
|
import 'package:mc_common_app/models/general_models/m_response.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/appointments_models/service_schedule_model.dart';
|
|
|
|
|
import 'package:mc_common_app/models/services_models/item_model.dart';
|
|
|
|
|
import 'package:mc_common_app/models/services_models/service_model.dart';
|
|
|
|
|
import 'package:mc_common_app/models/general_models/widgets_models.dart';
|
|
|
|
|
import 'package:mc_common_app/repositories/appointment_repo.dart';
|
|
|
|
|
import 'package:mc_common_app/repositories/common_repo.dart';
|
|
|
|
|
import 'package:mc_common_app/repositories/provider_repo.dart';
|
|
|
|
|
import 'package:mc_common_app/services/common_services.dart';
|
|
|
|
|
import 'package:mc_common_app/theme/colors.dart';
|
|
|
|
|
import 'package:mc_common_app/utils/enums.dart';
|
|
|
|
|
import 'package:mc_common_app/utils/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/dashboard_view_model_customer.dart';
|
|
|
|
|
import 'package:mc_common_app/view_models/payment_view_model.dart';
|
|
|
|
|
import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart';
|
|
|
|
|
import 'package:mc_common_app/views/appointments/widgets/appointment_service_pick_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/extensions/extensions_widget.dart';
|
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
|
|
import '../models/appointments_models/appointment_slots.dart';
|
|
|
|
|
|
|
|
|
|
class AppointmentsVM extends BaseVM {
|
|
|
|
|
final CommonRepo commonRepo;
|
|
|
|
|
final CommonAppServices commonServices;
|
|
|
|
|
final ProviderRepo providerRepo;
|
|
|
|
|
final AppointmentRepo scheduleRepo;
|
|
|
|
|
|
|
|
|
|
AppointmentsVM({required this.commonServices,
|
|
|
|
|
required this.scheduleRepo,
|
|
|
|
|
required this.providerRepo,
|
|
|
|
|
required this.commonRepo});
|
|
|
|
|
|
|
|
|
|
bool isUpcommingEnabled = true;
|
|
|
|
|
bool isFetchingLists = false;
|
|
|
|
|
int selectedBranch = 0;
|
|
|
|
|
int selectedAppointmentIndex = 0;
|
|
|
|
|
int selectedAppointmentSubIndex = 0;
|
|
|
|
|
int selectedAppointmentId = 0;
|
|
|
|
|
|
|
|
|
|
List<AppointmentListModel> myAppointments = [];
|
|
|
|
|
List<AppointmentListModel> myUpComingAppointments = [];
|
|
|
|
|
List<AppointmentListModel> myFilteredAppointments = [];
|
|
|
|
|
List<FilterListModel> appointmentsFilterOptions = [];
|
|
|
|
|
List<CustomerData> customersAppointments = [];
|
|
|
|
|
List<AppointmentListModel> myFilteredAppointments2 = [];
|
|
|
|
|
|
|
|
|
|
// List<ScheduleData> availableSchedules = [];
|
|
|
|
|
|
|
|
|
|
bool isFetchingServices = false;
|
|
|
|
|
|
|
|
|
|
List<DropValue> branchCategories = [];
|
|
|
|
|
|
|
|
|
|
bool isHomeTapped = false;
|
|
|
|
|
|
|
|
|
|
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];
|
|
|
|
|
|
|
|
|
|
bool ifItemAlreadySelected(int id) {
|
|
|
|
|
int indexFound = allSelectedItemsInAppointments
|
|
|
|
|
.indexWhere((element) => element.id == id);
|
|
|
|
|
if (indexFound != -1) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<ItemData> allSelectedItemsInAppointments = [];
|
|
|
|
|
|
|
|
|
|
setupProviderAppointmentFilter() {
|
|
|
|
|
appointmentsFilterOptions.clear();
|
|
|
|
|
appointmentsFilterOptions.add(
|
|
|
|
|
FilterListModel(id: 0, title: "All Appointments", isSelected: true));
|
|
|
|
|
appointmentsFilterOptions
|
|
|
|
|
.add(FilterListModel(id: 2, title: "Confirmed", isSelected: false));
|
|
|
|
|
appointmentsFilterOptions
|
|
|
|
|
.add(FilterListModel(id: 3, title: "Arrived", isSelected: false));
|
|
|
|
|
appointmentsFilterOptions
|
|
|
|
|
.add(
|
|
|
|
|
FilterListModel(id: 7, title: "Work In Progress", isSelected: false));
|
|
|
|
|
appointmentsFilterOptions
|
|
|
|
|
.add(FilterListModel(id: 8, title: "Completed", isSelected: false));
|
|
|
|
|
appointmentsFilterOptions
|
|
|
|
|
.add(FilterListModel(id: 4, title: "Canceled", isSelected: false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> onItemsSelectedInService() async {
|
|
|
|
|
if (currentServiceSelection != null) {
|
|
|
|
|
int index = servicesInCurrentAppointment.indexWhere((element) =>
|
|
|
|
|
element.serviceId == currentServiceSelection!.serviceId!);
|
|
|
|
|
|
|
|
|
|
if (index == -1) {
|
|
|
|
|
double totalPrice = 0.0;
|
|
|
|
|
for (var element in currentServiceSelection!.serviceItems!) {
|
|
|
|
|
totalPrice = totalPrice + double.parse(element.price ?? "0.0");
|
|
|
|
|
}
|
|
|
|
|
currentServiceSelection!.currentTotalServicePrice = totalPrice;
|
|
|
|
|
servicesInCurrentAppointment.insert(0, currentServiceSelection!);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resetCategorySelectionBottomSheet();
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> onBookAppointmentPressed(BuildContext context) async {
|
|
|
|
|
Utils.showLoading(context);
|
|
|
|
|
bool isSuccess = false;
|
|
|
|
|
List<int> appointmentIdsList = [];
|
|
|
|
|
try {
|
|
|
|
|
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<DashboardVmCustomer>().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> onConfirmAppointmentPressed(
|
|
|
|
|
{required BuildContext context, required appointmentId}) async {
|
|
|
|
|
context
|
|
|
|
|
.read<PaymentVM>()
|
|
|
|
|
.updateAppointmentIdsForPayment(ids: [appointmentId]);
|
|
|
|
|
navigateWithName(context, AppRoutes.paymentMethodsView,
|
|
|
|
|
arguments: PaymentTypes.appointment);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<DashboardVmCustomer>().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()}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateIsHomeTapped(bool value) {
|
|
|
|
|
isHomeTapped = value;
|
|
|
|
|
if (currentServiceSelection != null) {
|
|
|
|
|
currentServiceSelection!.isHomeSelected = value;
|
|
|
|
|
}
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String pickedHomeLocation = "";
|
|
|
|
|
|
|
|
|
|
void updatePickedHomeLocation(String value) {
|
|
|
|
|
pickedHomeLocation = value;
|
|
|
|
|
pickHomeLocationError = "";
|
|
|
|
|
if (currentServiceSelection != null) {
|
|
|
|
|
currentServiceSelection!.homeLocation = value;
|
|
|
|
|
}
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SelectionModel branchSelectedCategoryId =
|
|
|
|
|
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
|
|
|
|
|
|
|
|
void updateProviderCategoryId(SelectionModel id) {
|
|
|
|
|
branchSelectedCategoryId = id;
|
|
|
|
|
getBranchServices(categoryId: branchSelectedCategoryId.selectedId);
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<FilterListModel> providersFilterOptions = [];
|
|
|
|
|
List<BranchDetailModel> nearbyBranches = [];
|
|
|
|
|
BranchDetailModel? selectedBranchModel;
|
|
|
|
|
|
|
|
|
|
List<ServiceModel> branchServices = [];
|
|
|
|
|
|
|
|
|
|
List<ServiceModel> servicesInCurrentAppointment = [];
|
|
|
|
|
ServiceModel? currentServiceSelection;
|
|
|
|
|
|
|
|
|
|
void updateBranchServiceId(SelectionModel id) async {
|
|
|
|
|
branchSelectedServiceId = id;
|
|
|
|
|
currentServiceSelection = branchServices.firstWhere(
|
|
|
|
|
(element) => element.serviceProviderServiceId == id.selectedId);
|
|
|
|
|
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeServiceInCurrentAppointment(int index) {
|
|
|
|
|
int serviceId = servicesInCurrentAppointment
|
|
|
|
|
.elementAt(index)
|
|
|
|
|
.serviceProviderServiceId ??
|
|
|
|
|
-1;
|
|
|
|
|
allSelectedItemsInAppointments.removeWhere(
|
|
|
|
|
(element) => element.serviceProviderServiceId == serviceId);
|
|
|
|
|
servicesInCurrentAppointment.removeAt(index);
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resetCategorySelectionBottomSheet() {
|
|
|
|
|
selectedSubServicesCounter = 0;
|
|
|
|
|
branchSelectedCategoryId =
|
|
|
|
|
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
|
|
|
isHomeTapped = false;
|
|
|
|
|
branchSelectedServiceId =
|
|
|
|
|
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
|
|
|
currentServiceSelection = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resetAfterBookingAppointment() {
|
|
|
|
|
allSelectedItemsInAppointments.clear();
|
|
|
|
|
// servicesInCurrentAppointment.clear();
|
|
|
|
|
serviceAppointmentScheduleList.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<EnumsModel> myAppointmentsEnum = [];
|
|
|
|
|
|
|
|
|
|
populateAppointmentsFilterList() async {
|
|
|
|
|
appointmentsFilterOptions.clear();
|
|
|
|
|
|
|
|
|
|
myAppointmentsEnum = await commonRepo.getEnumTypeValues(
|
|
|
|
|
enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < myAppointmentsEnum.length; i++) {
|
|
|
|
|
appointmentsFilterOptions.add(FilterListModel(
|
|
|
|
|
title: myAppointmentsEnum[i].enumValueStr,
|
|
|
|
|
isSelected: false,
|
|
|
|
|
id: myAppointmentsEnum[i].enumValue));
|
|
|
|
|
}
|
|
|
|
|
appointmentsFilterOptions.insert(
|
|
|
|
|
0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));
|
|
|
|
|
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
applyFilterOnAppointmentsVM(
|
|
|
|
|
{required AppointmentStatusEnum appointmentStatusEnum,
|
|
|
|
|
bool isNeedCustomerFilter = false}) {
|
|
|
|
|
if (appointmentsFilterOptions.isEmpty) return;
|
|
|
|
|
for (var value in appointmentsFilterOptions) {
|
|
|
|
|
value.isSelected = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
appointmentsFilterOptions.forEach((element) {
|
|
|
|
|
if (element.id ==
|
|
|
|
|
appointmentStatusEnum.getIdFromAppointmentStatusEnum()) {
|
|
|
|
|
element.isSelected = true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// appointmentsFilterOptions[
|
|
|
|
|
// appointmentStatusEnum.getIdFromAppointmentStatusEnum()]
|
|
|
|
|
// .isSelected = true;
|
|
|
|
|
|
|
|
|
|
if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) {
|
|
|
|
|
myFilteredAppointments = myAppointments;
|
|
|
|
|
if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers();
|
|
|
|
|
notifyListeners();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
myFilteredAppointments = myAppointments
|
|
|
|
|
.where((element) =>
|
|
|
|
|
element.appointmentStatusID! ==
|
|
|
|
|
appointmentStatusEnum.getIdFromAppointmentStatusEnum())
|
|
|
|
|
.toList();
|
|
|
|
|
if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers();
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
findAppointmentsBasedOnCustomers() {
|
|
|
|
|
// Use a Set to ensure uniqueness of customerIDs
|
|
|
|
|
Set<int> uniqueCustomerIDs = Set<int>();
|
|
|
|
|
|
|
|
|
|
// Extract unique customerIDs
|
|
|
|
|
for (var item in myFilteredAppointments) {
|
|
|
|
|
uniqueCustomerIDs.add(item.customerID ?? 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a list of CustomerData instances
|
|
|
|
|
myFilteredAppointments2 = uniqueCustomerIDs.map((id) {
|
|
|
|
|
List<AppointmentListModel> list = myFilteredAppointments
|
|
|
|
|
.where((item) => item.customerID == id)
|
|
|
|
|
.toList();
|
|
|
|
|
AppointmentListModel model = list.first;
|
|
|
|
|
model.customerAppointmentList = list;
|
|
|
|
|
return model;
|
|
|
|
|
}).toList();
|
|
|
|
|
// customersAppointments = uniqueCustomerIDs.map((id) {
|
|
|
|
|
// List<AppointmentListModel> list = myFilteredAppointments
|
|
|
|
|
// .where((item) => item.customerID == id)
|
|
|
|
|
// .toList();
|
|
|
|
|
// var customerItem =
|
|
|
|
|
// myFilteredAppointments.firstWhere((item) => item.customerID == id);
|
|
|
|
|
//
|
|
|
|
|
// return CustomerData(
|
|
|
|
|
// customerID: id,
|
|
|
|
|
// customerName: customerItem.customerName ?? "",
|
|
|
|
|
// appointmentList: list,
|
|
|
|
|
// );
|
|
|
|
|
// }).toList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> getMyAppointments({bool isNeedToRebuild = false}) async {
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
|
|
|
|
|
myAppointments = await commonRepo.getMyAppointments();
|
|
|
|
|
myFilteredAppointments = myAppointments;
|
|
|
|
|
myUpComingAppointments = myAppointments
|
|
|
|
|
.where((element) =>
|
|
|
|
|
element.appointmentStatusEnum == AppointmentStatusEnum.confirmed)
|
|
|
|
|
.toList();
|
|
|
|
|
setState(ViewState.idle);
|
|
|
|
|
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AppointmentSlots? appointmentSlots;
|
|
|
|
|
|
|
|
|
|
Future<void> getAppointmentSlotsInfo({required Map<String, dynamic> map,
|
|
|
|
|
required BuildContext context,
|
|
|
|
|
bool isNeedToRebuild = false}) async {
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
try {
|
|
|
|
|
MResponse genericRespModel = await scheduleRepo.getAppointmentSlots(map);
|
|
|
|
|
if (genericRespModel.messageStatus == 1) {
|
|
|
|
|
appointmentSlots = AppointmentSlots.fromJson(genericRespModel.data);
|
|
|
|
|
} else {
|
|
|
|
|
Utils.showToast(genericRespModel.message.toString());
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Utils.showToast(e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> getProviderMyAppointments(Map<String, dynamic> map,
|
|
|
|
|
{bool isNeedToRebuild = false}) async {
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
|
|
|
|
|
myAppointments = await scheduleRepo.getMyAppointments(map);
|
|
|
|
|
myFilteredAppointments = myAppointments;
|
|
|
|
|
myUpComingAppointments = myAppointments
|
|
|
|
|
.where((element) =>
|
|
|
|
|
element.appointmentStatusEnum == AppointmentStatusEnum.booked)
|
|
|
|
|
.toList();
|
|
|
|
|
|
|
|
|
|
applyFilterOnAppointmentsVM(
|
|
|
|
|
appointmentStatusEnum: AppointmentStatusEnum.allAppointments,
|
|
|
|
|
isNeedCustomerFilter: true);
|
|
|
|
|
setState(ViewState.idle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateSelectedBranch(BranchDetailModel branchDetailModel) {
|
|
|
|
|
selectedBranchModel = branchDetailModel;
|
|
|
|
|
getBranchCategories();
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateAppointmentStatus(Map<String, dynamic> map,
|
|
|
|
|
{bool isNeedToRebuild = false}) async {
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
try {
|
|
|
|
|
MResponse genericRespModel =
|
|
|
|
|
await scheduleRepo.updateAppointmentStatus(map);
|
|
|
|
|
|
|
|
|
|
if (genericRespModel.messageStatus == 1) {
|
|
|
|
|
Utils.showToast("appointment status updated");
|
|
|
|
|
} else {
|
|
|
|
|
Utils.showToast(genericRespModel.message.toString());
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Utils.showToast(e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateAppointmentPaymentStatus(Map<String, dynamic> map,
|
|
|
|
|
{bool isNeedToRebuild = false}) async {
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
try {
|
|
|
|
|
MResponse genericRespModel =
|
|
|
|
|
await scheduleRepo.updateAppointmentPaymentStatus(map);
|
|
|
|
|
|
|
|
|
|
if (genericRespModel.messageStatus == 1) {
|
|
|
|
|
Utils.showToast("payment status updated");
|
|
|
|
|
} else {
|
|
|
|
|
Utils.showToast(genericRespModel.message.toString());
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Utils.showToast(e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<MResponse> createMergeAppointment(Map<String, dynamic> map,
|
|
|
|
|
{bool isNeedToRebuild = false}) async {
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
MResponse genericRespModel =
|
|
|
|
|
await scheduleRepo.createMergeAppointment(map);
|
|
|
|
|
|
|
|
|
|
return genericRespModel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool inNeedToEnableMergeButton = false;
|
|
|
|
|
|
|
|
|
|
updateCheckBoxInMergeRequest(int currentIndex) {
|
|
|
|
|
myFilteredAppointments2[selectedAppointmentIndex]
|
|
|
|
|
.customerAppointmentList![currentIndex]
|
|
|
|
|
.isSelected = !(myFilteredAppointments2[selectedAppointmentIndex]
|
|
|
|
|
.customerAppointmentList?[currentIndex]
|
|
|
|
|
.isSelected ??
|
|
|
|
|
false);
|
|
|
|
|
|
|
|
|
|
int count = countSelected(myFilteredAppointments2[selectedAppointmentIndex]
|
|
|
|
|
.customerAppointmentList ??
|
|
|
|
|
[]);
|
|
|
|
|
if (count > 1)
|
|
|
|
|
inNeedToEnableMergeButton = true;
|
|
|
|
|
else
|
|
|
|
|
inNeedToEnableMergeButton = false;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int countSelected(List<AppointmentListModel> appointments) {
|
|
|
|
|
return appointments
|
|
|
|
|
.where((appointment) => appointment.isSelected == true)
|
|
|
|
|
.toList()
|
|
|
|
|
.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateSelectedAppointmentDate(
|
|
|
|
|
{required int dateIndex, required int scheduleIndex}) {
|
|
|
|
|
for (var element in serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList!) {
|
|
|
|
|
element.date!.isSelected = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList![dateIndex]
|
|
|
|
|
.date!
|
|
|
|
|
.isSelected = true;
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
|
|
|
|
|
final date = TimeSlotModel(
|
|
|
|
|
date: serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList![dateIndex]
|
|
|
|
|
.date!
|
|
|
|
|
.date,
|
|
|
|
|
slotId: serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList![dateIndex]
|
|
|
|
|
.date!
|
|
|
|
|
.slotId,
|
|
|
|
|
isSelected: true,
|
|
|
|
|
slot: "",
|
|
|
|
|
);
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateSelectedAppointmentSlotByDate(
|
|
|
|
|
{required int scheduleIndex, required int slotIndex}) {
|
|
|
|
|
for (var element in serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList!) {
|
|
|
|
|
for (var element in element.availableSlots!) {
|
|
|
|
|
element.isSelected = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
int index =
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList![index]
|
|
|
|
|
.availableSlots![slotIndex]
|
|
|
|
|
.isSelected = true;
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.selectedCustomTimeDateSlotModel!
|
|
|
|
|
.availableSlots =
|
|
|
|
|
serviceAppointmentScheduleList[scheduleIndex]
|
|
|
|
|
.customTimeDateSlotList![index]
|
|
|
|
|
.availableSlots!;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double amountToPayForAppointment = 0.0;
|
|
|
|
|
double totalAmount = 0.0;
|
|
|
|
|
|
|
|
|
|
List<ItemData> serviceItemsFromApi = [];
|
|
|
|
|
|
|
|
|
|
ProviderProfileModel? providerProfileModel;
|
|
|
|
|
|
|
|
|
|
int selectedSubServicesCounter = 0;
|
|
|
|
|
|
|
|
|
|
onItemUpdateOrSelected(int index, bool selected, int itemId) {
|
|
|
|
|
int serviceIndex = servicesInCurrentAppointment.indexWhere(
|
|
|
|
|
(element) =>
|
|
|
|
|
element.serviceId == currentServiceSelection!.serviceId!);
|
|
|
|
|
// print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}");
|
|
|
|
|
// if (serviceIndex == -1) {
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
serviceItemsFromApi[index].isUpdateOrSelected = selected;
|
|
|
|
|
serviceItemsFromApi[index].isHomeSelected = isHomeTapped;
|
|
|
|
|
if (selected) {
|
|
|
|
|
selectedSubServicesCounter = selectedSubServicesCounter + 1;
|
|
|
|
|
selectSubServicesError = "";
|
|
|
|
|
currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]);
|
|
|
|
|
allSelectedItemsInAppointments.add(serviceItemsFromApi[index]);
|
|
|
|
|
for (var element in allSelectedItemsInAppointments) {
|
|
|
|
|
if (!ifItemAlreadySelected(element.id!)) {
|
|
|
|
|
servicesInCurrentAppointment[serviceIndex]
|
|
|
|
|
.serviceItems!
|
|
|
|
|
.add(serviceItemsFromApi[index]);
|
|
|
|
|
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
|
|
|
|
|
servicesInCurrentAppointment[serviceIndex]
|
|
|
|
|
.currentTotalServicePrice +
|
|
|
|
|
double.parse((serviceItemsFromApi[index].price) ?? "0.0");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!selected) {
|
|
|
|
|
selectedSubServicesCounter = selectedSubServicesCounter - 1;
|
|
|
|
|
currentServiceSelection!.serviceItems!
|
|
|
|
|
.removeWhere((element) => element.id == itemId);
|
|
|
|
|
allSelectedItemsInAppointments
|
|
|
|
|
.removeWhere((element) => element.id == itemId);
|
|
|
|
|
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
|
|
|
|
|
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice -
|
|
|
|
|
double.parse((serviceItemsFromApi[index].price) ?? "0.0");
|
|
|
|
|
servicesInCurrentAppointment[serviceIndex]
|
|
|
|
|
.serviceItems!
|
|
|
|
|
.removeWhere((element) => element.id == itemId);
|
|
|
|
|
}
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
populateBranchesFilterList() {
|
|
|
|
|
providersFilterOptions.clear();
|
|
|
|
|
providersFilterOptions = [
|
|
|
|
|
FilterListModel(title: "All Providers", isSelected: true, id: 0),
|
|
|
|
|
FilterListModel(title: "Maintenance", isSelected: false, id: 1),
|
|
|
|
|
FilterListModel(title: "Oil Service", isSelected: false, id: 2),
|
|
|
|
|
FilterListModel(title: "Accessories", isSelected: false, id: 3),
|
|
|
|
|
FilterListModel(title: "Tire Service", isSelected: false, id: 4),
|
|
|
|
|
FilterListModel(title: "Dent and Paint", isSelected: false, id: 5),
|
|
|
|
|
];
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
applyFilterOnProviders({required int index}) {
|
|
|
|
|
if (providersFilterOptions.isEmpty) return;
|
|
|
|
|
for (var value in providersFilterOptions) {
|
|
|
|
|
value.isSelected = false;
|
|
|
|
|
}
|
|
|
|
|
providersFilterOptions[index].isSelected = true;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getAllNearBranches({bool isNeedToRebuild = false}) async {
|
|
|
|
|
//TODO: needs to lat,long into API
|
|
|
|
|
nearbyBranches.clear();
|
|
|
|
|
if (isNeedToRebuild) setState(ViewState.busy);
|
|
|
|
|
nearbyBranches = await providerRepo.getAllNearBranchAndServices();
|
|
|
|
|
setState(ViewState.idle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<List<ItemData>> getServiceItems(int serviceId) async {
|
|
|
|
|
serviceItemsFromApi.clear();
|
|
|
|
|
serviceItemsFromApi = await providerRepo.getServiceItems(serviceId);
|
|
|
|
|
for (var item in serviceItemsFromApi) {
|
|
|
|
|
if (ifItemAlreadySelected(item.id!)) {
|
|
|
|
|
item.isUpdateOrSelected = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setState(ViewState.idle);
|
|
|
|
|
return serviceItemsFromApi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getBranchAndServices(int providerId) async {
|
|
|
|
|
providerProfileModel = null;
|
|
|
|
|
providerProfileModel = await providerRepo.getBranchAndServices(providerId);
|
|
|
|
|
setState(ViewState.idle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String pickHomeLocationError = "";
|
|
|
|
|
String selectSubServicesError = "";
|
|
|
|
|
|
|
|
|
|
SelectionModel branchSelectedServiceId =
|
|
|
|
|
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
|
|
|
|
|
|
|
|
bool isCategoryAlreadyPresent(int id) {
|
|
|
|
|
final contain = branchCategories.where((element) => element.id == id);
|
|
|
|
|
if (contain.isEmpty) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void getBranchCategories() async {
|
|
|
|
|
for (var value in selectedBranchModel!.branchServices!) {
|
|
|
|
|
if (!isCategoryAlreadyPresent(value.categoryId!)) {
|
|
|
|
|
branchCategories
|
|
|
|
|
.add(DropValue(value.categoryId!, value.categoryName!, ""));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getBranchServices({required int categoryId}) async {
|
|
|
|
|
branchSelectedServiceId =
|
|
|
|
|
SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
|
|
|
|
isHomeTapped = false;
|
|
|
|
|
pickedHomeLocation = "";
|
|
|
|
|
pickHomeLocationError = "";
|
|
|
|
|
if (categoryId != -1) {
|
|
|
|
|
isFetchingServices = true;
|
|
|
|
|
branchServices = getFilteredBranchServices(categoryId: categoryId);
|
|
|
|
|
isFetchingServices = false;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
|
|
|
|
|
List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!
|
|
|
|
|
.where((element) => element.categoryId == categoryId)
|
|
|
|
|
.toList();
|
|
|
|
|
return filteredServices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updatePickHomeLocationError(String value) {
|
|
|
|
|
pickHomeLocationError = value;
|
|
|
|
|
// notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isServiceSelectionValidated() {
|
|
|
|
|
if (branchSelectedServiceId.selectedId == -1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isHomeTapped) {
|
|
|
|
|
if (pickedHomeLocation == "") {
|
|
|
|
|
updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool validateItemsSelection() {
|
|
|
|
|
for (var value in serviceItemsFromApi) {
|
|
|
|
|
if (value.isUpdateOrSelected!) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
selectSubServicesError = "Please select at least one sub service";
|
|
|
|
|
notifyListeners();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getTotalPrice(List<ServiceModel> serviceItems) {
|
|
|
|
|
var totalPrice = 0.0;
|
|
|
|
|
for (var element in serviceItems) {
|
|
|
|
|
totalPrice = totalPrice + (element.currentTotalServicePrice);
|
|
|
|
|
}
|
|
|
|
|
return totalPrice.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void openTheAddServiceBottomSheet(BuildContext context,
|
|
|
|
|
AppointmentsVM appointmentsVM) {
|
|
|
|
|
showModalBottomSheet(
|
|
|
|
|
context: context,
|
|
|
|
|
isScrollControlled: true,
|
|
|
|
|
enableDrag: true,
|
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
|
return AppointmentServicePickBottomSheet();
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void priceBreakDownClicked(BuildContext context,
|
|
|
|
|
ServiceModel selectedService) {
|
|
|
|
|
showModalBottomSheet(
|
|
|
|
|
context: context,
|
|
|
|
|
isScrollControlled: true,
|
|
|
|
|
enableDrag: true,
|
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
|
double totalKms = 15.3;
|
|
|
|
|
return InfoBottomSheet(
|
|
|
|
|
title: "Charges Breakdown".toText(fontSize: 24, isBold: true),
|
|
|
|
|
description: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
"Services".toText(fontSize: 16, isBold: true),
|
|
|
|
|
Column(
|
|
|
|
|
children: List.generate(
|
|
|
|
|
selectedService.serviceItems!.length,
|
|
|
|
|
(index) =>
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
children: [
|
|
|
|
|
"${selectedService.serviceItems![index].name}"
|
|
|
|
|
.toText(
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
color: MyColors.lightTextColor,
|
|
|
|
|
isBold: true),
|
|
|
|
|
"${selectedService.serviceItems![index]
|
|
|
|
|
.price} SAR"
|
|
|
|
|
.toText(fontSize: 12, isBold: true),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
|
|
|
children: [
|
|
|
|
|
"${selectedService.currentTotalServicePrice} SAR"
|
|
|
|
|
.toText(fontSize: 16, isBold: true),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
if (selectedService.isHomeSelected) ...[
|
|
|
|
|
20.height,
|
|
|
|
|
"Home Location".toText(fontSize: 16, isBold: true),
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
children: [
|
|
|
|
|
"${totalKms}km ".toText(
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
color: MyColors.lightTextColor,
|
|
|
|
|
isBold: true),
|
|
|
|
|
"${selectedService.rangePricePerKm} x $totalKms"
|
|
|
|
|
.toText(fontSize: 12, isBold: true),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
8.height,
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
|
|
|
children: [
|
|
|
|
|
"${selectedService.rangePricePerKm ?? 0 * totalKms} SAR"
|
|
|
|
|
.toText(fontSize: 16, isBold: true),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
30.height,
|
|
|
|
|
Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
children: [
|
|
|
|
|
"Total Amount ".toText(fontSize: 16, isBold: true),
|
|
|
|
|
Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
|
|
|
children: [
|
|
|
|
|
(selectedService.isHomeSelected
|
|
|
|
|
? "${(selectedService.currentTotalServicePrice) +
|
|
|
|
|
(double.parse((selectedService.rangePricePerKm ??
|
|
|
|
|
"0.0")) * totalKms)}"
|
|
|
|
|
: "${selectedService.currentTotalServicePrice}")
|
|
|
|
|
.toText(fontSize: 29, isBold: true),
|
|
|
|
|
2.width,
|
|
|
|
|
"SAR"
|
|
|
|
|
.toText(
|
|
|
|
|
color: MyColors.lightTextColor,
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
isBold: true)
|
|
|
|
|
.paddingOnly(bottom: 5),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
30.height,
|
|
|
|
|
],
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onReviewButtonPressed(BuildContext context) {
|
|
|
|
|
bool isValidated = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < serviceAppointmentScheduleList.length; i++) {
|
|
|
|
|
final schedule = serviceAppointmentScheduleList[i];
|
|
|
|
|
if (schedule.selectedCustomTimeDateSlotModel == null) {
|
|
|
|
|
isValidated = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (schedule.selectedCustomTimeDateSlotModel!.date == null ||
|
|
|
|
|
!schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
|
|
|
|
|
isValidated = false;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) {
|
|
|
|
|
isValidated = false;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
TimeSlotModel slot = schedule
|
|
|
|
|
.selectedCustomTimeDateSlotModel!.availableSlots!
|
|
|
|
|
.firstWhere((element) => element.isSelected);
|
|
|
|
|
if (slot.date.isNotEmpty) {
|
|
|
|
|
isValidated = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!isValidated) {
|
|
|
|
|
Utils.showToast(
|
|
|
|
|
"You must select appointment time for each schedule's appointment.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
navigateWithName(context, AppRoutes.reviewAppointmentView);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onServicesNextPressed(BuildContext context) async {
|
|
|
|
|
Utils.showLoading(context);
|
|
|
|
|
|
|
|
|
|
List<String> serviceItemIdsForHome = [];
|
|
|
|
|
List<String> serviceItemIdsForWorkshop = [];
|
|
|
|
|
for (var serviceItem in allSelectedItemsInAppointments) {
|
|
|
|
|
if (serviceItem.isHomeSelected!) {
|
|
|
|
|
serviceItemIdsForHome.add(serviceItem.id!.toString());
|
|
|
|
|
} else {
|
|
|
|
|
serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
serviceAppointmentScheduleList =
|
|
|
|
|
await scheduleRepo.mergeServiceIntoAvailableSchedules(
|
|
|
|
|
serviceItemIdsForHome: serviceItemIdsForHome,
|
|
|
|
|
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (serviceAppointmentScheduleList.isEmpty) {
|
|
|
|
|
Utils.hideLoading(context);
|
|
|
|
|
Utils.showToast(
|
|
|
|
|
"There are no available appointments for selected Items.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
totalAmount = 0.0;
|
|
|
|
|
amountToPayForAppointment = 0.0;
|
|
|
|
|
for (var schedule in serviceAppointmentScheduleList) {
|
|
|
|
|
amountToPayForAppointment =
|
|
|
|
|
amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
|
|
|
|
|
totalAmount = totalAmount + (schedule.amountTotal ?? 0.0);
|
|
|
|
|
}
|
|
|
|
|
Utils.hideLoading(context);
|
|
|
|
|
|
|
|
|
|
navigateWithName(context, AppRoutes.bookAppointmenSchedulesView,
|
|
|
|
|
arguments: ScreenArgumentsForAppointmentDetailPage(
|
|
|
|
|
routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment
|
|
|
|
|
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> onRescheduleAppointmentPressed({required BuildContext context,
|
|
|
|
|
required AppointmentListModel appointmentListModel}) async {
|
|
|
|
|
Utils.showLoading(context);
|
|
|
|
|
|
|
|
|
|
List<String> serviceItemIdsForHome = [];
|
|
|
|
|
List<String> serviceItemIdsForWorkshop = [];
|
|
|
|
|
for (var service in appointmentListModel.appointmentServicesList!) {
|
|
|
|
|
for (var serviceItem in service.serviceItems!) {
|
|
|
|
|
serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
|
|
|
|
|
|
|
|
|
|
// if (serviceItem.isHomeSelected ?? false) {
|
|
|
|
|
// serviceItemIdsForHome.add(serviceItem.id!.toString());
|
|
|
|
|
// } else {
|
|
|
|
|
// serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
serviceAppointmentScheduleList =
|
|
|
|
|
await scheduleRepo.mergeServiceIntoAvailableSchedules(
|
|
|
|
|
serviceItemIdsForHome: serviceItemIdsForHome,
|
|
|
|
|
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (serviceAppointmentScheduleList.isEmpty) {
|
|
|
|
|
Utils.hideLoading(context);
|
|
|
|
|
Utils.showToast(
|
|
|
|
|
"There are no available appointments for selected Items.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Utils.hideLoading(context);
|
|
|
|
|
|
|
|
|
|
navigateWithName(
|
|
|
|
|
context,
|
|
|
|
|
AppRoutes.bookAppointmenSchedulesView,
|
|
|
|
|
arguments: ScreenArgumentsForAppointmentDetailPage(
|
|
|
|
|
routeFlag: 2, appointmentId: appointmentListModel.id ?? 0),
|
|
|
|
|
); // 2 For Rescheduling an Appointment
|
|
|
|
|
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> onRescheduleAppointmentConfirmPressed(
|
|
|
|
|
{required BuildContext context,
|
|
|
|
|
required int appointmentId,
|
|
|
|
|
required int selectedSlotId}) async {
|
|
|
|
|
Utils.showLoading(context);
|
|
|
|
|
try {
|
|
|
|
|
GenericRespModel genericRespModel =
|
|
|
|
|
await scheduleRepo.cancelOrRescheduleServiceAppointment(
|
|
|
|
|
serviceAppointmentID: appointmentId,
|
|
|
|
|
serviceSlotID: selectedSlotId,
|
|
|
|
|
appointmentScheduleAction: 1, // 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<DashboardVmCustomer>().onNavbarTapped(1);
|
|
|
|
|
applyFilterOnAppointmentsVM(
|
|
|
|
|
appointmentStatusEnum: AppointmentStatusEnum.cancelled);
|
|
|
|
|
Utils.showToast("${genericRespModel.message.toString()}");
|
|
|
|
|
getMyAppointments();
|
|
|
|
|
Utils.hideLoading(context);
|
|
|
|
|
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Utils.showToast("${e.toString()}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|