From ec4fb7158600f67f856b7c3c02e5d326a2f68721 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 5 Nov 2026 17:23:00 +0300 Subject: [PATCH] My appointments workflow updates --- .../my_appointments/my_appointments_repo.dart | 40 +++++++++++++++++++ .../my_appointments_view_model.dart | 30 ++++++++++++++ .../utils/appointment_type.dart | 8 ++++ .../appointment_details_page.dart | 39 +++++++++--------- .../widgets/appointment_card.dart | 1 + 5 files changed, 99 insertions(+), 19 deletions(-) diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart index 3f30ee4b..c443ff48 100644 --- a/lib/features/my_appointments/my_appointments_repo.dart +++ b/lib/features/my_appointments/my_appointments_repo.dart @@ -100,6 +100,8 @@ abstract class MyAppointmentsRepo { Future>>> getAppointmentInvoice(num appointmentNum); Future>> getParkingQR(num appointmentNum, int projectID); + + Future>> getAppointmentDetailsByAppointmentNumber(int appointmentID, int projectID, int clinicID); } class MyAppointmentsRepoImp implements MyAppointmentsRepo { @@ -1238,4 +1240,42 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> getAppointmentDetailsByAppointmentNumber(int appointmentID, int projectID, int clinicID) async { + Map mapDevice = { + "AppointmentNo": appointmentID, + "ProjectID": projectID, + "ClinicID":clinicID, + "IsActiveAppointment": true, + }; + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post(GET_PATIENT_APPOINTMENT_HISTORY, onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final list = response['AppoimentAllHistoryResultList']; + + final appointmentDetails = PatientAppointmentHistoryResponseModel.fromJson(list[0]); + + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: appointmentDetails, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, body: mapDevice); + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + return Left(UnknownFailure(e.toString())); + } + } + } diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 3eb0e965..4b2a2550 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -113,6 +113,9 @@ class MyAppointmentsViewModel extends ChangeNotifier { Uint8List? parkingQRImageBytes; + late PatientAppointmentHistoryResponseModel currentSelectedAppointmentDetails; + bool isAppointmentDetailsLoading = false; + MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState}); void onTabChange(int index) { @@ -1761,4 +1764,31 @@ class MyAppointmentsViewModel extends ChangeNotifier { }, ); } + + updateAppointmentDetailsPage() { + notifyListeners(); + } + + Future getAppointmentDetailsByAppointmentNumber({required int projectID, required int appointmentNo, required int clinicId, Function(dynamic)? onSuccess, Function(String)? onError}) async { + isAppointmentDetailsLoading = true; + notifyListeners(); + + final result = await myAppointmentsRepo.getAppointmentDetailsByAppointmentNumber(appointmentNo, projectID, clinicId); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + onError!(apiResponse.errorMessage!); + } else if (apiResponse.messageStatus == 1) { + currentSelectedAppointmentDetails = apiResponse.data!; + isAppointmentDetailsLoading = false; + if (onSuccess != null) { + onSuccess(apiResponse.data); + } + } + }, + ); + } + } diff --git a/lib/features/my_appointments/utils/appointment_type.dart b/lib/features/my_appointments/utils/appointment_type.dart index 13811737..f04a6e26 100644 --- a/lib/features/my_appointments/utils/appointment_type.dart +++ b/lib/features/my_appointments/utils/appointment_type.dart @@ -57,6 +57,8 @@ class AppointmentType { return AppColors.successColor; case 90: return AppColors.alertColor; + case 110: + return AppColors.primaryRedColor; default: return AppColors.successColor; } @@ -76,6 +78,8 @@ class AppointmentType { return AppColors.successColor; case 90: return AppColors.alertColor; + case 110: + return AppColors.primaryRedColor; default: return AppColors.successColor; } @@ -95,6 +99,8 @@ class AppointmentType { return LocaleKeys.confirmLiveCare.tr(); case 90: return LocaleKeys.checkinOption.tr(); + case 110: + return LocaleKeys.viewDetails.tr(); default: return LocaleKeys.upcomingNoAction.tr(); } @@ -114,6 +120,8 @@ class AppointmentType { return AppAssets.confirm_appointment_icon; case 90: return AppAssets.appointment_checkin_icon; + case 110: + return AppAssets.calendar; default: return AppAssets.checkmark_icon; } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 947d3efe..b28a93b9 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -61,9 +61,9 @@ import 'package:provider/provider.dart'; import '../medical_file/widgets/medical_file_card.dart'; class AppointmentDetailsPage extends StatefulWidget { - const AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel}); + AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel}); - final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; + PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; @override State createState() => _AppointmentDetailsPageState(); @@ -103,6 +103,17 @@ class _AppointmentDetailsPageState extends State { projectID: widget.patientAppointmentHistoryResponseModel.projectID, appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo); } else { + if (widget.patientAppointmentHistoryResponseModel.nextAction == 110) { + myAppointmentsViewModel + .getAppointmentDetailsByAppointmentNumber( + projectID: widget.patientAppointmentHistoryResponseModel.projectID, + appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo, + clinicId: widget.patientAppointmentHistoryResponseModel.clinicID) + .then((val) { + widget.patientAppointmentHistoryResponseModel = myAppointmentsViewModel.currentSelectedAppointmentDetails; + myAppointmentsViewModel.updateAppointmentDetailsPage(); + }); + } Duration difference = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate).difference(DateTime.now()); if (difference.inMinutes > 240) { isAppointmentWithin4Hours = false; @@ -1043,8 +1054,7 @@ class _AppointmentDetailsPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || - widget.patientAppointmentHistoryResponseModel.nextAction == 20) + if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -1052,10 +1062,7 @@ class _AppointmentDetailsPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true), - Utils.getPaymentAmountWithSymbol( - widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), - AppColors.blackColor, - 13, + Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13, isSaudiCurrency: true), ], ), @@ -1063,10 +1070,8 @@ class _AppointmentDetailsPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)), - "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})" - .toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64), + Expanded(child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)), + "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64), ], ), SizedBox(height: 18.h), @@ -1077,10 +1082,7 @@ class _AppointmentDetailsPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Utils.getPaymentAmountWithSymbol( - widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true), - AppColors.blackColor, - 17, + Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17, isSaudiCurrency: true), ], ), @@ -1118,8 +1120,7 @@ class _AppointmentDetailsPageState extends State { handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction); }, backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction), - borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction) - .withValues(alpha: 0.01), + borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white, fontSize: 16.f, fontWeight: FontWeight.w600, @@ -1132,7 +1133,7 @@ class _AppointmentDetailsPageState extends State { ).paddingSymmetrical(16.h, 24.h), ], ), - ), + ).toShimmer2(isShow: myAppointmentsViewModel.isAppointmentDetailsLoading), ), ], ), diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index b9a2f26f..3a89ffc3 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -729,6 +729,7 @@ class _AppointmentCardState extends State { Future handleAppointmentNextAction(nextAction, BuildContext context) async { switch (nextAction) { case 0: + case 110: // No action needed _goToDetails(context); break;