From 2be65cba512dab89722ddda0fdc6945a80dfc834 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 11 Feb 2026 16:02:48 +0300 Subject: [PATCH] Inactive Insurance case handled --- assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 4 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- lib/core/api_consts.dart | 2 +- lib/core/utils/utils.dart | 6 +- .../insurance/insurance_view_model.dart | 12 +- lib/generated/locale_keys.g.dart | 2 + .../widgets/patient_insurance_card.dart | 74 ++++++++++-- .../medical_file/medical_file_page.dart | 59 ++++++++-- .../profile_settings/profile_settings.dart | 111 +++++++++--------- 10 files changed, 200 insertions(+), 80 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index ea335bf..eeabdca 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1572,5 +1572,7 @@ "noThanksIKnowTheClinic": "لا، شكراً. أنا أعرف العيادة.", "unableToSendOTP": "تعذر إرسال رمز التحقق لمرة واحدة", "loadingAIAnalysis": "جارٍ تحليل نتائج المختبر، يرجى التحلي بالصبر والسماح للذكاء الاصطناعي بالقيام بالمهمة، قد يستغرق هذا بعض الوقت.", - "symptoms": "أعراض" + "symptoms": "أعراض", + "insuranceInActive": "التأمين غير نشط", + "insuranceInActiveContactSupport": "لديك تأمين ساري المفعول، ولكنه غير مُفعّل حاليًا في مجموعة حبيب الطبية. يُرجى التواصل مع خدمة عملاء مجموعة حبيب الطبية." } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index ee924fa..4909504 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1563,5 +1563,7 @@ "calculatedValue": "Calculated Value", "calculationFormula": "Calculation Formula", "loadingAIAnalysis": "Analysing your lab results, Please be patient and let the AI do the magic, This might take some time.", - "symptoms": "Symptoms" + "symptoms": "Symptoms", + "insuranceInActive": "Insurance Inactive", + "insuranceInActiveContactSupport": "You have a valid insurance but it is currently inactive in HMG. Please contact HMG customer support to activate it." } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 886ad92..e031a97 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -523,7 +523,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -709,7 +709,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -738,7 +738,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 2ed5528..03e1f7e 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/enums.dart'; class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 60925bc..ee03259 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -408,6 +408,8 @@ class Utils { Widget? bodyWidget, Function? onConfirmTap, Function? onCancelTap, + String? cancelText, + String? confirmText, }) { return Column( mainAxisAlignment: MainAxisAlignment.center, @@ -425,7 +427,7 @@ class Utils { children: [ Expanded( child: CustomButton( - text: LocaleKeys.cancel.tr(), + text: cancelText ?? LocaleKeys.cancel.tr(), onPressed: () { if (onCancelTap != null) { onCancelTap(); @@ -441,7 +443,7 @@ class Utils { SizedBox(width: 8.h), Expanded( child: CustomButton( - text: LocaleKeys.confirm.tr(), + text: confirmText ?? LocaleKeys.confirm.tr(), onPressed: () async { if (onConfirmTap != null) { onConfirmTap(); diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index 261bda2..fffe58f 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -18,6 +18,7 @@ class InsuranceViewModel extends ChangeNotifier { bool isInsuranceApprovalsLoading = false; bool isInsuranceExpired = false; + bool isInsuranceActive = false; InsuranceRepo insuranceRepo; ErrorHandlerService errorHandlerService; @@ -31,11 +32,11 @@ class InsuranceViewModel extends ChangeNotifier { InsuranceViewModel({required this.insuranceRepo, required this.errorHandlerService}); initInsuranceProvider() { - if (isInsuranceDataToBeLoaded) { + // if (isInsuranceDataToBeLoaded) { patientInsuranceList.clear(); isInsuranceLoading = true; getPatientInsuranceDetails(); - } + // } patientInsuranceCardHistoryList.clear(); isInsuranceHistoryLoading = true; isInsuranceDetailsLoading = true; @@ -70,7 +71,7 @@ class InsuranceViewModel extends ChangeNotifier { } Future getPatientInsuranceDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async { - if (!isInsuranceDataToBeLoaded) return; + // if (!isInsuranceDataToBeLoaded) return; final result = await insuranceRepo.getPatientInsuranceDetails(); @@ -79,6 +80,8 @@ class InsuranceViewModel extends ChangeNotifier { (failure) async { isInsuranceLoading = false; isInsuranceDataToBeLoaded = false; + isInsuranceExpired = false; + isInsuranceActive = false; notifyListeners(); }, (apiResponse) { @@ -94,6 +97,9 @@ class InsuranceViewModel extends ChangeNotifier { DateUtil.convertStringToDate(patientInsuranceList.first.cardValidTo), ); + isInsuranceActive = patientInsuranceList.first.isActive ?? false; + // isInsuranceActive = true; + notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 3256b3d..ac4ad58 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1564,5 +1564,7 @@ abstract class LocaleKeys { static const unableToSendOTP = 'unableToSendOTP'; static const loadingAIAnalysis = 'loadingAIAnalysis'; static const symptoms = 'symptoms'; + static const insuranceInActive = 'insuranceInActive'; + static const insuranceInActiveContactSupport = 'insuranceInActiveContactSupport'; } diff --git a/lib/presentation/insurance/widgets/patient_insurance_card.dart b/lib/presentation/insurance/widgets/patient_insurance_card.dart index c9ec790..531341b 100644 --- a/lib/presentation/insurance/widgets/patient_insurance_card.dart +++ b/lib/presentation/insurance/widgets/patient_insurance_card.dart @@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.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/insurance/insurance_view_model.dart'; @@ -16,6 +17,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class PatientInsuranceCard extends StatelessWidget { PatientInsuranceCard({super.key, required this.insuranceCardDetailsModel, required this.isInsuranceExpired}); @@ -49,19 +51,73 @@ class PatientInsuranceCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( - width: MediaQuery.of(context).size.width * 0.45, child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true)), + width: MediaQuery.of(context).size.width * 0.4, + child: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true, textOverflow: TextOverflow.clip)), LocaleKeys.policyNumber.tr(namedArgs: {'number': insuranceCardDetailsModel.insurancePolicyNo ?? ''}, context: context).toText12(isBold: true, color: AppColors.lightGrayColor), ], ), AppCustomChipWidget( - icon: isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon, - labelText: isInsuranceExpired ? LocaleKeys.insuranceExpired.tr(context: context) : LocaleKeys.insuranceActive.tr(context: context), - iconColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, - textColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, - iconSize: 12, - backgroundColor: isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), - labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), - ), + icon: insuranceViewModel.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceViewModel.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceViewModel.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceViewModel.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + iconSize: 12.w, + deleteIcon: insuranceViewModel.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceViewModel.isInsuranceActive) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + confirmText: LocaleKeys.contactUs.tr(context: context), + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(context); + }, + onConfirmTap: () async { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + backgroundColor: insuranceViewModel.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceViewModel.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceViewModel.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceViewModel.isInsuranceLoading), + // AppCustomChipWidget( + // icon: isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon, + // labelText: isInsuranceExpired ? LocaleKeys.insuranceExpired.tr(context: context) : LocaleKeys.insuranceActive.tr(context: context), + // iconColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, + // textColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, + // iconSize: 12, + // backgroundColor: isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), + // labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), + // ), ], ), SizedBox(height: 12.h), diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index ddac1bb..1b70f54 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -78,6 +78,7 @@ 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/common_shimmer_widget.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../features/active_prescriptions/active_prescriptions_view_model.dart'; import '../prescriptions/prescription_detail_page.dart'; @@ -286,14 +287,58 @@ class _MedicalFilePageState extends State { ), Consumer(builder: (context, insuranceVM, child) { return AppCustomChipWidget( - icon: insuranceVM.isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon, - labelText: insuranceVM.isInsuranceExpired ? LocaleKeys.insuranceExpired.tr(context: context) : LocaleKeys.insuranceActive.tr(context: context), - iconColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, - textColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor, + icon: insuranceVM.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceVM.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceVM.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceVM.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, iconSize: 12.w, - backgroundColor: insuranceVM.isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.1) : AppColors.successColor.withOpacity(0.1), - labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), - ); + deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceVM.isInsuranceActive) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: navigationService.navigatorKey.currentContext!), + navigationService.navigatorKey.currentContext!, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + confirmText: LocaleKeys.contactUs.tr(context: context), + isShowActionButtons: true, + onCancelTap: () { + navigationService.pop(); + }, + onConfirmTap: () async { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + backgroundColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceVM.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceVM.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceVM.isInsuranceLoading); }), ], ), diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index a3c2667..8dddafa 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -228,8 +228,8 @@ class ProfileSettingsState extends State { child: Column( children: [ actionItem(AppAssets.call_fill, LocaleKeys.contactUs.tr(context: context), () { - launchUrl(Uri.parse("tel://" + "+966 11 525 9999")); - }, trailingLabel: "011 525 9999"), + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }, trailingLabel: "92 006 6666"), 1.divider, actionItem(AppAssets.permission, LocaleKeys.permissions.tr(context: context), () {}, trailingLabel: "Location, Camera"), 1.divider, @@ -366,61 +366,66 @@ class FamilyCardWidget extends StatelessWidget { labelText: "Blood: ${appState.getAuthenticatedUser()!.bloodGroup ?? ""}", iconColor: AppColors.primaryRedColor) : SizedBox(), - Selector( - selector: (context, insuranceVM) => ( - isEmpty: insuranceVM.patientInsuranceList.isEmpty, - patientID: insuranceVM.patientInsuranceList.isNotEmpty ? insuranceVM.patientInsuranceList.first.patientID : null, - isLoading: insuranceVM.isInsuranceLoading, - cardValidTo: insuranceVM.patientInsuranceList.isNotEmpty ? insuranceVM.patientInsuranceList.first.cardValidTo : null - ), - builder: (context, data, child) { - if (data.isEmpty) { - return const SizedBox(); - } else if (profile.responseId != data.patientID) { - return SizedBox(); - } - - final isLoading = data.isLoading; - final isExpired = !isLoading && DateTime.now().isAfter(DateUtil.convertStringToDate(data.cardValidTo)); - - final String icon; - final String labelText; - final Color iconColor; - final Color backgroundColor; - - if (isLoading) { - icon = AppAssets.cancel_circle_icon; - labelText = LocaleKeys.insurance.tr(context: context); - iconColor = AppColors.primaryRedColor; - backgroundColor = AppColors.primaryRedColor; - } else if (isExpired) { - icon = AppAssets.cancel_circle_icon; - labelText = LocaleKeys.insuranceExpired.tr(context: context); - iconColor = AppColors.primaryRedColor; - backgroundColor = AppColors.primaryRedColor.withValues(alpha: 0.15); - } else { - icon = AppAssets.insurance_active_icon; - labelText = LocaleKeys.insuranceActive.tr(context: context); - iconColor = AppColors.successColor; - backgroundColor = AppColors.successColor.withValues(alpha: 0.15); - } - - return AppCustomChipWidget( - icon: icon, - labelText: labelText, - iconColor: iconColor, - iconSize: 12.w, - backgroundColor: backgroundColor, - labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 8.w), - // padding: EdgeInsets.zero, - ).toShimmer2(isShow: isLoading); - }, - ) + Consumer(builder: (context, insuranceVM, child) { + return AppCustomChipWidget( + icon: insuranceVM.isInsuranceExpired + ? AppAssets.cancel_circle_icon + : insuranceVM.isInsuranceActive + ? AppAssets.insurance_active_icon + : AppAssets.alertSquare, + labelText: insuranceVM.isInsuranceExpired + ? LocaleKeys.insuranceExpired.tr(context: context) + : insuranceVM.isInsuranceActive + ? LocaleKeys.insuranceActive.tr(context: context) + : LocaleKeys.insuranceInActive.tr(context: context), + iconColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + textColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor + : insuranceVM.isInsuranceActive + ? AppColors.successColor + : AppColors.warningColorYellow, + iconSize: 12.w, + deleteIcon: insuranceVM.isInsuranceActive ? null : AppAssets.forward_chevron_icon, + deleteIconColor: AppColors.warningColorYellow, + deleteIconHasColor: true, + onChipTap: () { + if (!insuranceVM.isInsuranceActive) { + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getWarningWidget( + loadingText: LocaleKeys.insuranceInActiveContactSupport.tr(context: context), + confirmText: LocaleKeys.contactUs.tr(context: context), + isShowActionButtons: true, + onCancelTap: () { + Navigator.pop(context); + }, + onConfirmTap: () async { + launchUrl(Uri.parse("tel://" + "+966 92 006 6666")); + }), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + backgroundColor: insuranceVM.isInsuranceExpired + ? AppColors.primaryRedColor.withOpacity(0.1) + : insuranceVM.isInsuranceActive + ? AppColors.successColor.withOpacity(0.1) + : AppColors.warningColorYellow.withOpacity(0.1), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: insuranceVM.isInsuranceActive ? 6.w : 0.w), + ).toShimmer2(isShow: insuranceVM.isInsuranceLoading); + }), ], ), ), ], - ).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 0.h), + ).paddingOnly(top: 16.h, right: 16.w, left: 16.w, bottom: 8.h), 1.divider.paddingSymmetrical(16.w, 0.h), _buildActionButton(appState), ],