From c416d84a3a3de72d40f324979f07e48c176b4180 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Thu, 12 Feb 2026 15:11:15 +0300 Subject: [PATCH] register insurance in progress. --- .../hmg_services/hmg_services_repo.dart | 30 +++- .../insurance/insurance_view_model.dart | 22 ++- .../authentication/register_step2.dart | 154 ++++++++++++------ .../vital_sign/vital_sign_details_page.dart | 22 ++- .../vital_sign/vital_sign_page.dart | 31 +++- 5 files changed, 189 insertions(+), 70 deletions(-) diff --git a/lib/features/hmg_services/hmg_services_repo.dart b/lib/features/hmg_services/hmg_services_repo.dart index e4b9a030..89285339 100644 --- a/lib/features/hmg_services/hmg_services_repo.dart +++ b/lib/features/hmg_services/hmg_services_repo.dart @@ -918,7 +918,10 @@ class HmgServicesRepoImp implements HmgServicesRepo { @override Future>>> getPatientVitalSign() async { - Map requestBody = {}; + Map requestBody = { + + + }; try { GenericApiModel>? apiResponse; @@ -942,12 +945,29 @@ class HmgServicesRepoImp implements HmgServicesRepo { if (vitalSignJson is Map) { final vitalSign = VitalSignResModel.fromJson(vitalSignJson); - // Only add records where BOTH height AND weight are greater than 0 + // Debug logging for blood pressure + print('=== Repository Blood Pressure Check ==='); + print('bloodPressureHigher: ${vitalSign.bloodPressureHigher}'); + print('bloodPressureLower: ${vitalSign.bloodPressureLower}'); + print('weightKg: ${vitalSign.weightKg}'); + print('heightCm: ${vitalSign.heightCm}'); + + // Check if the record has at least one valid vital sign measurement final hasValidWeight = _isValidValue(vitalSign.weightKg); final hasValidHeight = _isValidValue(vitalSign.heightCm); - - // Only add if both height and weight are valid (> 0) - if (hasValidWeight && hasValidHeight) { + final hasValidBMI = _isValidValue(vitalSign.bodyMassIndex); + final hasValidTemperature = _isValidValue(vitalSign.temperatureCelcius); + final hasValidHeartRate = _isValidValue(vitalSign.heartRate) || _isValidValue(vitalSign.pulseBeatPerMinute); + final hasValidRespiration = _isValidValue(vitalSign.respirationBeatPerMinute); + final hasValidBloodPressure = _isValidValue(vitalSign.bloodPressureHigher) || _isValidValue(vitalSign.bloodPressureLower); + + print('hasValidBloodPressure: $hasValidBloodPressure'); + print('Will add to list: ${hasValidWeight || hasValidHeight || hasValidBMI || hasValidTemperature || hasValidHeartRate || hasValidRespiration || hasValidBloodPressure}'); + print('====================================='); + + // Add if ANY vital sign has valid data + if (hasValidWeight || hasValidHeight || hasValidBMI || hasValidTemperature || + hasValidHeartRate || hasValidRespiration || hasValidBloodPressure) { vitalSignList.add(vitalSign); } } diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index 0bbdda20..8573ae9d 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -30,10 +30,14 @@ class InsuranceViewModel extends ChangeNotifier { InsuranceViewModel({required this.insuranceRepo, required this.errorHandlerService}); initInsuranceProvider() { + debugPrint("InsuranceViewModel: initInsuranceProvider called, isInsuranceDataToBeLoaded=$isInsuranceDataToBeLoaded"); if (isInsuranceDataToBeLoaded) { patientInsuranceList.clear(); isInsuranceLoading = true; + debugPrint("InsuranceViewModel: Calling getPatientInsuranceDetails API"); getPatientInsuranceDetails(); + } else { + debugPrint("InsuranceViewModel: Skipping API call, isInsuranceDataToBeLoaded is false"); } patientInsuranceCardHistoryList.clear(); isInsuranceHistoryLoading = true; @@ -69,29 +73,39 @@ class InsuranceViewModel extends ChangeNotifier { } Future getPatientInsuranceDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async { - if (!isInsuranceDataToBeLoaded) return; + if (!isInsuranceDataToBeLoaded) { + debugPrint("InsuranceViewModel: getPatientInsuranceDetails - skipping, flag is false"); + return; + } + debugPrint("InsuranceViewModel: getPatientInsuranceDetails - making API call"); final result = await insuranceRepo.getPatientInsuranceDetails(); result.fold( // (failure) async => await errorHandlerService.handleError(failure: failure), (failure) async { + debugPrint("InsuranceViewModel: API call failed - ${failure.toString()}"); isInsuranceLoading = false; isInsuranceDataToBeLoaded = false; notifyListeners(); }, (apiResponse) { if (apiResponse.messageStatus == 2) { + debugPrint("InsuranceViewModel: API returned error status"); isInsuranceDataToBeLoaded = false; // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { + debugPrint("InsuranceViewModel: API success - received ${apiResponse.data?.length ?? 0} insurance records"); patientInsuranceList = apiResponse.data!; isInsuranceLoading = false; isInsuranceDataToBeLoaded = false; - isInsuranceExpired = DateTime.now().isAfter( - DateUtil.convertStringToDate(patientInsuranceList.first.cardValidTo), - ); + if (patientInsuranceList.isNotEmpty) { + isInsuranceExpired = DateTime.now().isAfter( + DateUtil.convertStringToDate(patientInsuranceList.first.cardValidTo), + ); + debugPrint("InsuranceViewModel: Insurance card expired: $isInsuranceExpired"); + } notifyListeners(); if (onSuccess != null) { diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart index 71cef960..fdb0f42e 100644 --- a/lib/presentation/authentication/register_step2.dart +++ b/lib/presentation/authentication/register_step2.dart @@ -5,12 +5,15 @@ import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/enums.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/validation_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/authentication/authentication_view_model.dart'; +import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; @@ -28,11 +31,22 @@ class RegisterNewStep2 extends StatefulWidget { class _RegisterNew extends State { AuthenticationViewModel? authVM; + InsuranceViewModel? insuranceVM; @override void initState() { super.initState(); authVM = context.read(); + insuranceVM = context.read(); + + // Call insurance API to fetch data + WidgetsBinding.instance.addPostFrameCallback((_) { + debugPrint("Registration Step 2: Calling insurance API"); + // Reset the flag to ensure API gets called + insuranceVM?.setIsInsuranceDataToBeLoaded(true); + insuranceVM?.initInsuranceProvider(); + debugPrint("Registration Step 2: Insurance API call initiated"); + }); } @override @@ -59,6 +73,59 @@ class _RegisterNew extends State { onLanguageChanged: (lang) {}, hideLogoAndLang: true, ), + bottomSheet: Container( + // height: 200.h, + width: MediaQuery.of(context).size.width, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + customBorder: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), + hasShadow: true, + ), + child: Row( + children: [ + Expanded( + child: CustomButton( + text: LocaleKeys.cancel.tr(), + icon: AppAssets.cancel, + onPressed: () { + Navigator.of(context).pop(); + // authVM!.clearDefaultInputValues(); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + iconColor: AppColors.primaryRedColor, + ), + ), + SizedBox(width: 16.w), + Expanded( + child: CustomButton( + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + text: LocaleKeys.confirm.tr(), + icon: AppAssets.confirm, + iconColor: AppColors.whiteColor, + onPressed: () { + if (appState.getUserRegistrationPayload.zipCode != CountryEnum.saudiArabia.countryCode) { + if (ValidationUtils.validateUaeRegistration( + name: authVM!.nameController.text, + gender: authVM!.genderType, + country: authVM!.pickedCountryByUAEUser, + maritalStatus: authVM!.maritalStatus, + onOkPress: () { + Navigator.of(context).pop(); + })) { + showModel(context: context); + } + } else { + showModel(context: context); + } + }, + ), + ) + ], + ).paddingAll(16.h),), body: GestureDetector( onTap: () { FocusScope.of(context).unfocus(); @@ -75,6 +142,29 @@ class _RegisterNew extends State { children: [ LocaleKeys.personalDetailsVerification.tr().toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2), SizedBox(height: 24.h), + + // Insurance Card Section + Consumer( + builder: (context, insuranceVM, child) { + // Only show if insurance data is available and not loading + if (!insuranceVM.isInsuranceLoading && insuranceVM.patientInsuranceList.isNotEmpty) { + return Column( + children: [ + PatientInsuranceCard( + insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first, + isInsuranceExpired: DateTime.now().isAfter( + DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo), + ), + ), + SizedBox(height: 24.h), + ], + ); + } + // Don't show anything if loading or no data + return SizedBox.shrink(); + }, + ), + Container( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), padding: EdgeInsets.only(left: 16.h, right: 16.h), @@ -97,7 +187,7 @@ class _RegisterNew extends State { isReadOnly: authVM!.isUserFromUAE() ? false : true, leadingIcon: AppAssets.user_circle, labelColor: AppColors.textColor, - ).paddingSymmetrical(0.h, 16.h), + ).paddingSymmetrical(0.h, 8.h), Divider(height: 1.h, color: AppColors.greyColor), TextInputWidget( labelText: LocaleKeys.nationalIdNumber.tr(), @@ -111,7 +201,7 @@ class _RegisterNew extends State { isReadOnly: true, labelColor: AppColors.textColor, leadingIcon: AppAssets.student_card) - .paddingSymmetrical(0.h, 16.h), + .paddingSymmetrical(0.h, 8.h), Divider(height: 1, color: AppColors.greyColor), authVM!.isUserFromUAE() ? Selector( @@ -148,7 +238,7 @@ class _RegisterNew extends State { leadingIcon: AppAssets.user_full, labelColor: AppColors.textColor, onChange: (value) {}) - .paddingSymmetrical(0.h, 16.h), + .paddingSymmetrical(0.h, 8.h), Divider(height: 1, color: AppColors.greyColor), authVM!.isUserFromUAE() ? Selector( @@ -187,7 +277,7 @@ class _RegisterNew extends State { labelColor: AppColors.textColor, leadingIcon: AppAssets.smart_phone, onChange: (value) {}) - .paddingSymmetrical(0.h, 16.h), + .paddingSymmetrical(0.h, 8.h), Divider(height: 1.h, color: AppColors.greyColor), authVM!.isUserFromUAE() ? Selector? countriesList, NationalityCountries? selectedCountry, bool isArabic})>( @@ -237,14 +327,14 @@ class _RegisterNew extends State { labelColor: AppColors.textColor, leadingIcon: AppAssets.globe, onChange: (value) {}) - .paddingSymmetrical(0.h, 16.h), + .paddingSymmetrical(0.h, 8.h), Divider( height: 1, color: AppColors.greyColor, ), TextInputWidget( labelText: LocaleKeys.mobileNumber.tr(), - hintText: (appState.getUserRegistrationPayload.patientMobileNumber.toString() ?? ""), + hintText: appState.getUserRegistrationPayload.patientMobileNumber.toString(), controller: null, isEnable: false, prefix: null, @@ -254,7 +344,7 @@ class _RegisterNew extends State { labelColor: AppColors.textColor, isReadOnly: true, leadingIcon: AppAssets.call) - .paddingSymmetrical(0.h, 16.h), + .paddingSymmetrical(0.h, 8.h), Divider( height: 1.h, color: AppColors.greyColor, @@ -271,56 +361,12 @@ class _RegisterNew extends State { labelColor: AppColors.textColor, leadingIcon: AppAssets.birthday_cake, selectionType: null, - ).paddingSymmetrical(0.h, 16.h), + ).paddingSymmetrical(0.h, 8.h), ], ), ), - SizedBox(height: 50.h), - Row( - children: [ - Expanded( - child: CustomButton( - text: LocaleKeys.cancel.tr(), - icon: AppAssets.cancel, - onPressed: () { - Navigator.of(context).pop(); - // authVM!.clearDefaultInputValues(); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - iconColor: AppColors.primaryRedColor, - ), - ), - SizedBox(width: 16.w), - Expanded( - child: CustomButton( - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, - text: LocaleKeys.confirm.tr(), - icon: AppAssets.confirm, - iconColor: AppColors.whiteColor, - onPressed: () { - if (appState.getUserRegistrationPayload.zipCode != CountryEnum.saudiArabia.countryCode) { - if (ValidationUtils.validateUaeRegistration( - name: authVM!.nameController.text, - gender: authVM!.genderType, - country: authVM!.pickedCountryByUAEUser, - maritalStatus: authVM!.maritalStatus, - onOkPress: () { - Navigator.of(context).pop(); - })) { - showModel(context: context); - } - } else { - showModel(context: context); - } - }, - ), - ) - ], - ), + SizedBox(height: 120.h), + ], ), ), diff --git a/lib/presentation/vital_sign/vital_sign_details_page.dart b/lib/presentation/vital_sign/vital_sign_details_page.dart index f6325029..f7aafa48 100644 --- a/lib/presentation/vital_sign/vital_sign_details_page.dart +++ b/lib/presentation/vital_sign/vital_sign_details_page.dart @@ -216,12 +216,21 @@ class _VitalSignDetailsPageState extends State { } Widget _historyCard(BuildContext context, {required List history}) { + // For graph display, use only the last 5 data points to avoid performance issues + final graphHistory = _isGraphVisible && history.length > 5 + ? history.sublist(history.length - 5) + : history; + // For blood pressure, we need both systolic and diastolic series List? secondaryHistory; if (args.metric == VitalSignMetric.bloodPressure) { - secondaryHistory = _buildBloodPressureDiastolicSeries( + final fullSecondaryHistory = _buildBloodPressureDiastolicSeries( context.read().vitalSignList, ); + // Also limit secondary history to last 5 for graph + secondaryHistory = _isGraphVisible && fullSecondaryHistory.length > 5 + ? fullSecondaryHistory.sublist(fullSecondaryHistory.length - 5) + : fullSecondaryHistory; } return Container( @@ -290,7 +299,7 @@ class _VitalSignDetailsPageState extends State { if (history.isEmpty) Utils.getNoDataWidget(context, noDataText: 'No history available'.needTranslation, isSmallWidget: true) else if (_isGraphVisible) - _buildHistoryGraph(history, secondaryHistory: secondaryHistory) + _buildHistoryGraph(graphHistory, secondaryHistory: secondaryHistory) else _buildHistoryList(context, history), ], @@ -591,8 +600,13 @@ class _VitalSignDetailsPageState extends State { double? _toDouble(dynamic v) { if (v == null) return null; - if (v is num) return v.toDouble(); - return double.tryParse(v.toString()); + if (v is num) { + // Treat 0 as invalid for vital signs + return v == 0 ? null : v.toDouble(); + } + final parsed = double.tryParse(v.toString()); + // Treat 0 as invalid for vital signs + return (parsed == null || parsed == 0) ? null : parsed; } String _latestValueText(VitalSignResModel? latest) { diff --git a/lib/presentation/vital_sign/vital_sign_page.dart b/lib/presentation/vital_sign/vital_sign_page.dart index fbf9fc6d..04d36bd9 100644 --- a/lib/presentation/vital_sign/vital_sign_page.dart +++ b/lib/presentation/vital_sign/vital_sign_page.dart @@ -24,6 +24,19 @@ class VitalSignPage extends StatefulWidget { } class _VitalSignPageState extends State { + + // Helper function to check if a value is valid (not null, not 0, not empty string) + bool _isValidValue(dynamic value) { + if (value == null) return false; + if (value is num) return value > 0; + if (value is String) { + if (value.trim().isEmpty) return false; + final parsed = double.tryParse(value); + return parsed != null && parsed > 0; + } + return false; + } + void _openDetails(VitalSignDetailsArgs args) { Navigator.of(context).push( CustomPageRoute( @@ -51,6 +64,18 @@ class _VitalSignPageState extends State { ? viewModel.vitalSignList.first : null; + // Debug logging for blood pressure + if (latestVitalSign != null) { + print('=== Blood Pressure Debug ==='); + print('bloodPressureHigher: ${latestVitalSign.bloodPressureHigher}'); + print('bloodPressureLower: ${latestVitalSign.bloodPressureLower}'); + print('bloodPressureHigher type: ${latestVitalSign.bloodPressureHigher.runtimeType}'); + print('bloodPressureLower type: ${latestVitalSign.bloodPressureLower.runtimeType}'); + print('bloodPressureHigher == 0: ${latestVitalSign.bloodPressureHigher == 0}'); + print('bloodPressureLower == 0: ${latestVitalSign.bloodPressureLower == 0}'); + print('========================'); + } + return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -125,9 +150,9 @@ class _VitalSignPageState extends State { _buildVitalSignCard( icon: AppAssets.bloodPressure, label: 'Blood Pressure', - value: latestVitalSign != null && - latestVitalSign.bloodPressureHigher != null && - latestVitalSign.bloodPressureLower != null + value: (latestVitalSign != null && + _isValidValue(latestVitalSign.bloodPressureHigher) && + _isValidValue(latestVitalSign.bloodPressureLower)) ? '${latestVitalSign.bloodPressureHigher}/${latestVitalSign.bloodPressureLower}' : '--', unit: '',