import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:maps_launcher/maps_launcher.dart'; import 'package:provider/provider.dart'; import '../../core/dependencies.dart'; import '../medical_file/widgets/medical_file_card.dart'; class AppointmentDetailsPage extends StatefulWidget { AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel}); PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; @override State createState() => _AppointmentDetailsPageState(); } class _AppointmentDetailsPageState extends State { late MyAppointmentsViewModel myAppointmentsViewModel; late PrescriptionsViewModel prescriptionsViewModel; late BookAppointmentsViewModel bookAppointmentsViewModel; @override void initState() { scheduleMicrotask(() { if (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) { prescriptionsViewModel.setPrescriptionsDetailsLoading(); prescriptionsViewModel.getPrescriptionDetails(getPrescriptionRequestModel()); } }); super.initState(); } @override Widget build(BuildContext context) { AppState appState = getIt.get(); myAppointmentsViewModel = Provider.of(context, listen: false); prescriptionsViewModel = Provider.of(context, listen: false); bookAppointmentsViewModel = Provider.of(context, listen: false); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Column( children: [ Expanded( child: CollapsingListView( title: "Appointment Details".needTranslation, report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? () {} : null, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AppointmentDoctorCard( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onAskDoctorTap: () {}, onCancelTap: () async { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); showCommonBottomSheet(context, child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false); await myAppointmentsViewModel.cancelAppointment( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onSuccess: (apiResponse) { Navigator.of(context).pop(); showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: "Appointment Cancelled Successfully".needTranslation), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false, isSuccessDialog: true); }); Navigator.of(context).pop(); Navigator.of(context).pop(); }, onRescheduleTap: () async { openDoctorScheduleCalendar(); }, ), SizedBox(height: 16.h), !AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? Column( children: [ Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, ), child: Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ "Appointment Status".needTranslation.toText16(isBold: true), ], ), SizedBox(height: 4.h), (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) ? "Not Confirmed".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500) : "Confirmed".needTranslation.toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)), SizedBox(height: 16.h), //TODO Add countdown timer in case of LiveCare Appointment widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false ? Row( children: [ Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 40.h, height: 40.h), SizedBox(width: 12.h), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "The doctor will call you once the appointment time approaches." .needTranslation .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), ], ) : Stack( children: [ ClipRRect( clipBehavior: Clip.hardEdge, borderRadius: BorderRadius.circular(24), child: Image.network( "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng", fit: BoxFit.contain, ), ), Positioned( bottom: 0, child: SizedBox( width: MediaQuery.of(context).size.width * 0.785, child: CustomButton( text: "Get Directions".needTranslation, onPressed: () { MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName); }, backgroundColor: AppColors.textColor.withOpacity(0.8), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01), textColor: AppColors.whiteColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12.h, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, icon: AppAssets.directions_icon, iconColor: AppColors.whiteColor, iconSize: 13.h, ).paddingAll(12.h), ), ), ], ), ], ), ), ), SizedBox(height: 16.h), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, ), child: Row( mainAxisSize: MainAxisSize.max, children: [ Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h), SizedBox(width: 8.h), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), "Notify me before the appointment".needTranslation.toText11(color: AppColors.textColorLight, weight: FontWeight.w500), ], ), const Spacer(), Switch( activeColor: AppColors.successColor, activeTrackColor: AppColors.successColor.withValues(alpha: .15), value: widget.patientAppointmentHistoryResponseModel.hasReminder!, onChanged: (newValue) { setState(() { myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel); }); }, ), ], ).paddingSymmetrical(16.h, 16.h), ), SizedBox(height: 16.h), ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "Lab & Radiology".needTranslation.toText18(isBold: true), SizedBox(height: 16.h), GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13.h, mainAxisSpacing: 13.h, childAspectRatio: 7 / 6), physics: NeverScrollableScrollPhysics(), shrinkWrap: true, children: [ MedicalFileCard( label: LocaleKeys.labResults.tr(context: context), textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.lab_result_icon, iconSize: 40, isLargeText: true, ), MedicalFileCard( label: LocaleKeys.radiology.tr(context: context), textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.radiology_icon, iconSize: 40, isLargeText: true, ), ], ), LocaleKeys.prescriptions.tr().toText18(isBold: true), SizedBox(height: 16.h), Consumer(builder: (context, prescriptionVM, child) { return prescriptionVM.isPrescriptionsDetailsLoading ? const MoviesShimmerWidget() : Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: Colors.white, borderRadius: 20.h, ), child: Padding( padding: EdgeInsets.all(16.h), child: Column( children: [ ListView.separated( itemCount: prescriptionVM.prescriptionDetailsList.length, shrinkWrap: true, padding: const EdgeInsets.only(left: 0, right: 8), physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 500), child: SlideAnimation( verticalOffset: 100.0, child: FadeInAnimation( child: Row( children: [ Utils.buildSvgWithAssets( icon: AppAssets.prescription_item_icon, width: 40.h, height: 40.h, ), SizedBox(width: 8.h), Row( mainAxisSize: MainAxisSize.max, children: [ Column( children: [ SizedBox(width: 150.h, child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText12(isBold: true, maxLine: 1)), SizedBox( width: 150.h, child: "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}" .needTranslation .toText10(weight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: -0.4), ), ], ), SizedBox(width: 68.h), Transform.flip( flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets( icon: AppAssets.forward_arrow_icon, iconColor: AppColors.blackColor, width: 18.h, height: 13.h, fit: BoxFit.contain, ), ), ], ), ], ), ), ), ); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h), ).onPress(() { prescriptionVM.setPrescriptionsDetailsLoading(); Navigator.of(context).push( CustomPageRoute( page: PrescriptionDetailPage(prescriptionsResponseModel: getPrescriptionRequestModel()), ), ); }), SizedBox(height: 16.h), const Divider(color: AppColors.dividerColor), SizedBox(height: 16.h), Row( children: [ // Expanded( // child: CustomButton( // text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context), // onPressed: () {}, // backgroundColor: AppColors.secondaryLightRedColor, // borderColor: AppColors.secondaryLightRedColor, // textColor: AppColors.primaryRedColor, // fontSize: 14, // fontWeight: FontWeight.w500, // borderRadius: 12.h, // height: 40.h, // icon: AppAssets.appointment_calendar_icon, // iconColor: AppColors.primaryRedColor, // iconSize: 16.h, // ), // ), // SizedBox(width: 16.h), Expanded( child: CustomButton( text: "All Prescriptions".needTranslation, onPressed: () { Navigator.of(context) .push( CustomPageRoute( page: PrescriptionsListPage(), ), ) .then((val) { prescriptionsViewModel.setPrescriptionsDetailsLoading(); prescriptionsViewModel.getPrescriptionDetails(getPrescriptionRequestModel()); }); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14, fontWeight: FontWeight.w500, borderRadius: 12.h, height: 40.h, icon: AppAssets.requests, iconColor: AppColors.primaryRedColor, iconSize: 16.h, ), ), ], ), ], ), ), ); }), ], ), ], ).paddingSymmetrical(24.h, 24.h), ), ), ), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true, ), child: SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ "Amount before tax".needTranslation.toText18(isBold: true), Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13, isSaudiCurrency: true), ], ), SizedBox(height: 4.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)), "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -2), ], ), SizedBox(height: 18.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SizedBox( width: 150.h, child: Utils.getPaymentMethods(), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17, isSaudiCurrency: true), ], ), ], ) ], ).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h), AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? CustomButton( text: "Re-book Appointment".needTranslation, onPressed: () { openDoctorScheduleCalendar(); }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, fontSize: 16, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 50.h, icon: AppAssets.add_icon, iconColor: AppColors.whiteColor, iconSize: 18.h, ).paddingSymmetrical(16.h, 24.h) : CustomButton( text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), onPressed: () { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction); }, backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01), textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : AppColors.whiteColor, fontSize: 16, fontWeight: FontWeight.w500, borderRadius: 12, padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 50.h, icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction), iconColor: AppColors.whiteColor, iconSize: 18.h, ).paddingSymmetrical(16.h, 24.h), ], ), ), ), ], ), ); } openDoctorScheduleCalendar() async { DoctorsListResponseModel doctor = DoctorsListResponseModel( clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, projectID: widget.patientAppointmentHistoryResponseModel.projectID, doctorID: widget.patientAppointmentHistoryResponseModel.doctorID, doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL, doctorTitle: widget.patientAppointmentHistoryResponseModel.doctorTitle, name: widget.patientAppointmentHistoryResponseModel.doctorNameObj, nationalityFlagURL: "https://hmgwebservices.com/Images/flag/SYR.png", speciality: [], clinicName: widget.patientAppointmentHistoryResponseModel.clinicName, projectName: widget.patientAppointmentHistoryResponseModel.projectName, ); bookAppointmentsViewModel.setSelectedDoctor(doctor); LoaderBottomSheet.showLoader(); await bookAppointmentsViewModel.getDoctorFreeSlots( isBookingForLiveCare: false, onSuccess: (dynamic respData) async { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( title: "Pick a Date".needTranslation, context, child: AppointmentCalendar(), isFullScreen: false, isCloseButtonVisible: true, callBackFunc: () {}, ); }, onError: (err) { LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, child: Utils.getErrorWidget(loadingText: err), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true, ); }); } Future handleAppointmentNextAction(nextAction) async { switch (nextAction) { case 0: break; case 10: showCommonBottomSheet(context, child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false); await myAppointmentsViewModel.confirmAppointment( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, onSuccess: (apiResponse) { Navigator.of(context).pop(); showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: "Appointment Confirmed Successfully".needTranslation), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false, isSuccessDialog: true); }); Navigator.of(context).pop(); Navigator.of(context).pop(); case 15: break; case 20: myAppointmentsViewModel.setIsPatientAppointmentShareLoading(true); Navigator.of(context).push( CustomPageRoute( page: AppointmentPaymentPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), ), ); case 50: // return LocaleKeys.confirmLiveCare.tr(); case 90: showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.onlineCheckIn.tr(), child: AppointmentCheckinBottomSheet( patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, myAppointmentsViewModel: myAppointmentsViewModel, ), callBackFunc: () {}, isFullScreen: false); default: // return "No Action".needTranslation; } } PatientPrescriptionsResponseModel getPrescriptionRequestModel() { return PatientPrescriptionsResponseModel( appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo, setupID: widget.patientAppointmentHistoryResponseModel.setupID, episodeID: widget.patientAppointmentHistoryResponseModel.episodeID, clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, projectID: widget.patientAppointmentHistoryResponseModel.projectID, dischargeNo: 0, isInOutPatient: widget.patientAppointmentHistoryResponseModel.isInOutPatient, isHomeMedicineDeliverySupported: false, doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL, doctorName: "${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}", appointmentDate: widget.patientAppointmentHistoryResponseModel.appointmentDate, clinicDescription: widget.patientAppointmentHistoryResponseModel.clinicName, decimalDoctorRate: widget.patientAppointmentHistoryResponseModel.decimalDoctorRate, name: widget.patientAppointmentHistoryResponseModel.projectName, ); } }