diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 5478c379..d2ea81f9 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -210,8 +210,8 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; } - body['TokenID'] = "@dm!n"; - // body['PatientID'] = 6424682; + // body['TokenID'] = "@dm!n"; + // body['PatientID'] = 4772993; // body['PatientID'] = 89754444; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 9e8a044d..320bd1cf 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -4,12 +4,14 @@ import 'dart:io'; import 'dart:math' as dartMath; import 'dart:typed_data'; +import 'package:clarity_flutter/clarity_flutter.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:crypto/crypto.dart' as crypto; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:get_it/get_it.dart'; import 'package:google_api_availability/google_api_availability.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; @@ -916,7 +918,8 @@ class Utils { appState.isArabic() ? Container() : Utils.buildSvgWithAssets( - icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol, + // icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol, + icon: (getIt.get().getAuthenticatedUser()!.outSa == 0) ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol, iconColor: iconColor, width: iconSize.h, height: iconSize.h, @@ -928,7 +931,8 @@ class Utils { !appState.isArabic() ? Container() : Utils.buildSvgWithAssets( - icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol, + // icon: isSaudiCurrency ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol, + icon: (getIt.get().getAuthenticatedUser()!.outSa == 0) ? AppAssets.saudi_riyal_icon : AppAssets.uae_dirham_symbol, iconColor: iconColor, width: iconSize.h, height: iconSize.h, @@ -958,7 +962,7 @@ class Utils { WidgetSpan( alignment: PlaceholderAlignment.baseline, baseline: TextBaseline.alphabetic, - child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: resolvedIconColor), + child: Utils.buildSvgWithAssets(icon: (getIt.get().getAuthenticatedUser()!.outSa == 1) ? AppAssets.uae_dirham_symbol : AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: resolvedIconColor), ), TextSpan( // text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount), diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index a4a61f35..e34e2188 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -1127,7 +1127,9 @@ class BookAppointmentsViewModel extends ChangeNotifier { result.fold( (failure) async { - print(failure); + if(onError != null) { + onError(failure.message); + } }, (apiResponse) { if (apiResponse.messageStatus == 2) { diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 90f504d2..0862c40d 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -1010,7 +1010,9 @@ class MyAppointmentsViewModel extends ChangeNotifier { } } // patientQueueDetailsList.first.callType = 1; - patientQueueDetailsList.removeWhere((element) => element.patientID == patientArrivedAppointmentsHistoryList.first.patientID); + // if (patientQueueDetailsList.length > 1) { + patientQueueDetailsList.removeWhere((element) => element.patientID == patientArrivedAppointmentsHistoryList.first.patientID); + // } } else { patientQueueDetailsList.clear(); isPatientHasQueueAppointment = false; diff --git a/lib/features/payfort/payfort_view_model.dart b/lib/features/payfort/payfort_view_model.dart index 8d26eab1..aebb8d5f 100644 --- a/lib/features/payfort/payfort_view_model.dart +++ b/lib/features/payfort/payfort_view_model.dart @@ -319,7 +319,7 @@ class PayfortViewModel extends ChangeNotifier { "amount": Platform.isAndroid ? (num.parse(amount) * 100).toInt() : (num.parse(amount) * 100).toInt().toString(), // "amount": "100000", "currency": getIt.get().getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", - "language": "en", + "language": getIt.get().isArabic() ? "ar" : "en", "customer_email": "CustID_$fileNumber@HMG.com", "sdk_token": sdkTokenResponse!.sdkToken, "customer_name": "${getIt.get().getAuthenticatedUser()!.firstName} ${getIt.get().getAuthenticatedUser()!.lastName}", @@ -353,6 +353,11 @@ class PayfortViewModel extends ChangeNotifier { // Process real payment rejection errors here print("Actual Payment Failure: ${e.details.toString()}"); + if (onFailed != null) { + final paymentMap = (e.details as Map).cast(); + paymentMap["message"] = e.details["response_message"] ?? "Payment failed with unknown error."; + onFailed(PayFortFailureResult.fromMap(paymentMap)); + } } catch (error) { print("Generic Error: $error"); } diff --git a/lib/features/paytabs/paytabs_view_model.dart b/lib/features/paytabs/paytabs_view_model.dart index d572ab33..35a924af 100644 --- a/lib/features/paytabs/paytabs_view_model.dart +++ b/lib/features/paytabs/paytabs_view_model.dart @@ -65,7 +65,7 @@ class PayTabsViewModel extends ChangeNotifier { "12626"), alternativePaymentMethods: [], linkBillingNameWithCardHolderName: true, - simplifyApplePayValidation: false, + simplifyApplePayValidation: true, ); paymentConfiguration.iOSThemeConfigurations = IOSThemeConfigurations( diff --git a/lib/features/weather/weather_view_model.dart b/lib/features/weather/weather_view_model.dart index a145fcca..081ef192 100644 --- a/lib/features/weather/weather_view_model.dart +++ b/lib/features/weather/weather_view_model.dart @@ -23,10 +23,14 @@ class WeatherMonitorViewModel extends ChangeNotifier { final List _cityInfoList = []; bool isLoading = false; + bool isWeatherNeedToLoad = true; List get cityInfoList => _cityInfoList; Future fetchCityInfoList({Function(dynamic)? onSuccess, Function(String)? onError}) async { + if (!isWeatherNeedToLoad) { + return; + } isLoading = true; notifyListeners(); _cityInfoList.clear(); @@ -34,7 +38,7 @@ class WeatherMonitorViewModel extends ChangeNotifier { // Check if location permission is already granted final isLocationEnabled = await locationUtils.isLocationPermissionEnabled(); - if (isLocationEnabled) { + if (isLocationEnabled && getIt.get().userLat != 0.0 && getIt.get().userLong != 0.0) { // Permission already granted, fetch data directly isLocationAvailable = true; final result = await weatherRepo.getCityInfo(); @@ -61,6 +65,7 @@ class WeatherMonitorViewModel extends ChangeNotifier { if (onSuccess != null) { onSuccess(apiResponse); } + isWeatherNeedToLoad = false; } }, ); diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index 79b99a1e..b3814f00 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -69,11 +69,13 @@ class _AppointmentPaymentPageState extends State { widget.patientAppointmentHistoryResponseModel.clinicID, widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false, onSuccess: (val) { myAppointmentsViewModel.getTamaraInstallmentsDetails().then((val) { - if (myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! >= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! && - myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! <= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) { - setState(() { - isShowTamara = true; - }); + if (myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel != null) { + if (myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! >= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! && + myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax! <= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) { + setState(() { + isShowTamara = true; + }); + } } }); }, onError: (err) { diff --git a/lib/presentation/appointments/appointment_queue_page.dart b/lib/presentation/appointments/appointment_queue_page.dart index 59522149..f2bd1d18 100644 --- a/lib/presentation/appointments/appointment_queue_page.dart +++ b/lib/presentation/appointments/appointment_queue_page.dart @@ -26,6 +26,8 @@ class AppointmentQueuePage extends StatelessWidget { @override Widget build(BuildContext context) { appState = getIt.get(); + final currentQueue = getIt.get().currentPatientQueueDetails; + final currentStatus = getIt.get().currentQueueStatus; return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Consumer(builder: (context, myAppointmentsVM, child) { @@ -67,7 +69,7 @@ class AppointmentQueuePage extends StatelessWidget { labelText: myAppointmentsVM.currentQueueStatus == 0 ? LocaleKeys.inQueue.tr(context: context) : LocaleKeys.yourTurn.tr(context: context), backgroundColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.20), textColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus), - ).toShimmer2(isShow: myAppointmentsVM.patientQueueDetailsList.isEmpty), + ).toShimmer2(isShow: (currentQueue.queueNo == null || currentQueue.queueNo!.isEmpty)), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.greyColor, @@ -88,7 +90,7 @@ class AppointmentQueuePage extends StatelessWidget { SizedBox(height: 8.h), (myAppointmentsVM.currentPatientQueueDetails.queueNo ?? "IM-123") .toText32(isBold: true) - .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading || myAppointmentsVM.patientQueueDetailsList.isEmpty), + .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading || (currentQueue.queueNo == null || currentQueue.queueNo!.isEmpty)), SizedBox(height: 8.h), CustomButton( text: Utils.getCardButtonText(myAppointmentsVM.currentQueueStatus, myAppointmentsVM.currentPatientQueueDetails.roomNo ?? ""), @@ -103,7 +105,7 @@ class AppointmentQueuePage extends StatelessWidget { height: 40.h, iconColor: AppColors.whiteColor, iconSize: 18.h, - ).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading || myAppointmentsVM.patientQueueDetailsList.isEmpty), + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading || (currentQueue.queueNo == null || currentQueue.queueNo!.isEmpty)), ], ), ), diff --git a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart index 817ebfa0..dd6cf8eb 100644 --- a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart +++ b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart @@ -10,6 +10,7 @@ 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/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; @@ -153,9 +154,15 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.initAppointmentsViewModel(); myAppointmentsViewModel.getPatientAppointments(true, false); + + getIt.get().setIsWalletAmountToBeLoaded(true); + getIt.get().initHabibWalletProvider(); + getIt.get().getPatientBalanceAmount(); + LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight(context, title: LocaleKeys.success.tr(context: context), child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr()), callBackFunc: () async { // await myAppointmentsViewModel.getPatientAppointmentQueueDetails(); + Navigator.of(context).pop(); Navigator.pushAndRemoveUntil( context, diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index c38e9ad9..dee44de0 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -94,27 +94,29 @@ class LoginScreenState extends State { LocaleKeys.welcomeToDrSulaiman.tr(context: context).toText32(isBold: true, color: AppColors.textColor ), SizedBox(height: 32.h), Localizations.override(context: context, locale: Locale('en', 'US'), child: Container()), // Force English locale for this widget - TextInputWidget( - labelText: LocaleKeys.nationalIdFileNumber.tr(context: context), - hintText: "xxxxxxxxx", - controller: authVm.nationalIdController, - focusNode: _nationalIdFocusNode, - keyboardType: TextInputType.number, - isEnable: true, - prefix: null, - autoFocus: true, - isAllowRadius: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 10.h), - leadingIcon: AppAssets.student_card, - errorMessage: authVm.nationalIdError, - hasError: authVm.nationalIdError != null, - fontFamily: "Poppins", - onChange: (value) { - // Clear error when user starts typing - authVm.clearNationalIdError(); - }, + ClarityUnmask( + child: TextInputWidget( + labelText: LocaleKeys.nationalIdFileNumber.tr(context: context), + hintText: "xxxxxxxxx", + controller: authVm.nationalIdController, + focusNode: _nationalIdFocusNode, + keyboardType: TextInputType.number, + isEnable: true, + prefix: null, + autoFocus: true, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 10.h), + leadingIcon: AppAssets.student_card, + errorMessage: authVm.nationalIdError, + hasError: authVm.nationalIdError != null, + fontFamily: "Poppins", + onChange: (value) { + // Clear error when user starts typing + authVm.clearNationalIdError(); + }, + ), ), SizedBox(height: 16.h), CustomButton( @@ -205,65 +207,67 @@ class LoginScreenState extends State { child: SingleChildScrollView( child: Consumer( builder: (context, authVm, child) { - return GenericBottomSheet( - countryCode: authVm.selectedCountrySignup.countryCode, - initialPhoneNumber: "", - textController: phoneNumberController, - isEnableCountryDropdown: true, - onCountryChange: (country) { - authVm.onCountryChange(country); - // Clear error when country changes - authVm.clearPhoneNumberError(); - }, - onChange: (value) { - authVm.onPhoneNumberChange(value); - // Clear error when user starts typing - authVm.clearPhoneNumberError(); - }, - phoneNumberError: authVm.phoneNumberError, - buttons: [ - if (authVm.selectedCountrySignup != CountryEnum.others) + return ClarityUnmask( + child: GenericBottomSheet( + countryCode: authVm.selectedCountrySignup.countryCode, + initialPhoneNumber: "", + textController: phoneNumberController, + isEnableCountryDropdown: true, + onCountryChange: (country) { + authVm.onCountryChange(country); + // Clear error when country changes + authVm.clearPhoneNumberError(); + }, + onChange: (value) { + authVm.onPhoneNumberChange(value); + // Clear error when user starts typing + authVm.clearPhoneNumberError(); + }, + phoneNumberError: authVm.phoneNumberError, + buttons: [ + if (authVm.selectedCountrySignup != CountryEnum.others) + Padding( + padding: EdgeInsets.only(bottom: 10.h), + child: CustomButton( + text: LocaleKeys.sendOTPSMS.tr(context: context), + onPressed: () async { + validatePhoneAndProceed(OTPTypeEnum.sms); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedBorderColor, + textColor: Colors.white, + iconColor: Colors.white, + icon: AppAssets.message, + ), + ), + if (authVm.selectedCountrySignup != CountryEnum.others) + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.h), + child: LocaleKeys.oR.tr(context: context).toText16(color: AppColors.textColor), + ), + ], + ), Padding( - padding: EdgeInsets.only(bottom: 10.h), + padding: EdgeInsets.only(bottom: 10.h, top: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPSMS.tr(context: context), + text: LocaleKeys.sendOTPWHATSAPP.tr(context: context), onPressed: () async { - validatePhoneAndProceed(OTPTypeEnum.sms); + validatePhoneAndProceed(OTPTypeEnum.whatsapp); }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedBorderColor, - textColor: Colors.white, - iconColor: Colors.white, - icon: AppAssets.message, + backgroundColor: AppColors.whiteColor, + borderColor: AppColors.textColor, + textColor: AppColors.textColor, + icon: AppAssets.whatsapp, + iconColor: null, + applyThemeColor: false, ), ), - if (authVm.selectedCountrySignup != CountryEnum.others) - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 8.h), - child: LocaleKeys.oR.tr(context: context).toText16(color: AppColors.textColor), - ), - ], - ), - Padding( - padding: EdgeInsets.only(bottom: 10.h, top: 10.h), - child: CustomButton( - text: LocaleKeys.sendOTPWHATSAPP.tr(context: context), - onPressed: () async { - validatePhoneAndProceed(OTPTypeEnum.whatsapp); - }, - backgroundColor: AppColors.whiteColor, - borderColor: AppColors.textColor, - textColor: AppColors.textColor, - icon: AppAssets.whatsapp, - iconColor: null, - applyThemeColor: false, - ), - ), - ], + ], + ), ); }, ), diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart index aa23fef8..04fd3073 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart @@ -63,11 +63,13 @@ class _ImmediateLiveCarePaymentPageState extends State= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! && - num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!) <= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) { - setState(() { - isShowTamara = true; - }); + if (myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel != null) { + if (num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!) >= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! && + num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!) <= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.maxLimit!.amount!) { + setState(() { + isShowTamara = true; + }); + } } }); }); diff --git a/lib/presentation/book_appointment/review_appointment_page.dart b/lib/presentation/book_appointment/review_appointment_page.dart index 2b0b0368..b7fb6469 100644 --- a/lib/presentation/book_appointment/review_appointment_page.dart +++ b/lib/presentation/book_appointment/review_appointment_page.dart @@ -432,8 +432,15 @@ class _ReviewAppointmentPageState extends State { if (bookAppointmentsViewModel.isLiveCareSchedule) { await bookAppointmentsViewModel.insertSpecificAppointmentForLiveCare(onError: (err) { - print(err.data["ErrorEndUserMessage"]); LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + title: LocaleKeys.notice.tr(context: context), + context, + child: Utils.getErrorWidget(loadingText: err.toString()), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); }, onSuccess: (apiResp) async { LoaderBottomSheet.hideLoader(); await Future.delayed(Duration(milliseconds: 50)).then((value) async { diff --git a/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart b/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart index c7ef62bb..9b9e85bb 100644 --- a/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart +++ b/lib/presentation/book_appointment/waiting_appointment/waiting_appointment_payment_page.dart @@ -194,7 +194,7 @@ class _WaitingAppointmentPaymentPageState extends State { ), ), const Spacer(), - LocaleKeys.sar.tr(context: context).toText20(color: AppColors.greyTextColor, isBold: true), + ((getIt.get().getAuthenticatedUser()!.outSa == 1) ? LocaleKeys.aed.tr(context: context) : LocaleKeys.sar.tr(context: context)) + .toText20(color: AppColors.greyTextColor, isBold: true), ], ), ], diff --git a/lib/presentation/hmg_services/services_page.dart b/lib/presentation/hmg_services/services_page.dart index 6cc1bb93..75144cf7 100644 --- a/lib/presentation/hmg_services/services_page.dart +++ b/lib/presentation/hmg_services/services_page.dart @@ -544,7 +544,7 @@ class _ServicesPageState extends State { return Row( children: [ Utils.buildSvgWithAssets( - icon: AppAssets.saudi_riyal_icon, + icon: (getIt.get().getAuthenticatedUser()!.outSa == 1) ? AppAssets.uae_dirham_symbol : AppAssets.saudi_riyal_icon, iconColor: AppColors.inputLabelTextColor, width: 24.h, height: 24.h, @@ -554,7 +554,7 @@ class _ServicesPageState extends State { NumberFormat.decimalPattern() .format(habibWalletVM.habibWalletAmount) .toString() - .toText28(isBold: true, isEnglishOnly: true) + .toText28(isBold: true) .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h), ], ); diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 5f46f94f..531b310a 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -28,6 +28,7 @@ import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_liveca import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_queue_details_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; @@ -144,6 +145,8 @@ class _LandingPageState extends State { } if (appState.isAuthenticated) { + Clarity.setCustomUserId(appState.getAuthenticatedUser()!.patientId.toString()); + habibWalletVM.initHabibWalletProvider(); habibWalletVM.getPatientBalanceAmount(); habibWalletVM.getLakumAccountInformation(); @@ -1110,7 +1113,7 @@ class _LandingPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildQueueHeader(currentStatus), + _buildQueueHeader(currentQueue, currentStatus), SizedBox(height: 8.h), _buildQueueGreeting(), SizedBox(height: 2.h), @@ -1119,11 +1122,11 @@ class _LandingPageState extends State { color: AppColors.textColorLight, ), SizedBox(height: 8.h), - (currentQueue.queueNo ?? "IM-123").toText28(isBold: true).toShimmer2(isShow: myAppointmentsViewModel.patientQueueDetailsList.isEmpty), + (currentQueue.queueNo ?? "IM-123").toText28(isBold: true).toShimmer2(isShow: (currentQueue.queueNo == null || currentQueue.queueNo!.isEmpty)), SizedBox(height: 6.h), _buildServingNowSection(), SizedBox(height: 5.h), - _buildQueueActionButton(currentStatus, currentQueue.roomNo ?? "").toShimmer2(isShow: myAppointmentsViewModel.patientQueueDetailsList.isEmpty), + _buildQueueActionButton(currentStatus, currentQueue.roomNo ?? "").toShimmer2(isShow: (currentQueue.queueNo == null || currentQueue.queueNo!.isEmpty)), ], ), ), @@ -1135,7 +1138,7 @@ class _LandingPageState extends State { } // Queue Card: Header with status chip and icon - Widget _buildQueueHeader(int currentStatus) { + Widget _buildQueueHeader(PatientInQueueList currentQueue, int currentStatus) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, @@ -1144,7 +1147,7 @@ class _LandingPageState extends State { labelText: currentStatus == 0 ? LocaleKeys.inQueue.tr() : LocaleKeys.yourTurn.tr(), backgroundColor: Utils.getCardBorderColor(currentStatus).withValues(alpha: 0.20), textColor: Utils.getCardBorderColor(currentStatus), - ).toShimmer2(isShow: myAppointmentsViewModel.patientQueueDetailsList.isEmpty), + ).toShimmer2(isShow: (currentQueue.queueNo == null || currentQueue.queueNo!.isEmpty)), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.greyColor, diff --git a/lib/presentation/home/widgets/habib_wallet_card.dart b/lib/presentation/home/widgets/habib_wallet_card.dart index 1d9bd656..0bfba696 100644 --- a/lib/presentation/home/widgets/habib_wallet_card.dart +++ b/lib/presentation/home/widgets/habib_wallet_card.dart @@ -91,7 +91,7 @@ class HabibWalletCard extends StatelessWidget { Row( children: [ Utils.buildSvgWithAssets( - icon: AppAssets.saudi_riyal_icon, + icon: (getIt.get().getAuthenticatedUser()!.outSa == 1) ? AppAssets.uae_dirham_symbol : AppAssets.saudi_riyal_icon, iconColor: AppColors.inputLabelTextColor, width: 24.h, height: 24.h, diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 81343e42..66135dda 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -1226,10 +1226,13 @@ class _MedicalFilePageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "${LocaleKeys.sickSubtitle.tr(context: context)} ${LocaleKeys.sick2.tr(context: context)}".toText16(isBold: true), + (!appState.isArabic() + ? "${LocaleKeys.sick2.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}" + : "${LocaleKeys.sickSubtitle.tr(context: context)} ${LocaleKeys.sick2.tr(context: context)}") + .toText16(isBold: true), Row( children: [ - LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor), + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), ], diff --git a/lib/presentation/medical_file/patient_sickleaves_list_page.dart b/lib/presentation/medical_file/patient_sickleaves_list_page.dart index c31d80ac..431a8faf 100644 --- a/lib/presentation/medical_file/patient_sickleaves_list_page.dart +++ b/lib/presentation/medical_file/patient_sickleaves_list_page.dart @@ -53,7 +53,9 @@ class _PatientSickleavesListPageState extends State { return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( - title: "${LocaleKeys.sickSubtitle.tr(context: context)} ${LocaleKeys.sick2.tr(context: context)}", + title: (!appState.isArabic() + ? "${LocaleKeys.sick2.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}" + : "${LocaleKeys.sickSubtitle.tr(context: context)} ${LocaleKeys.sick2.tr(context: context)}"), child: SingleChildScrollView( child: Consumer(builder: (context, model, child) { return Column( diff --git a/lib/presentation/medical_file/widgets/medical_report_card.dart b/lib/presentation/medical_file/widgets/medical_report_card.dart index e2464392..1dc080c7 100644 --- a/lib/presentation/medical_file/widgets/medical_report_card.dart +++ b/lib/presentation/medical_file/widgets/medical_report_card.dart @@ -62,7 +62,7 @@ class MedicalReportCard extends StatelessWidget { ), if (listReady.isNotEmpty) AppCustomChipWidget( - labelText: '${listRequest.length.toString().padLeft(2, '0')} ${LocaleKeys.readyToDownload.tr()}', + labelText: '${listReady.length.toString().padLeft(2, '0')} ${LocaleKeys.readyToDownload.tr()}', icon: AppAssets.sucess, iconColor: AppColors.successColor, textColor: AppColors.successColor, diff --git a/lib/presentation/my_family/widget/family_cards.dart b/lib/presentation/my_family/widget/family_cards.dart index 2f48bcbe..8feb8434 100644 --- a/lib/presentation/my_family/widget/family_cards.dart +++ b/lib/presentation/my_family/widget/family_cards.dart @@ -444,7 +444,7 @@ class _FamilyCardsState extends State { // Original logic: final canSwitch = isParentUser || (!isParentUser && profile.responseId == appState.getSuperUserID); final canSwitch = true; // Disabled - allows all users to switch return Container( - padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h), + padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 12.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), child: Opacity( opacity: isActive || profile.status == FamilyFileEnum.pending.toInt || !canSwitch ? 0.4 : 1.0, // Fade all content if active @@ -454,8 +454,8 @@ class _FamilyCardsState extends State { mainAxisSize: MainAxisSize.min, children: [ UserAvatarWidget( - width: 72.h, - height: 70.h, + width: 70.h, + height: 66.h, gender: profile.gender, age: profile.age, fit: BoxFit.cover, @@ -463,7 +463,7 @@ class _FamilyCardsState extends State { isCircular: true, isFamilyMember: true, // Prevent AppState fallback ), - SizedBox(height: 8.h), + SizedBox(height: 4.h), (profile.patientName ?? "Unknown").toText14(isBold: true, isCenter: true, maxlines: 1), // SizedBox(height: 8.h), // CustomChipWidget( @@ -476,14 +476,17 @@ class _FamilyCardsState extends State { // textColor: AppColors.textColor), widget.isShowDetails ? SizedBox(height: 4.h) : SizedBox(), widget.isShowDetails - ? CustomChipWidget( - chipType: ChipTypeEnum.alert, - backgroundColor: AppColors.lightGrayBGColor, - chipText: "${LocaleKeys.age.tr(context: context)}: ${profile.age ?? "N/A"} ${LocaleKeys.years.tr(context: context)}", - isShowBorder: false, - borderRadius: 8.h, - textColor: AppColors.textColor, - ) + ? Wrap(direction: Axis.horizontal, spacing: 4.h, runSpacing: 4.h, children: [ + AppCustomChipWidget( + icon: AppAssets.file_icon, + richText: "${LocaleKeys.fileno.tr(context: context)}: ${profile.responseId}".toText10(isBold: true), + labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), + ), + AppCustomChipWidget( + labelText: "${LocaleKeys.age.tr(context: context)}: ${profile.age ?? "N/A"} ${LocaleKeys.years.tr(context: context)}", + labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 6.w), + ), + ]) : SizedBox(), widget.isShowDetails ? SizedBox(height: 8.h) diff --git a/lib/presentation/prescriptions/prescription_delivery_order_summary_page.dart b/lib/presentation/prescriptions/prescription_delivery_order_summary_page.dart index a5823b4f..968c4b5b 100644 --- a/lib/presentation/prescriptions/prescription_delivery_order_summary_page.dart +++ b/lib/presentation/prescriptions/prescription_delivery_order_summary_page.dart @@ -104,6 +104,8 @@ class PrescriptionDeliveryOrderSummaryPage extends StatelessWidget { url: "https://maps.googleapis.com/maps/api/staticmap?center=${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lat},${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lng}&zoom=15&size=350x165&maptype=roadmap&markers=color:red%7C${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lat},${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lng}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng", iconColor: AppColors.blackBgColor, fit: BoxFit.contain, + width: double.infinity, + height: 165.h, ), ), ], diff --git a/lib/presentation/profile_settings/accessibility_page.dart b/lib/presentation/profile_settings/accessibility_page.dart index 7fe9b61b..328c1936 100644 --- a/lib/presentation/profile_settings/accessibility_page.dart +++ b/lib/presentation/profile_settings/accessibility_page.dart @@ -417,17 +417,17 @@ class _AccessibilityPageState extends State { // Price with SAR symbol Row( children: [ - "1234".toText24( - isBold: true, - color: AppColors.blackBgColor, // Always use base color - ), - SizedBox(width: 4.w), SvgPicture.asset( - AppAssets.saudi_riyal_icon, + (Utils.appState.getAuthenticatedUser()!.outSa == 1) ? AppAssets.uae_dirham_symbol : AppAssets.saudi_riyal_icon, colorFilter: ColorFilter.mode(AppColors.blackBgColor, BlendMode.srcIn), width: 16.w, height: 16.h, ), + SizedBox(width: 4.h), + "1234".toText24( + isBold: true, + color: AppColors.blackBgColor, // Always use base color + ), ], ), SizedBox(height: 16.h), diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 16a955c8..b7fe686f 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -1,5 +1,6 @@ import 'dart:ui' as ui; +import 'package:clarity_flutter/clarity_flutter.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -405,64 +406,66 @@ class TextInputWidget extends StatelessWidget { child: Localizations.override( context: context, locale: const Locale('en', 'US'), // Force English locale for TextField - child: TextField( - hintLocales: const [Locale('en', 'US')], - enabled: isEnable, - scrollPadding: EdgeInsets.zero, - keyboardType: isMultiline - ? TextInputType.multiline - : (isWalletAmountInput! ? const TextInputType.numberWithOptions(decimal: true) : keyboardType), - controller: controller, - readOnly: isReadOnly, - textAlignVertical: TextAlignVertical.top, - textAlign: isArabic ? TextAlign.right : TextAlign.left, - textDirection: ui.TextDirection.ltr, - onChanged: onChange, - focusNode: focusNode ?? _focusNode, - autofocus: autoFocus, - textInputAction: TextInputAction.done, - cursorHeight: isWalletAmountInput! ? 40.h : 20.h, - maxLength: isWalletAmountInput! ? 7 : 100, - inputFormatters: isWalletAmountInput! - ? [ - _ThousandSeparatorInputFormatter(), - ] - : null, - onTapOutside: (event) { - FocusManager.instance.primaryFocus?.unfocus(); - }, - onSubmitted: onSubmitted, - minLines: isMultiline ? minLines : 1, - maxLines: isMultiline ? maxLines : 1, - style: TextStyle( - fontSize: fontS, - height: isMultiline ? 1.2 : (isWalletAmountInput! ? 1 / 4 : 0), - fontWeight: FontWeight.w600, - color: AppColors.textColor, - letterSpacing: -1, - fontFamily: fontFamily, - locale: const Locale('en', 'US'), // Force English locale for text style - ), - decoration: InputDecoration( - counterText: "", - isDense: true, - hintText: hintText, - hintStyle: TextStyle( - fontFamily: isArabic ? 'CairoArabic' : 'Poppins', - fontSize: 14.f, - height: 21 / 16, + child: ClarityUnmask( + child: TextField( + hintLocales: const [Locale('en', 'US')], + enabled: isEnable, + scrollPadding: EdgeInsets.zero, + keyboardType: isMultiline + ? TextInputType.multiline + : (isWalletAmountInput! ? const TextInputType.numberWithOptions(decimal: true) : keyboardType), + controller: controller, + readOnly: isReadOnly, + textAlignVertical: TextAlignVertical.top, + textAlign: isArabic ? TextAlign.right : TextAlign.left, + textDirection: ui.TextDirection.ltr, + onChanged: onChange, + focusNode: focusNode ?? _focusNode, + autofocus: autoFocus, + textInputAction: TextInputAction.done, + cursorHeight: isWalletAmountInput! ? 40.h : 20.h, + maxLength: isWalletAmountInput! ? 7 : 100, + inputFormatters: isWalletAmountInput! + ? [ + _ThousandSeparatorInputFormatter(), + ] + : null, + onTapOutside: (event) { + FocusManager.instance.primaryFocus?.unfocus(); + }, + onSubmitted: onSubmitted, + minLines: isMultiline ? minLines : 1, + maxLines: isMultiline ? maxLines : 1, + style: TextStyle( + fontSize: fontS, + height: isMultiline ? 1.2 : (isWalletAmountInput! ? 1 / 4 : 0), fontWeight: FontWeight.w600, - color: hintColor != null ? AppColors.textColor : Color(0xff898A8D), - letterSpacing: -0.75, + color: AppColors.textColor, + letterSpacing: -1, + fontFamily: fontFamily, + locale: const Locale('en', 'US'), // Force English locale for text style + ), + decoration: InputDecoration( + counterText: "", + isDense: true, + hintText: hintText, + hintStyle: TextStyle( + fontFamily: isArabic ? 'CairoArabic' : 'Poppins', + fontSize: 14.f, + height: 21 / 16, + fontWeight: FontWeight.w600, + color: hintColor != null ? AppColors.textColor : Color(0xff898A8D), + letterSpacing: -0.75, + ), + prefixIconConstraints: BoxConstraints(minWidth: 30.h), + prefixIcon: prefix == null ? null : "+${prefix!}".toText14(letterSpacing: -1, color: AppColors.textColor, isBold: true), + contentPadding: EdgeInsets.only(right: isArabic ? 10.w : 0), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + // Show red border when field has error - but we handle this in the parent Container + // The parent Container in build() already shows red border based on hasError flag ), - prefixIconConstraints: BoxConstraints(minWidth: 30.h), - prefixIcon: prefix == null ? null : "+${prefix!}".toText14(letterSpacing: -1, color: AppColors.textColor, isBold: true), - contentPadding: EdgeInsets.only(right: isArabic ? 10.w : 0), - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - // Show red border when field has error - but we handle this in the parent Container - // The parent Container in build() already shows red border based on hasError flag ), ), ),