register insurance in progress.

dev_sultan
Sultan khan 4 weeks ago
parent 7d8537fae6
commit c416d84a3a

@ -918,7 +918,10 @@ class HmgServicesRepoImp implements HmgServicesRepo {
@override
Future<Either<Failure, GenericApiModel<List<VitalSignResModel>>>> getPatientVitalSign() async {
Map<String, dynamic> requestBody = {};
Map<String, dynamic> requestBody = {
};
try {
GenericApiModel<List<VitalSignResModel>>? apiResponse;
@ -942,12 +945,29 @@ class HmgServicesRepoImp implements HmgServicesRepo {
if (vitalSignJson is Map<String, dynamic>) {
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);
}
}

@ -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<void> 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) {

@ -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<RegisterNewStep2> {
AuthenticationViewModel? authVM;
InsuranceViewModel? insuranceVM;
@override
void initState() {
super.initState();
authVM = context.read<AuthenticationViewModel>();
insuranceVM = context.read<InsuranceViewModel>();
// 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<RegisterNewStep2> {
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<RegisterNewStep2> {
children: <Widget>[
LocaleKeys.personalDetailsVerification.tr().toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2),
SizedBox(height: 24.h),
// Insurance Card Section
Consumer<InsuranceViewModel>(
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<RegisterNewStep2> {
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<RegisterNewStep2> {
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<AuthenticationViewModel, GenderTypeEnum?>(
@ -148,7 +238,7 @@ class _RegisterNew extends State<RegisterNewStep2> {
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<AuthenticationViewModel, MaritalStatusTypeEnum?>(
@ -187,7 +277,7 @@ class _RegisterNew extends State<RegisterNewStep2> {
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<AuthenticationViewModel, ({List<NationalityCountries>? countriesList, NationalityCountries? selectedCountry, bool isArabic})>(
@ -237,14 +327,14 @@ class _RegisterNew extends State<RegisterNewStep2> {
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<RegisterNewStep2> {
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<RegisterNewStep2> {
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),
],
),
),

@ -216,12 +216,21 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
}
Widget _historyCard(BuildContext context, {required List<DataPoint> 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<DataPoint>? secondaryHistory;
if (args.metric == VitalSignMetric.bloodPressure) {
secondaryHistory = _buildBloodPressureDiastolicSeries(
final fullSecondaryHistory = _buildBloodPressureDiastolicSeries(
context.read<HmgServicesViewModel>().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<VitalSignDetailsPage> {
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<VitalSignDetailsPage> {
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) {

@ -24,6 +24,19 @@ class VitalSignPage extends StatefulWidget {
}
class _VitalSignPageState extends State<VitalSignPage> {
// 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<VitalSignPage> {
? 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<VitalSignPage> {
_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: '',

Loading…
Cancel
Save