Merge branch 'refs/heads/master' into offers_discounts

offers_discounts
Aamir Muhammad 2 days ago
commit 1d9783a5b3

@ -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;

@ -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<AppState>().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<AppState>().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<AppState>().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),

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

@ -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;

@ -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<AppState>().getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
"language": "en",
"language": getIt.get<AppState>().isArabic() ? "ar" : "en",
"customer_email": "CustID_$fileNumber@HMG.com",
"sdk_token": sdkTokenResponse!.sdkToken,
"customer_name": "${getIt.get<AppState>().getAuthenticatedUser()!.firstName} ${getIt.get<AppState>().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<String, dynamic>();
paymentMap["message"] = e.details["response_message"] ?? "Payment failed with unknown error.";
onFailed(PayFortFailureResult.fromMap(paymentMap));
}
} catch (error) {
print("Generic Error: $error");
}

@ -65,7 +65,7 @@ class PayTabsViewModel extends ChangeNotifier {
"12626"),
alternativePaymentMethods: [],
linkBillingNameWithCardHolderName: true,
simplifyApplePayValidation: false,
simplifyApplePayValidation: true,
);
paymentConfiguration.iOSThemeConfigurations = IOSThemeConfigurations(

@ -23,10 +23,14 @@ class WeatherMonitorViewModel extends ChangeNotifier {
final List<GetCityInfoList> _cityInfoList = [];
bool isLoading = false;
bool isWeatherNeedToLoad = true;
List<GetCityInfoList> get cityInfoList => _cityInfoList;
Future<void> 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<AppState>().userLat != 0.0 && getIt.get<AppState>().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;
}
},
);

@ -69,11 +69,13 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
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) {

@ -26,6 +26,8 @@ class AppointmentQueuePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
appState = getIt.get<AppState>();
final currentQueue = getIt.get<MyAppointmentsViewModel>().currentPatientQueueDetails;
final currentStatus = getIt.get<MyAppointmentsViewModel>().currentQueueStatus;
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<MyAppointmentsViewModel>(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)),
],
),
),

@ -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<HabibWalletViewModel>().setIsWalletAmountToBeLoaded(true);
getIt.get<HabibWalletViewModel>().initHabibWalletProvider();
getIt.get<HabibWalletViewModel>().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,

@ -94,27 +94,29 @@ class LoginScreenState extends State<LoginScreen> {
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<LoginScreen> {
child: SingleChildScrollView(
child: Consumer<AuthenticationViewModel>(
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,
),
),
],
],
),
);
},
),

@ -63,11 +63,13 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
myAppointmentsViewModel.getTamaraInstallmentsDetails().then((val) {
if (num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!) >= 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;
});
}
}
});
});

@ -432,8 +432,15 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
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 {

@ -194,7 +194,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
payfortViewModel.initiatePaymentWithCard(
transactionID: transID,
fileNumber: appState.getAuthenticatedUser()!.patientId.toString(),
amount: myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString(),
amount: bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString(),
onSucceeded: (paymentResult) async {
print("Payment Success Data: ${paymentResult.toString()}");
LoaderBottomSheet.hideLoader();
@ -338,7 +338,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
payfortViewModel.initiatePaymentWithCard(
transactionID: transID,
fileNumber: appState.getAuthenticatedUser()!.patientId.toString(),
amount: myAppointmentsViewModel.patientAppointmentShareResponseModel!.patientShareWithTax!.toString(),
amount: bookAppointmentsViewModel.patientWalkInAppointmentShareResponseModel!.patientShareWithTax!.toString(),
onSucceeded: (paymentResult) async {
print("Payment Success Data: ${paymentResult.toString()}");
LoaderBottomSheet.hideLoader();

@ -149,7 +149,8 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
),
),
const Spacer(),
LocaleKeys.sar.tr(context: context).toText20(color: AppColors.greyTextColor, isBold: true),
((getIt.get<AppState>().getAuthenticatedUser()!.outSa == 1) ? LocaleKeys.aed.tr(context: context) : LocaleKeys.sar.tr(context: context))
.toText20(color: AppColors.greyTextColor, isBold: true),
],
),
],

@ -544,7 +544,7 @@ class _ServicesPageState extends State<ServicesPage> {
return Row(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.saudi_riyal_icon,
icon: (getIt.get<AppState>().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<ServicesPage> {
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),
],
);

@ -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<LandingPage> {
}
if (appState.isAuthenticated) {
Clarity.setCustomUserId(appState.getAuthenticatedUser()!.patientId.toString());
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
habibWalletVM.getLakumAccountInformation();
@ -1110,7 +1113,7 @@ class _LandingPageState extends State<LandingPage> {
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<LandingPage> {
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<LandingPage> {
}
// 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<LandingPage> {
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,

@ -91,7 +91,7 @@ class HabibWalletCard extends StatelessWidget {
Row(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.saudi_riyal_icon,
icon: (getIt.get<AppState>().getAuthenticatedUser()!.outSa == 1) ? AppAssets.uae_dirham_symbol : AppAssets.saudi_riyal_icon,
iconColor: AppColors.inputLabelTextColor,
width: 24.h,
height: 24.h,

@ -1226,10 +1226,13 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
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),
],

@ -53,7 +53,9 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
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<MedicalFileViewModel>(builder: (context, model, child) {
return Column(

@ -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,

@ -444,7 +444,7 @@ class _FamilyCardsState extends State<FamilyCards> {
// 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<FamilyCards> {
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<FamilyCards> {
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<FamilyCards> {
// 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)

@ -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,
),
),
],

@ -417,17 +417,17 @@ class _AccessibilityPageState extends State<AccessibilityPage> {
// 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),

@ -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
),
),
),

Loading…
Cancel
Save