diff --git a/assets/images/png/female_bmi.png b/assets/images/png/female_bmi.png new file mode 100644 index 00000000..437f1dc1 Binary files /dev/null and b/assets/images/png/female_bmi.png differ diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index e2e96449..5df2dcbd 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -83,6 +83,8 @@ "bookSuccessConfirmMore2412": "ستكون عملية الدفع عبر الإنترنت متاحة قبل 24 ساعة ��ن الموعد.", "upcomingPaymentPending": "سيتم تفعيل الدفع عبر الإنترنت قبل 24 ساعة من موعد الموعد", "upcomingPaymentNow": "ادفع عبر الإنترنت الآن لتجنب الانتظار الطويل", + "timeUntilAppointment": "الوقت المتبقي حتى الموعد", + "appointmentTimePassed": "انتهى وقت الموعد", "upcomingQR": "استخدم رمز الاستجابة السريعة لتسجيل الوصول في المستشفى", "upcomingVirtual": "هذا موعد افتراضي، يرجى الالتزام بالتعليمات لتجربة سلسة.", "upcomingLivecare": "هذا موعد لايف كير", @@ -307,6 +309,7 @@ "vitalSignObese": "بدين", "vitalSignOverweight": "زيادة الوزن", "vitalSignUnderweight": "نقص الوزن", + "vitalSignSkinny": "نحيف جداً", "myMedical": "نشط", "myMedicalSubtitle": "الأدوية", "myDoctor": "أطبائي", @@ -1462,6 +1465,8 @@ "setTimerOfReminder": "ضبط مؤقت التذكير", "youHaveAppointmentWithDr": "لديك موعد مع د. ", "hours": "ساعات", + "minutes": "دقائق", + "seconds": "ثواني", "secs": "ثواني", "noAllergiesDataFound": "لم يتم العثور على بيانات الحساسية...", "heartRateDescription": "معدل ضربات قلبك يشير إلى عدد المرات التي ينبض فيها قلبك في الدقيقة", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 0f108ade..ca64e0a9 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -306,6 +306,7 @@ "vitalSignObese": "Obese", "vitalSignOverweight": "Overweight", "vitalSignUnderweight": "Underweight", + "vitalSignSkinny": "Underweight", "myMedical": "Active", "myMedicalSubtitle": "Medications", "myDoctor": "My Doctors", @@ -1453,6 +1454,8 @@ "setTimerOfReminder": "Set the timer of reminder", "youHaveAppointmentWithDr": "You have appointment with Dr. ", "hours": "Hours", + "minutes": "Minutes", + "seconds": "Seconds", "secs": "Secs", "noAllergiesDataFound": "No allergies data found...", "heartRateDescription": "Your heart rate indicates how many times your heart beats per minute", diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index dd4861e1..743505b9 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -400,6 +400,7 @@ class AppAssets { static const String fullBodyFrontFemale = '$pngBasePath/full_body_front_female.png'; static const String fullBodyBackFemale = '$pngBasePath/full_body_back_female.png'; static const String bmiFullBody = '$pngBasePath/bmi_image_1.png'; + static const String bmiFullBodyFemale = '$pngBasePath/female_bmi.png'; static const String defaultMEP = '$pngBasePath/default_MEP.png'; diff --git a/lib/features/emergency_services/emergency_services_repo.dart b/lib/features/emergency_services/emergency_services_repo.dart index 10c5541a..582c4a58 100644 --- a/lib/features/emergency_services/emergency_services_repo.dart +++ b/lib/features/emergency_services/emergency_services_repo.dart @@ -183,7 +183,7 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo { @override Future>>> getProjectList() async { - Map request = {'IsOnlineCheckIn': true, 'IsAdvancePayment': false, 'IsForER': true}; + Map request = {"IsEROnlineCheckIn":true,'IsOnlineCheckIn': false, 'IsAdvancePayment': false, 'IsForER': true}; try { GenericApiModel>? apiResponse; diff --git a/lib/features/hmg_services/models/ui_models/vital_sign_ui_model.dart b/lib/features/hmg_services/models/ui_models/vital_sign_ui_model.dart index ea0782bd..6fb24066 100644 --- a/lib/features/hmg_services/models/ui_models/vital_sign_ui_model.dart +++ b/lib/features/hmg_services/models/ui_models/vital_sign_ui_model.dart @@ -11,6 +11,7 @@ enum VitalSignStatus { obese, overweight, underweight, + skinny, } /// UI-only helper model for Vital Sign cards. @@ -34,8 +35,9 @@ class VitalSignUiModel { /// /// Rules: /// - Height is always blue. - /// - High, Obese, Overweight => red scheme. - /// - Low, Underweight => yellow scheme. + /// - High, Obese => red scheme. + /// - Overweight => orange scheme. + /// - Low, Underweight, Skinny => yellow scheme. /// - Otherwise => green scheme (Normal). static VitalSignUiModel scheme({required VitalSignStatus? status, required String label}) { final l = label.toLowerCase(); @@ -50,10 +52,8 @@ class VitalSignUiModel { ); } - // High, Obese, Overweight => red scheme (health concerns) - if (status == VitalSignStatus.high || - status == VitalSignStatus.obese || - status == VitalSignStatus.overweight) { + // High, Obese => red scheme (health concerns) + if (status == VitalSignStatus.high || status == VitalSignStatus.obese) { return VitalSignUiModel( iconBg: AppColors.chipSecondaryLightRedColor, iconFg: AppColors.primaryRedColor, @@ -62,8 +62,20 @@ class VitalSignUiModel { ); } - // Low, Underweight => yellow scheme (warning) - if (status == VitalSignStatus.low || status == VitalSignStatus.underweight) { + // Overweight => orange scheme (warning) + if (status == VitalSignStatus.overweight) { + return VitalSignUiModel( + iconBg: AppColors.warningColorYellow.withValues(alpha: 0.12), + iconFg: AppColors.warningColorYellow, + chipBg: AppColors.warningColorYellow.withValues(alpha: 0.12), + chipFg: AppColors.warningColorYellow, + ); + } + + // Low, Underweight, Skinny => yellow scheme (warning) + if (status == VitalSignStatus.low || + status == VitalSignStatus.underweight || + status == VitalSignStatus.skinny) { final Color yellowBg = AppColors.highAndLow.withValues(alpha: 0.12); return VitalSignUiModel( iconBg: yellowBg, @@ -98,6 +110,8 @@ class VitalSignUiModel { return LocaleKeys.vitalSignOverweight.tr(); case VitalSignStatus.underweight: return LocaleKeys.vitalSignUnderweight.tr(); + case VitalSignStatus.skinny: + return LocaleKeys.vitalSignSkinny.tr(); } } @@ -131,22 +145,30 @@ class VitalSignUiModel { return null; } - // BMI >= 25 (Overweight or Obese) => High - if (bmiResult >= 25) { - return VitalSignStatus.high; + // BMI >= 30 (Obese) => Red + if (bmiResult >= 30) { + return VitalSignStatus.obese; + } + // BMI >= 25 (Overweight) => Orange + else if (bmiResult >= 25) { + return VitalSignStatus.overweight; } - // BMI >= 18.5 and < 25 => Normal + // BMI >= 18.5 (Normal) => Green else if (bmiResult >= 18.5) { return VitalSignStatus.normal; } - // BMI < 18.5 (Underweight) => Low + // BMI >= 16 (Underweight) => Yellow + else if (bmiResult >= 16) { + return VitalSignStatus.underweight; + } + // BMI < 16 (Skinny/Severely underweight) => Yellow else { - return VitalSignStatus.low; + return VitalSignStatus.skinny; } } /// Weight status based on BMI with detailed classification - /// Returns: Obese, Overweight, Normal, Underweight + /// Returns: Obese, Overweight, Normal, Underweight, Skinny static VitalSignStatus? weightStatus(dynamic bmi) { // Return null if BMI is not available or is 0 final double bmiResult = double.tryParse(bmi.toString()) ?? 0; @@ -155,15 +177,26 @@ class VitalSignUiModel { return null; } + // BMI >= 30 (Obese) => Red if (bmiResult >= 30) { return VitalSignStatus.obese; - } else if (bmiResult >= 25) { + } + // BMI >= 25 (Overweight) => Orange + else if (bmiResult >= 25) { return VitalSignStatus.overweight; - } else if (bmiResult >= 18.5) { + } + // BMI >= 18.5 (Normal) => Green + else if (bmiResult >= 18.5) { return VitalSignStatus.normal; - } else { + } + // BMI >= 16 (Underweight) => Yellow + else if (bmiResult >= 16) { return VitalSignStatus.underweight; } + // BMI < 16 (Skinny/Severely underweight) => Yellow + else { + return VitalSignStatus.skinny; + } } } diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index 28210d39..621ebe4c 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -191,6 +191,7 @@ class InsuranceViewModel extends ChangeNotifier { notifyListeners(); }, (apiResponse) { + patientInsuranceApprovalsList =[]; if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { diff --git a/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart b/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart index cea2e64b..420c0482 100644 --- a/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart +++ b/lib/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart @@ -75,6 +75,7 @@ class PatientAppointmentHistoryResponseModel { num? patientShareWithTax; num? patientTaxAmount; String? doctorNationalityFlagURL; + bool? isClinicReBookingAllowed; PatientAppointmentHistoryResponseModel({ this.setupID, @@ -152,6 +153,7 @@ class PatientAppointmentHistoryResponseModel { this.patientShareWithTax, this.patientTaxAmount, this.doctorNationalityFlagURL, + this.isClinicReBookingAllowed, }); PatientAppointmentHistoryResponseModel.fromJson(Map json) { @@ -241,6 +243,7 @@ class PatientAppointmentHistoryResponseModel { patientShareWithTax = json['PatientShareWithTax']; patientTaxAmount = json['PatientTaxAmount']; doctorNationalityFlagURL = json['DoctorNationalityFlagURL']; + isClinicReBookingAllowed = json['IsClinicReBookingAllowed']; } Map toJson() { @@ -313,6 +316,7 @@ class PatientAppointmentHistoryResponseModel { data['RemaniningHoursTocanPay'] = this.remaniningHoursTocanPay; data['SMSButtonVisable'] = this.sMSButtonVisable; data['ServiceID'] = this.serviceID; + data['IsClinicReBookingAllowed'] = this.isClinicReBookingAllowed; return data; } } diff --git a/lib/features/my_invoices/my_invoices_view_model.dart b/lib/features/my_invoices/my_invoices_view_model.dart index cd18026c..631efd5b 100644 --- a/lib/features/my_invoices/my_invoices_view_model.dart +++ b/lib/features/my_invoices/my_invoices_view_model.dart @@ -52,6 +52,8 @@ class MyInvoicesViewModel extends ChangeNotifier { notifyListeners(); }, (apiResponse) { + _originalInvoicesList =[]; + allInvoicesList =[]; if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 17950a46..7722c8d8 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -322,6 +322,7 @@ class CodegenLoader extends AssetLoader{ "vitalSignObese": "بدين", "vitalSignOverweight": "زيادة الوزن", "vitalSignUnderweight": "نقص الوزن", + "vitalSignSkinny": "نحيف جداً", "myMedical": "نشط", "myMedicalSubtitle": "الأدوية", "myDoctor": "أطبائي", @@ -1465,6 +1466,8 @@ class CodegenLoader extends AssetLoader{ "setTimerOfReminder": "ضبط مؤقت التذكير", "youHaveAppointmentWithDr": "لديك موعد مع د. ", "hours": "ساعات", + "minutes": "دقائق", + "seconds": "ثواني", "secs": "ثواني", "noAllergiesDataFound": "لم يتم العثور على بيانات الحساسية...", "heartRateDescription": "معدل ضربات قلبك يشير إلى عدد المرات التي ينبض فيها قلبك في الدقيقة", @@ -2034,6 +2037,7 @@ static const Map _en_US = { "vitalSignObese": "Obese", "vitalSignOverweight": "Overweight", "vitalSignUnderweight": "Underweight", + "vitalSignSkinny": "Underweight", "myMedical": "Active", "myMedicalSubtitle": "Medications", "myDoctor": "My Doctors", @@ -3174,6 +3178,8 @@ static const Map _en_US = { "setTimerOfReminder": "Set the timer of reminder", "youHaveAppointmentWithDr": "You have appointment with Dr. ", "hours": "Hours", + "minutes": "Minutes", + "seconds": "Seconds", "secs": "Secs", "noAllergiesDataFound": "No allergies data found...", "heartRateDescription": "Your heart rate indicates how many times your heart beats per minute", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index fbe9bef9..64577cbb 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -87,6 +87,8 @@ abstract class LocaleKeys { static const bookSuccessConfirmMore2412 = 'bookSuccessConfirmMore2412'; static const upcomingPaymentPending = 'upcomingPaymentPending'; static const upcomingPaymentNow = 'upcomingPaymentNow'; + static const timeUntilAppointment = 'timeUntilAppointment'; + static const appointmentTimePassed = 'appointmentTimePassed'; static const upcomingQR = 'upcomingQR'; static const upcomingVirtual = 'upcomingVirtual'; static const upcomingLivecare = 'upcomingLivecare'; @@ -308,6 +310,7 @@ abstract class LocaleKeys { static const vitalSignObese = 'vitalSignObese'; static const vitalSignOverweight = 'vitalSignOverweight'; static const vitalSignUnderweight = 'vitalSignUnderweight'; + static const vitalSignSkinny = 'vitalSignSkinny'; static const myMedical = 'myMedical'; static const myMedicalSubtitle = 'myMedicalSubtitle'; static const myDoctor = 'myDoctor'; @@ -1457,6 +1460,8 @@ abstract class LocaleKeys { static const setTimerOfReminder = 'setTimerOfReminder'; static const youHaveAppointmentWithDr = 'youHaveAppointmentWithDr'; static const hours = 'hours'; + static const minutes = 'minutes'; + static const seconds = 'seconds'; static const secs = 'secs'; static const noAllergiesDataFound = 'noAllergiesDataFound'; static const heartRateDescription = 'heartRateDescription'; diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index ef3b0c94..5344fead 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -74,6 +74,12 @@ class _AppointmentDetailsPageState extends State { bool isAppointmentWithin4Hours = false; + // Countdown timer variables + Timer? _countdownTimer; + Duration? _timeRemaining; + String _countdownText = ""; + Function(void Function())? _modalSetState; // Callback for modal state updates + @override void initState() { scheduleMicrotask(() async { @@ -92,9 +98,114 @@ class _AppointmentDetailsPageState extends State { } } }); + + // Initialize countdown timer for payment + if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || + widget.patientAppointmentHistoryResponseModel.nextAction == 20) { + _startCountdownTimer(); + } + super.initState(); } + void _startCountdownTimer() { + final appointmentDate = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate); + _updateTimeRemaining(); + + _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (mounted) { + _updateTimeRemaining(); + } else { + timer.cancel(); + } + }); + } + + void _updateTimeRemaining() { + final appointmentDate = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate); + final now = DateTime.now(); + final difference = appointmentDate.difference(now); + + if (difference.isNegative) { + if (mounted) { + setState(() { + _timeRemaining = Duration.zero; + _countdownText = LocaleKeys.appointmentTimePassed.tr(context: context); + }); + } + // Also update modal if callback is available + _modalSetState?.call(() { + _timeRemaining = Duration.zero; + _countdownText = LocaleKeys.appointmentTimePassed.tr(context: context); + }); + _countdownTimer?.cancel(); + } else { + if (mounted) { + setState(() { + _timeRemaining = difference; + _countdownText = _formatDuration(difference); + }); + } + // Also update modal if callback is available + _modalSetState?.call(() { + _timeRemaining = difference; + _countdownText = _formatDuration(difference); + }); + } + } + + String _formatDuration(Duration duration) { + final days = duration.inDays; + final hours = duration.inHours.remainder(24); + final minutes = duration.inMinutes.remainder(60); + final seconds = duration.inSeconds.remainder(60); + + // Format: DD : HH : MM : SS + return '${days.toString().padLeft(2, '0')} : ${hours.toString().padLeft(2, '0')} : ${minutes.toString().padLeft(2, '0')} : ${seconds.toString().padLeft(2, '0')}'; + } + + @override + void dispose() { + _countdownTimer?.cancel(); + super.dispose(); + } + + // Helper method to build each time unit (number + label) + Widget _buildTimeUnit(String value, String label) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + alignment: Alignment.center, + child: value.toText32( + isBold: true, + color: AppColors.blackColor, + isEnglishOnly: true, + ), + ), + SizedBox(height: 4.h), + Container( + alignment: Alignment.center, + child: label.toText12( + color: AppColors.greyTextColor, + ), + ), + ], + ); + } + + // Helper method to build time separator (:) + Widget _buildTimeSeparator() { + return Padding( + padding: EdgeInsets.only(bottom: 16.h, left: 6.w, right: 6.w), + child: ':'.toText32( + isBold: true, + color: AppColors.blackColor, + ), + ); + } + @override Widget build(BuildContext context) { myAppointmentsViewModel = Provider.of(context, listen: false); @@ -934,6 +1045,7 @@ class _AppointmentDetailsPageState extends State { ? (!(widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) || widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! || widget.patientAppointmentHistoryResponseModel.isExecludeDoctor! || + widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false || !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)) ? SizedBox.shrink() : CustomButton( @@ -1126,14 +1238,86 @@ class _AppointmentDetailsPageState extends State { }); // LoaderBottomSheet.hideLoader(); case 15: - getIt.get().showCommonBottomSheetWithoutH( - message: LocaleKeys.upcomingPaymentPending.tr(context: context), - label: LocaleKeys.notice.tr(), - onOkPressed: () {}, - okLabel: "confirm", - cancelLabel: LocaleKeys.acknowledged.tr(context: context), - isConfirmButton: true, - ); + // Ensure timer is running before showing modal + if (_countdownTimer == null || !_countdownTimer!.isActive) { + _startCountdownTimer(); + } + + showCommonBottomSheetWithoutHeight( + context, + title: LocaleKeys.notice.tr(), + child: StatefulBuilder( + builder: (context, setModalState) { + // Store the modal setState callback + _modalSetState = setModalState; + + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Message text + LocaleKeys.upcomingPaymentPending.tr(context: context).toText14( + color: AppColors.textColor, + isCenter: true, + ), + SizedBox(height: 24.h), + // Countdown Timer - DD : HH : MM : SS format with labels + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Days + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00', + LocaleKeys.days.tr(context: context), + ), + _buildTimeSeparator(), + // Hours + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00', + LocaleKeys.hours.tr(context: context), + ), + _buildTimeSeparator(), + // Minutes + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00', + LocaleKeys.minutes.tr(context: context), + ), + _buildTimeSeparator(), + // Seconds + _buildTimeUnit( + _timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00', + LocaleKeys.seconds.tr(context: context), + ), + ], + ), + SizedBox(height: 24.h), + // Green Acknowledge button with checkmark icon + CustomButton( + text: LocaleKeys.acknowledged.tr(context: context), + onPressed: () { + _modalSetState = null; // Clear callback when closing + Navigator.of(context).pop(); + }, + backgroundColor: AppColors.successColor, + borderColor: AppColors.successColor, + textColor: Colors.white, + fontSize: 16.f, + fontWeight: FontWeight.w600, + borderRadius: 12.r, + height: 50.h, + icon: AppAssets.checkmark_icon, + iconColor: Colors.white, + ), + ], + ); + }, + ), + callBackFunc: () { + _modalSetState = null; // Clear callback when closing + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); case 20: myAppointmentsViewModel.setIsPatientAppointmentShareLoading(true); Navigator.of(context).push( diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index db08c923..d551c444 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -392,58 +392,62 @@ class AppointmentCard extends StatelessWidget { } } return (patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) - ? Row( - children: [ - Expanded( - flex: 6, - child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel) - ? _getArrivedButton(context) - : CustomButton( - text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction), - onPressed: () => _goToDetails(context), - backgroundColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15), - borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), - textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), - fontSize: (isFoldable || isTablet) ? 12.f : 14.f, - fontWeight: FontWeight.w600, - borderRadius: 12.r, - padding: EdgeInsets.symmetric(horizontal: 10.w), - height: 40.h, - icon: AppointmentType.getNextActionIcon(patientAppointmentHistoryResponseModel.nextAction), - iconColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), - iconSize: 15.h, - )) - .toShimmer2(isShow: isLoading), - ), - SizedBox(width: 8.h), - Expanded( - flex: 1, - child: Container( - height: (isFoldable || isTablet) ? 50.h : 40.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.transparent, - borderRadius: 10.h, - side: BorderSide( - color: AppColors.textColor, - width: 1.2, - ), - ), - child: Transform.flip( - flipX: appState.isArabic(), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.textColor, - width: 24.w, - height: 24.h, - fit: BoxFit.contain, - ), - ), - ).toShimmer2(isShow: isLoading).onPress(() { - _goToDetails(context); - }), - ), - ], - ) + ? (AppointmentType.isArrived(patientAppointmentHistoryResponseModel) && + patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false) + ? // Show only View Details button without arrow when rebooking not allowed + _getArrivedButton(context) + : Row( + children: [ + Expanded( + flex: 6, + child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel) + ? _getArrivedButton(context) + : CustomButton( + text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction), + onPressed: () => _goToDetails(context), + backgroundColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15), + borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), + textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), + fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + fontWeight: FontWeight.w600, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: 40.h, + icon: AppointmentType.getNextActionIcon(patientAppointmentHistoryResponseModel.nextAction), + iconColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), + iconSize: 15.h, + )) + .toShimmer2(isShow: isLoading), + ), + SizedBox(width: 8.h), + Expanded( + flex: 1, + child: Container( + height: (isFoldable || isTablet) ? 50.h : 40.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.transparent, + borderRadius: 10.h, + side: BorderSide( + color: AppColors.textColor, + width: 1.2, + ), + ), + child: Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.textColor, + width: 24.w, + height: 24.h, + fit: BoxFit.contain, + ), + ), + ).toShimmer2(isShow: isLoading).onPress(() { + _goToDetails(context); + }), + ), + ], + ) : CustomButton( text: LocaleKeys.viewDetails.tr(context: context), onPressed: () { @@ -475,54 +479,22 @@ class AppointmentCard extends StatelessWidget { } Widget _getArrivedButton(BuildContext context) { - // final isRecent = DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15; - // - // if (isRecent) { - // return CustomButton( - // text: LocaleKeys.askDoctor.tr(context: context), - // onPressed: () async { - // LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); - // await myAppointmentsViewModel.isDoctorAvailable( - // projectID: patientAppointmentHistoryResponseModel.projectID, - // doctorId: patientAppointmentHistoryResponseModel.doctorID, - // clinicId: patientAppointmentHistoryResponseModel.clinicID, - // onSuccess: (value) async { - // if (value) { - // await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) { - // LoaderBottomSheet.hideLoader(); - // showCommonBottomSheetWithoutHeight( - // context, - // title: LocaleKeys.askDoctor.tr(context: context), - // child: AskDoctorRequestTypeSelect( - // askDoctorRequestTypeList: myAppointmentsViewModel.askDoctorRequestTypeList, - // myAppointmentsViewModel: myAppointmentsViewModel, - // patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, - // ), - // callBackFunc: () {}, - // isFullScreen: false, - // isCloseButtonVisible: true, - // ); - // }); - // } else { - // print("Doctor is not available"); - // } - // }); - // }, - // backgroundColor: AppColors.secondaryLightRedColor, - // borderColor: AppColors.secondaryLightRedColor, - // textColor: AppColors.primaryRedColor, - // fontSize: (isFoldable || isTablet) ? 12.f : 14.f, - // fontWeight: FontWeight.w600, - // borderRadius: 12.r, - // padding: EdgeInsets.symmetric(horizontal: 10.w), - // // height: isTablet || isFoldable ? 46.h : 40.h, - // height: 40.h, - // icon: AppAssets.ask_doctor_icon, - // iconColor: AppColors.primaryRedColor, - // iconSize: 16.h, - // ); - // } + if (patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false) { + return CustomButton( + text: LocaleKeys.viewDetails.tr(context: context), + onPressed: () => _goToDetails(context), + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: (isFoldable || isTablet) ? 12.f : 14.f, + fontWeight: FontWeight.w600, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: 40.h, + ); + } + // Show Rebook button return CustomButton( borderSide: BorderSide( color: AppColors.textColor, diff --git a/lib/presentation/symptoms_checker/triage_screen.dart b/lib/presentation/symptoms_checker/triage_screen.dart index da35a805..76fad545 100644 --- a/lib/presentation/symptoms_checker/triage_screen.dart +++ b/lib/presentation/symptoms_checker/triage_screen.dart @@ -80,7 +80,7 @@ class _TriagePageState extends State { } // Case 2: Should stop flag is true OR Case 3: Probability >= 70% OR Case 4: 7 or more questions answered - if (viewModel.shouldStopTriage || highestProbability >= 70.0 || viewModel.triageQuestionCount >= 7) { + if (viewModel.shouldStopTriage || highestProbability >= 70.0 || viewModel.triageQuestionCount >= 15) { // Navigate to results/possible conditions screen context.navigateWithName(AppRoutes.possibleConditionsPage); return; diff --git a/lib/presentation/vital_sign/vital_sign_page.dart b/lib/presentation/vital_sign/vital_sign_page.dart index f712aa77..fb3f1a58 100644 --- a/lib/presentation/vital_sign/vital_sign_page.dart +++ b/lib/presentation/vital_sign/vital_sign_page.dart @@ -236,7 +236,9 @@ class _VitalSignPageState extends State { fit: StackFit.expand, children: [ Image.asset( - AppAssets.bmiFullBody, + getIt.get().getAuthenticatedUser()?.gender == 1 + ? AppAssets.bmiFullBody + : AppAssets.bmiFullBodyFemale, fit: BoxFit.cover, alignment: Alignment.topCenter, ),