You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
17 KiB
Dart
376 lines
17 KiB
Dart
import 'dart:developer';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:mc_common_app/classes/consts.dart';
|
|
import 'package:mc_common_app/extensions/int_extensions.dart';
|
|
import 'package:mc_common_app/extensions/string_extensions.dart';
|
|
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
|
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
|
import 'package:mc_common_app/models/chat_models/chat_message_model.dart';
|
|
import 'package:mc_common_app/models/services_models/service_model.dart';
|
|
import 'package:mc_common_app/theme/colors.dart';
|
|
import 'package:mc_common_app/utils/date_helper.dart';
|
|
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.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/appointments_view_model.dart';
|
|
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
|
import 'package:mc_common_app/widgets/checkbox_with_title_desc.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/info_bottom_sheet.dart';
|
|
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
|
import 'package:mc_common_app/widgets/txt_field.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:sizer/sizer.dart';
|
|
|
|
class AppointmentDetailView extends StatelessWidget {
|
|
final AppointmentListModel appointmentListModel;
|
|
|
|
const AppointmentDetailView({super.key, required this.appointmentListModel});
|
|
|
|
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 getArrivedBottomActionButton({required BuildContext context, required AppointmentPaymentStatusEnum appointmentPaymentStatusEnum}) {
|
|
final appointmentVM = context.read<AppointmentsVM>();
|
|
switch (appointmentPaymentStatusEnum) {
|
|
case AppointmentPaymentStatusEnum.defaultStatus:
|
|
case AppointmentPaymentStatusEnum.paid:
|
|
case AppointmentPaymentStatusEnum.payLater:
|
|
case AppointmentPaymentStatusEnum.payPartial:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: SizedBox(
|
|
height: 8.h,
|
|
child: Utils.buildStatusContainer(LocaleKeys.workInProgress.tr()),
|
|
),
|
|
);
|
|
case AppointmentPaymentStatusEnum.payNow:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: Row(
|
|
children: [
|
|
getBaseActionButtonWidget(
|
|
color: MyColors.darkPrimaryColor,
|
|
textColor: MyColors.white,
|
|
onPressed: () {
|
|
if (appointmentListModel.remainingAmount != null && appointmentListModel.remainingAmount! > 0.0) {
|
|
appointmentVM.onPayNowPressedForAppointment(
|
|
context: context,
|
|
appointmentID: appointmentListModel.id ?? 0,
|
|
);
|
|
}
|
|
},
|
|
text: LocaleKeys.payNow.tr(),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context, required bool shouldShowConfirmButton}) {
|
|
switch (appointmentStatusEnum) {
|
|
case AppointmentStatusEnum.booked:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: Row(
|
|
children: [
|
|
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
|
|
if (shouldShowConfirmButton) ...[
|
|
12.width,
|
|
getBaseActionButtonWidget(
|
|
color: MyColors.greenColor,
|
|
onPressed: () {
|
|
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
|
|
},
|
|
text: LocaleKeys.confirm.tr()),
|
|
]
|
|
],
|
|
),
|
|
);
|
|
case AppointmentStatusEnum.confirmed:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: Row(
|
|
children: [
|
|
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
|
|
],
|
|
),
|
|
);
|
|
case AppointmentStatusEnum.visitCompleted:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: SizedBox(
|
|
height: 8.h,
|
|
child: Utils.buildStatusContainer(LocaleKeys.visitCompleted.tr()),
|
|
),
|
|
);
|
|
|
|
case AppointmentStatusEnum.arrived:
|
|
case AppointmentStatusEnum.workStarted:
|
|
return getArrivedBottomActionButton(appointmentPaymentStatusEnum: appointmentListModel.appointmentPaymentStatusEnum ?? AppointmentPaymentStatusEnum.defaultStatus, context: context);
|
|
case AppointmentStatusEnum.cancelled:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: SizedBox(
|
|
height: 8.h,
|
|
child: Utils.buildStatusContainer(LocaleKeys.appointmentCancelled.tr()),
|
|
),
|
|
);
|
|
case AppointmentStatusEnum.allAppointments:
|
|
return const SizedBox();
|
|
case AppointmentStatusEnum.rescheduled:
|
|
return Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: Row(
|
|
children: [
|
|
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => buildCancelAppointmentReasonsBottomSheet(context: context), text: LocaleKeys.cancel.tr()),
|
|
if (shouldShowConfirmButton) ...[
|
|
12.width,
|
|
getBaseActionButtonWidget(
|
|
color: MyColors.greenColor,
|
|
onPressed: () {
|
|
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
|
|
},
|
|
text: LocaleKeys.confirm.tr()),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
default:
|
|
return const SizedBox();
|
|
}
|
|
}
|
|
|
|
void appointmentCancelConfirmationSheet(BuildContext context) {
|
|
final appointmentsVm = context.read<AppointmentsVM>();
|
|
return actionConfirmationBottomSheet(
|
|
context: context,
|
|
title: LocaleKeys.youWantCancelAppointment.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
|
|
subtitle: LocaleKeys.appointmentCancelledCannotUndoAction.tr(),
|
|
actionButtonYes: Expanded(
|
|
child: ShowFillButton(
|
|
maxHeight: 55,
|
|
title: LocaleKeys.yes.tr(),
|
|
fontSize: 15,
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
|
|
},
|
|
),
|
|
),
|
|
actionButtonNo: Expanded(
|
|
child: ShowFillButton(
|
|
maxHeight: 55,
|
|
isFilled: false,
|
|
borderColor: MyColors.darkPrimaryColor,
|
|
title: LocaleKeys.no.tr(),
|
|
txtColor: MyColors.darkPrimaryColor,
|
|
fontSize: 15,
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future buildCancelAppointmentReasonsBottomSheet({required BuildContext context}) {
|
|
return showModalBottomSheet(
|
|
context: context,
|
|
isScrollControlled: true,
|
|
enableDrag: true,
|
|
builder: (BuildContext context) {
|
|
return Consumer(builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
|
return InfoBottomSheet(
|
|
title: LocaleKeys.pleaseSpecify.tr().toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
|
|
description: Padding(
|
|
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
12.height,
|
|
ListView.separated(
|
|
shrinkWrap: true,
|
|
itemCount: appointmentsVM.cancelAppointmentReasonList.length,
|
|
separatorBuilder: (BuildContext context, int index) {
|
|
return const Divider(thickness: 0.5);
|
|
},
|
|
itemBuilder: (BuildContext context, int index) {
|
|
OfferRequestCommentModel offerRequestCommentModel = appointmentsVM.cancelAppointmentReasonList[index];
|
|
return CircleCheckBoxWithTitle(
|
|
isChecked: offerRequestCommentModel.isSelected ?? false,
|
|
title: '${offerRequestCommentModel.title}',
|
|
onSelected: () {
|
|
appointmentsVM.updateSelectedCancelAppointmentReason(index);
|
|
},
|
|
selectedColor: MyColors.darkPrimaryColor,
|
|
);
|
|
},
|
|
),
|
|
if (appointmentsVM.selectedCancelAppointmentReason.index == appointmentsVM.cancelAppointmentReasonList.length - 1) ...[
|
|
// comparing if the "other" is selected
|
|
12.height,
|
|
TxtField(
|
|
maxLines: 5,
|
|
value: appointmentsVM.cancelAppointmentDescription,
|
|
errorValue: appointmentsVM.cancelAppointmentDescriptionError,
|
|
keyboardType: TextInputType.text,
|
|
hint: LocaleKeys.description.tr(),
|
|
onChanged: (v) => appointmentsVM.updateCancelAppointmentDescription(v),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
25.height,
|
|
ShowFillButton(
|
|
title: LocaleKeys.submit.tr(),
|
|
onPressed: () {
|
|
if (appointmentsVM.selectedCancelAppointmentReason.index == 0) {
|
|
appointmentsVM.onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
|
|
} else {
|
|
context.read<AppointmentsVM>().onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
|
|
}
|
|
},
|
|
maxWidth: double.infinity,
|
|
),
|
|
19.height,
|
|
],
|
|
),
|
|
));
|
|
});
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
|
|
bool shouldShowConfirmButton = false;
|
|
final currentDateTime = DateTime.now();
|
|
if ((appointmentListModel.isPaymentRequiredAtBooking ?? false) && appointmentListModel.appointmentDate != null && appointmentListModel.appointmentDate!.isNotEmpty) {
|
|
final DateTime appointmentDatetime = DateHelper.parseStringToDate(appointmentListModel.appointmentDate!);
|
|
shouldShowConfirmButton = (appointmentListModel.isPaymentRequiredAtBooking ?? false) && (appointmentDatetime.isAfter(currentDateTime));
|
|
}
|
|
return Scaffold(
|
|
appBar: CustomAppBar(
|
|
title: LocaleKeys.appointment.tr(),
|
|
profileImageUrl: MyAssets.bnCar,
|
|
isRemoveBackButton: false,
|
|
isDrawerEnabled: false,
|
|
),
|
|
body: Container(
|
|
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
|
child: Stack(
|
|
children: [
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
appointmentListModel.providerName!.toText(fontSize: 16, isBold: true),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
MyAssets.miniClockDark.buildSvg(
|
|
height: 12,
|
|
width: 12,
|
|
fit: BoxFit.fill,
|
|
),
|
|
5.width,
|
|
"${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor),
|
|
],
|
|
),
|
|
13.height,
|
|
if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[
|
|
Column(
|
|
children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
|
|
ServiceModel service = appointmentListModel.appointmentServicesList![index];
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
"${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true),
|
|
if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
|
|
Column(
|
|
children: List.generate(
|
|
service.serviceItems!.length,
|
|
(index) => "${service.serviceItems![index].name}".toText(
|
|
textAlign: TextAlign.start,
|
|
fontSize: 12,
|
|
color: MyColors.lightTextColor,
|
|
),
|
|
),
|
|
).paddingOnly(left: 15),
|
|
],
|
|
],
|
|
),
|
|
5.height,
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
((service.currentTotalServicePrice).toString()).toText(fontSize: 19, isBold: true),
|
|
2.width,
|
|
LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 12, isBold: true).paddingOnly(bottom: 5),
|
|
const Icon(Icons.arrow_drop_down, size: 25)
|
|
],
|
|
).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)),
|
|
],
|
|
).paddingOnly(bottom: 15);
|
|
}),
|
|
),
|
|
],
|
|
15.height,
|
|
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked || appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.confirmed) ...[
|
|
Row(
|
|
children: [
|
|
CardButtonWithIcon(
|
|
title: LocaleKeys.rescheduleAppointment.tr(),
|
|
onCardTapped: () {
|
|
context.read<AppointmentsVM>().onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
|
|
},
|
|
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
|
|
),
|
|
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked && (shouldShowConfirmButton)) ...[
|
|
10.width,
|
|
CardButtonWithIcon(
|
|
title: LocaleKeys.payforAppointment.tr(),
|
|
onCardTapped: () {
|
|
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
|
|
},
|
|
icon: MyAssets.creditCardIcon.buildSvg(),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
15.height,
|
|
],
|
|
],
|
|
).toWhiteContainer(width: double.infinity, allPading: 12),
|
|
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context, shouldShowConfirmButton: shouldShowConfirmButton),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|