Merge pull request 'offers_discounts' (#321) from offers_discounts into master

Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/321
pull/322/head
Haroon6138 3 weeks ago
commit a173dd3389

@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.preProd;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -99,29 +99,32 @@ class AuthenticationViewModel extends ChangeNotifier {
// Login screen errors
String? _nationalIdError;
String? get nationalIdError => _nationalIdError;
// Phone number errors (used in multiple screens)
String? _phoneNumberError;
String? get phoneNumberError => _phoneNumberError;
// Registration screen errors
String? _nameError;
String? get nameError => _nameError;
String? _emailError;
String? get emailError => _emailError;
String? _dobError;
String? get dobError => _dobError;
// Check if registration form has any errors (for container border)
bool get hasRegistrationFormError =>
_nationalIdError != null || _dobError != null;
bool get hasRegistrationFormError => _nationalIdError != null || _dobError != null;
// Check if ID and phone have errors (for family file container)
bool get hasIdAndPhoneError =>
_nationalIdError != null || _phoneNumberError != null;
bool get hasIdAndPhoneError => _nationalIdError != null || _phoneNumberError != null;
// Additional field errors for UAE registration step 2
String? _genderError;
@ -130,15 +133,13 @@ class AuthenticationViewModel extends ChangeNotifier {
// Getters for step 2 field errors (nameError and emailError already exist above)
String? get genderError => _genderError;
String? get maritalStatusError => _maritalStatusError;
String? get countryError => _countryError;
// Check if registration step 2 form has any errors (for container border)
bool get hasRegistrationStep2FormError =>
_nameError != null ||
_genderError != null ||
_maritalStatusError != null ||
_countryError != null;
bool get hasRegistrationStep2FormError => _nameError != null || _genderError != null || _maritalStatusError != null || _countryError != null;
// Clear all step 2 field errors
void clearAllStep2FieldErrors() {
@ -349,7 +350,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (nationalIdController.text.isEmpty) {
_nationalIdError = LocaleKeys.pleaseEnterAnationalID.tr();
notifyListeners();
return false; // Stop here, don't check phone yet
return false; // Stop here, don't check phone yet
}
// Step 2: Validate National ID format
@ -359,7 +360,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!Utils.isSAUDIIDValid(cleanedId)) {
_nationalIdError = LocaleKeys.enterValidNationalId.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
}
@ -368,13 +369,13 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!ValidationUtils.validateIqama(nationalIdController.text)) {
_nationalIdError = LocaleKeys.pleaseEnterAValidIqamaID.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
} else if (selectedCountrySignup == CountryEnum.unitedArabEmirates) {
if (!ValidationUtils.validateUaeNationalId(nationalIdController.text)) {
_nationalIdError = LocaleKeys.pleaseEnterAValidNationalID.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
}
@ -382,7 +383,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (phoneNumberController.text.isEmpty) {
_phoneNumberError = LocaleKeys.enterValidPhoneNumber.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
// Step 5: Validate phone number format based on country
@ -412,7 +413,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (nationalIdController.text.isEmpty) {
_nationalIdError = LocaleKeys.pleaseEnterAnationalID.tr();
notifyListeners();
return false; // Stop here, don't check other fields
return false; // Stop here, don't check other fields
}
// Step 2: Validate National ID format
@ -422,7 +423,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!Utils.isSAUDIIDValid(cleanedId)) {
_nationalIdError = LocaleKeys.enterValidNationalId.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
}
@ -431,13 +432,13 @@ class AuthenticationViewModel extends ChangeNotifier {
if (!ValidationUtils.validateIqama(nationalIdController.text)) {
_nationalIdError = LocaleKeys.pleaseEnterAValidIqamaID.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
} else if (selectedCountrySignup == CountryEnum.unitedArabEmirates) {
if (!ValidationUtils.validateUaeNationalId(nationalIdController.text)) {
_nationalIdError = LocaleKeys.pleaseEnterAValidNationalID.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
}
@ -445,7 +446,7 @@ class AuthenticationViewModel extends ChangeNotifier {
if (dobController.text.isEmpty || dob == null || dob!.isEmpty) {
_dobError = LocaleKeys.pleaseEnterAValidDateOfBirth.tr();
notifyListeners();
return false; // Stop here
return false; // Stop here
}
// Step 5: Only validate Terms if both National ID and DOB are valid
@ -458,7 +459,7 @@ class AuthenticationViewModel extends ChangeNotifier {
},
);
notifyListeners();
return false; // Stop here
return false; // Stop here
}
// All validations passed
@ -481,11 +482,27 @@ class AuthenticationViewModel extends ChangeNotifier {
_countryError = null;
// Step 1: Validate name (only for UAE users)
// if (isUserFromUAE()) {
// if (nameController.text.trim().isEmpty) {
// _nameError = isArabic ? "الرجاء إدخال الاسم الكامل" : "Please enter full name";
// notifyListeners();
// return false; // Stop here
// }
// }
if (isUserFromUAE()) {
if (nameController.text.trim().isEmpty) {
// Remove extra spaces between words
final fullName = nameController.text.trim().replaceAll(RegExp(r'\s+'), ' ');
// Split into words
final nameParts = fullName.split(' ');
// Require at least 2 words
if (nameParts.length < 2) {
_nameError = isArabic ? "الرجاء إدخال الاسم الكامل" : "Please enter full name";
notifyListeners();
return false; // Stop here
return false;
}
}
@ -603,7 +620,6 @@ class AuthenticationViewModel extends ChangeNotifier {
// Format for display (use Hijri)
dobController.text = Utils.formatHijriDateToDisplay(hijriDateTimeForController.toIso8601String());
} else {
// Gregorian calendar mode
// Validate the date can be parsed
@ -624,7 +640,6 @@ class AuthenticationViewModel extends ChangeNotifier {
clearDobError();
notifyListeners();
} catch (e, stackTrace) {
debugPrint('onDobChange: Unexpected error processing date "$date" - $e');
debugPrint('Stack trace: $stackTrace');
@ -768,7 +783,7 @@ class AuthenticationViewModel extends ChangeNotifier {
},
(apiResponse) {
// LoadingUtils.hideFullScreenLoader();
log("apiResponse: ${apiResponse.data.toString()}");
log("apiResponse: ${apiResponse.data?.toJson().toString()}");
log("messageStatus: ${apiResponse.messageStatus.toString()}");
if (apiResponse.messageStatus == 1) {
onSuccess(apiResponse.data);
@ -856,6 +871,9 @@ class AuthenticationViewModel extends ChangeNotifier {
nationId: nationalIdController.text,
isForRegister: false,
patientOutSA: false,
// patientOutSA: selectedCountrySignup == CountryEnum.others
// ? false
// : (_appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? true : false),
otpTypeEnum: otpTypeEnum,
patientId: 0,
zipCode: selectedCountrySignup == CountryEnum.others
@ -889,7 +907,10 @@ class AuthenticationViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['isSMSSent']) {
_appState.setAppAuthToken = apiResponse.data['LogInTokenID'];
await sendActivationCode(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumberController.text, nationalIdOrFileNumber: nationalIdController.text, isForRegister: false);
print("============================");
var zipcode = getZipCode();
print("======== Zip Code =========== $zipcode ========");
await sendActivationCode(otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumberController.text, nationalIdOrFileNumber: nationalIdController.text, isForRegister: false, zipCode: zipcode);
} else {
if (apiResponse.data['IsAuthenticated']) {
await checkActivationCode(
@ -911,6 +932,14 @@ class AuthenticationViewModel extends ChangeNotifier {
);
}
String getZipCode() {
return selectedCountrySignup == CountryEnum.others
? "0"
: (_appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true
? CountryEnum.unitedArabEmirates.countryCode.toString()
: selectedCountrySignup.countryCode.toString());
}
Future<void> sendActivationCode(
{required OTPTypeEnum otpTypeEnum,
required String nationalIdOrFileNumber,
@ -921,12 +950,13 @@ class AuthenticationViewModel extends ChangeNotifier {
bool isExcludedUser = false,
bool isFormFamilyFile = false,
bool isNeedLoading = false,
int? responseID}) async {
int? responseID,
String? zipCode}) async {
var request = RequestUtils.getCommonRequestSendActivationCode(
otpTypeEnum: otpTypeEnum,
mobileNumber: phoneNumber,
selectedLoginType: otpTypeEnum.toInt(),
zipCode: selectedCountrySignup.countryCode,
zipCode: zipCode ?? selectedCountrySignup.countryCode,
nationalId: nationalIdOrFileNumber,
isFileNo: isForRegister ? isPatientHasFile(request: payload) : false,
patientId: isFormFamilyFile ? _appState.getAuthenticatedUser()!.patientId : 0,
@ -983,6 +1013,7 @@ class AuthenticationViewModel extends ChangeNotifier {
navigateToOTPScreen(
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumber,
zipCode: zipCode ?? "",
isComingFromRegister: checkIsUserComingForRegister(request: payload),
payload: payload,
isFormFamilyFile: isFormFamilyFile,
@ -1308,10 +1339,12 @@ class AuthenticationViewModel extends ChangeNotifier {
bool isFormFamilyFile = false,
bool isExcludedUser = false,
int? responseID,
int? patientShareRequestID}) async {
int? patientShareRequestID,
required String zipCode}) async {
_navigationService.pushToOtpScreen(
phoneNumber: phoneNumber,
isFormFamilyFile: isFormFamilyFile,
zipCode: zipCode,
checkActivationCode: (int activationCode) async {
await checkActivationCode(
activationCode: activationCode.toString(),
@ -1324,18 +1357,18 @@ class AuthenticationViewModel extends ChangeNotifier {
},
);
},
onResendOTPPressed: (String phoneNumber) async {
onResendOTPPressed: (String phoneNumber, String zipCode) async {
await sendActivationCode(
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text,
isForRegister: isComingFromRegister,
isComingFromResendOTP: true,
payload: payload,
isFormFamilyFile: isFormFamilyFile,
isExcludedUser: isExcludedUser,
responseID: responseID,
);
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text,
isForRegister: isComingFromRegister,
isComingFromResendOTP: true,
payload: payload,
isFormFamilyFile: isFormFamilyFile,
isExcludedUser: isExcludedUser,
responseID: responseID,
zipCode: zipCode);
},
);
}

@ -427,12 +427,12 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
class OTPVerificationScreen extends StatefulWidget {
final String phoneNumber;
final String zipCode;
final Function(int code) checkActivationCode;
final Function(String phoneNumber) onResendOTPPressed;
final Function(String phoneNumber, String zipCode) onResendOTPPressed;
final bool isFormFamilyFile;
const OTPVerificationScreen(
{super.key, required this.phoneNumber, required this.checkActivationCode, required this.onResendOTPPressed, required this.isFormFamilyFile});
const OTPVerificationScreen({super.key, required this.phoneNumber, required this.zipCode, required this.checkActivationCode, required this.onResendOTPPressed, required this.isFormFamilyFile});
@override
State<OTPVerificationScreen> createState() => _OTPVerificationScreenState();
@ -452,7 +452,7 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
super.initState();
_otpController = TextEditingController();
_startResendTimer();
if(Platform.isAndroid) {
if (Platform.isAndroid) {
checkSignature();
}
}
@ -521,7 +521,7 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
});
_otpController.clear();
_startResendTimer();
widget.onResendOTPPressed(widget.phoneNumber);
widget.onResendOTPPressed(widget.phoneNumber, widget.zipCode);
}
}
@ -584,12 +584,7 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
pinBoxColor: AppColors.whiteColor,
autoFocus: true,
onTextChanged: _onOtpChanged,
pinTextStyle: TextStyle(
fontSize: 40.f,
fontWeight: FontWeight.bold,
color: AppColors.whiteColor,
fontFamily: "Poppins"
),
pinTextStyle: TextStyle(fontSize: 40.f, fontWeight: FontWeight.bold, color: AppColors.whiteColor, fontFamily: "Poppins"),
),
),
),

@ -781,6 +781,7 @@ class HmgServicesViewModel extends ChangeNotifier {
navigationService.pushToOtpScreen(
phoneNumber: phoneNumber,
isFormFamilyFile: false,
zipCode: "",
checkActivationCode: (int activationCode) async {
checkEReferralActivationCode(
requestModel: CheckActivationCodeForEReferralRequestModel(
@ -795,7 +796,7 @@ class HmgServicesViewModel extends ChangeNotifier {
},
);
},
onResendOTPPressed: (String phoneNumber) async {
onResendOTPPressed: (String phoneNumber, String zipCode) async {
// await sendActivationCode(
// otpTypeEnum: otpTypeEnum,
// phoneNumber: phoneNumberController.text,

@ -42,15 +42,12 @@ class _RegisterNew extends State<RegisterNewStep2> {
WidgetsBinding.instance.addPostFrameCallback((_) {
authVM?.clearAllStep2FieldErrors();
});
// 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");
});
if (!authVM!.isUserFromUAE()) {
WidgetsBinding.instance.addPostFrameCallback((_) {
insuranceVM?.setIsInsuranceDataToBeLoaded(true);
insuranceVM?.initInsuranceProvider();
});
}
}
@override
@ -188,254 +185,256 @@ class _RegisterNew extends State<RegisterNewStep2> {
),
padding: EdgeInsets.only(left: 16.h, right: 16.h),
child: Column(
children: [
TextInputWidget(
labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr(context: context) : LocaleKeys.name.tr(context: context),
hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr(context: context) : (name),
controller: authVM!.isUserFromUAE() ? authVM!.nameController : null,
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
// textInputAction: TextInputAction.done,
onSubmitted: (value) {
FocusScope.of(context).unfocus();
},
onChange: (value) {
// Clear error when user starts typing
authVM!.clearNameError();
},
isAllowLeadingIcon: true,
isReadOnly: authVM!.isUserFromUAE() ? false : true,
leadingIcon: AppAssets.user_circle,
labelColor: AppColors.textColor,
).paddingSymmetrical(0.h, 8.h),
// Show error message if exists
if (authVM!.isUserFromUAE() && authVM!.nameError != null)
Padding(
padding: EdgeInsets.only(left: 52.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.nameError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
TextInputWidget(
labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr(context: context) : LocaleKeys.name.tr(context: context),
hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr(context: context) : (name),
controller: authVM!.isUserFromUAE() ? authVM!.nameController : null,
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
// hintColor: Color(0xff898A8D),
keyboardType: TextInputType.text,
onSubmitted: (value) {
FocusScope.of(context).unfocus();
},
onChange: (value) {
authVM!.clearNameError();
},
isAllowLeadingIcon: true,
isReadOnly: authVM!.isUserFromUAE() ? false : true,
leadingIcon: AppAssets.user_circle,
labelColor: AppColors.textColor,
).paddingSymmetrical(0.h, 8.h),
// Show error message if exists
if (authVM!.isUserFromUAE() && authVM!.nameError != null)
Padding(
padding: EdgeInsets.only(left: 0.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.nameError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
),
),
),
),
),
Divider(height: 1.h, color: AppColors.greyColor),
TextInputWidget(
labelText: LocaleKeys.nationalIdNumber.tr(context: context),
hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.patientIdentificationId.toString() : (appState.getNHICUserData.idNumber ?? ""),
controller: null,
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.student_card)
.paddingSymmetrical(0.h, 8.h),
Divider(height: 1, color: AppColors.greyColor),
authVM!.isUserFromUAE()
? Selector<AuthenticationViewModel, GenderTypeEnum?>(
selector: (_, authViewModel) => authViewModel.genderType,
shouldRebuild: (previous, next) => previous != next,
builder: (context, genderType, child) {
final authVM = context.read<AuthenticationViewModel>();
return DropdownWidget(
labelText: LocaleKeys.gender.tr(context: context),
hintText: LocaleKeys.malE.tr(context: context),
isEnable: true,
dropdownItems: GenderTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: genderType != null ? (appState.isArabic() ? genderType.typeAr : genderType.type) : "",
onChange: authVM.onGenderChange,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
isAllowRadius: false,
labelColor: AppColors.textColor,
padding: EdgeInsets.only(top: 8.h, bottom: 8.h, left: 0, right: 0),
selectionCustomIcon: AppAssets.arrow_down,
leadingIcon: AppAssets.user_full,
).withVerticalPadding(8);
})
: TextInputWidget(
labelText: LocaleKeys.gender.tr(context: context),
hintText: (appState.getNHICUserData.gender ?? ""),
Divider(height: 1.h, color: AppColors.greyColor),
TextInputWidget(
labelText: LocaleKeys.nationalIdNumber.tr(context: context),
hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.patientIdentificationId.toString() : (appState.getNHICUserData.idNumber ?? ""),
controller: null,
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: authVM!.isUserFromUAE() ? false : true,
leadingIcon: AppAssets.user_full,
labelColor: AppColors.textColor,
onChange: (value) {})
.paddingSymmetrical(0.h, 8.h),
// Show gender error message if exists (for UAE users)
if (authVM!.isUserFromUAE() && authVM!.genderError != null)
Padding(
padding: EdgeInsets.only(left: 52.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.genderError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
),
),
),
Divider(height: 1, color: AppColors.greyColor),
authVM!.isUserFromUAE()
? Selector<AuthenticationViewModel, MaritalStatusTypeEnum?>(
selector: (_, authViewModel) => authViewModel.maritalStatus,
shouldRebuild: (previous, next) => previous != next,
builder: (context, maritalStatus, child) {
final authVM = context.read<AuthenticationViewModel>(); // For onChange
return DropdownWidget(
labelText: LocaleKeys.maritalStatus.tr(context: context),
hintText: LocaleKeys.married.tr(context: context),
isEnable: true,
dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: maritalStatus != null ? (appState.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "",
onChange: authVM.onMaritalStatusChange,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
isAllowRadius: false,
labelColor: AppColors.textColor,
padding: EdgeInsets.only(top: 8.h, bottom: 8.h, left: 0, right: 0),
selectionCustomIcon: AppAssets.arrow_down,
leadingIcon: AppAssets.smart_phone,
).withVerticalPadding(8);
},
)
: TextInputWidget(
labelText: LocaleKeys.maritalStatus.tr(context: context),
hintText: appState.isArabic()
? (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)?.typeAr ?? '')
: (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)?.type ?? ''),
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.smart_phone,
onChange: (value) {})
leadingIcon: AppAssets.student_card)
.paddingSymmetrical(0.h, 8.h),
// Show marital status error message if exists (for UAE users)
if (authVM!.isUserFromUAE() && authVM!.maritalStatusError != null)
Padding(
padding: EdgeInsets.only(left: 52.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.maritalStatusError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
Divider(height: 1, color: AppColors.greyColor),
authVM!.isUserFromUAE()
? Selector<AuthenticationViewModel, GenderTypeEnum?>(
selector: (_, authViewModel) => authViewModel.genderType,
shouldRebuild: (previous, next) => previous != next,
builder: (context, genderType, child) {
final authVM = context.read<AuthenticationViewModel>();
return DropdownWidget(
labelText: LocaleKeys.gender.tr(context: context),
hintText: LocaleKeys.malE.tr(context: context),
isEnable: true,
dropdownItems: GenderTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: genderType != null ? (appState.isArabic() ? genderType.typeAr : genderType.type) : "",
onChange: authVM.onGenderChange,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
isAllowRadius: false,
labelColor: AppColors.textColor,
padding: EdgeInsets.only(top: 8.h, bottom: 8.h, left: 0, right: 0),
selectionCustomIcon: AppAssets.arrow_down,
leadingIcon: AppAssets.user_full,
).withVerticalPadding(8);
})
: TextInputWidget(
labelText: LocaleKeys.gender.tr(context: context),
hintText: (appState.getNHICUserData.gender ?? ""),
controller: null,
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: authVM!.isUserFromUAE() ? false : true,
leadingIcon: AppAssets.user_full,
labelColor: AppColors.textColor,
onChange: (value) {})
.paddingSymmetrical(0.h, 8.h),
// Show gender error message if exists (for UAE users)
if (authVM!.isUserFromUAE() && authVM!.genderError != null)
Padding(
padding: EdgeInsets.only(left: 0.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.genderError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
),
),
),
Divider(height: 1, color: AppColors.greyColor),
authVM!.isUserFromUAE()
? Selector<AuthenticationViewModel, MaritalStatusTypeEnum?>(
selector: (_, authViewModel) => authViewModel.maritalStatus,
shouldRebuild: (previous, next) => previous != next,
builder: (context, maritalStatus, child) {
final authVM = context.read<AuthenticationViewModel>(); // For onChange
return DropdownWidget(
labelText: LocaleKeys.maritalStatus.tr(context: context),
hintText: LocaleKeys.married.tr(context: context),
isEnable: true,
dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(),
selectedValue: maritalStatus != null ? (appState.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "",
onChange: authVM.onMaritalStatusChange,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
isAllowRadius: false,
labelColor: AppColors.textColor,
padding: EdgeInsets.only(top: 8.h, bottom: 8.h, left: 0, right: 0),
selectionCustomIcon: AppAssets.arrow_down,
leadingIcon: AppAssets.smart_phone,
).withVerticalPadding(8);
},
)
: TextInputWidget(
labelText: LocaleKeys.maritalStatus.tr(context: context),
hintText: appState.isArabic()
? (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)?.typeAr ?? '')
: (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)?.type ?? ''),
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.smart_phone,
onChange: (value) {})
.paddingSymmetrical(0.h, 8.h),
// Show marital status error message if exists (for UAE users)
if (authVM!.isUserFromUAE() && authVM!.maritalStatusError != null)
Padding(
padding: EdgeInsets.only(left: 0.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.maritalStatusError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
),
),
),
Divider(height: 1.h, color: AppColors.greyColor),
authVM!.isUserFromUAE()
? Selector<AuthenticationViewModel, ({List<NationalityCountries>? countriesList, NationalityCountries? selectedCountry, bool isArabic})>(
selector: (context, authViewModel) {
final appState = getIt.get<AppState>();
return (
countriesList: authViewModel.countriesList,
selectedCountry: authViewModel.pickedCountryByUAEUser,
isArabic: appState.isArabic(),
);
},
shouldRebuild: (previous, next) =>
previous.countriesList != next.countriesList || previous.selectedCountry != next.selectedCountry || previous.isArabic != next.isArabic,
builder: (context, data, child) {
final authVM = context.read<AuthenticationViewModel>();
return DropdownWidget(
labelText: LocaleKeys.country.tr(context: context),
hintText: LocaleKeys.uae.tr(context: context),
isEnable: true,
dropdownItems: (data.countriesList ?? []).map((e) => data.isArabic ? e.nameN ?? "" : e.name ?? "").toList(),
selectedValue: data.selectedCountry != null
? data.isArabic
? data.selectedCountry!.nameN ?? ""
: data.selectedCountry!.name ?? ""
: "",
onChange: authVM.onUAEUserCountrySelection,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
labelColor: AppColors.textColor,
isAllowRadius: false,
padding: EdgeInsets.only(top: 8.h, bottom: 8.h, left: 0, right: 0),
selectionCustomIcon: AppAssets.arrow_down,
leadingIcon: AppAssets.globe,
).withVerticalPadding(8.h);
},
)
: TextInputWidget(
labelText: LocaleKeys.nationality.tr(context: context),
hintText: appState.isArabic()
? (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "")
: (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""),
isEnable: true,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.globe,
onChange: (value) {})
.paddingSymmetrical(0.h, 8.h),
// Show country error message if exists (for UAE users)
if (authVM!.isUserFromUAE() && authVM!.countryError != null)
Padding(
padding: EdgeInsets.only(left: 0.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.countryError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
),
),
),
Divider(
height: 1,
color: AppColors.greyColor,
),
),
Divider(height: 1.h, color: AppColors.greyColor),
authVM!.isUserFromUAE()
? Selector<AuthenticationViewModel, ({List<NationalityCountries>? countriesList, NationalityCountries? selectedCountry, bool isArabic})>(
selector: (context, authViewModel) {
final appState = getIt.get<AppState>();
return (
countriesList: authViewModel.countriesList,
selectedCountry: authViewModel.pickedCountryByUAEUser,
isArabic: appState.isArabic(),
);
},
shouldRebuild: (previous, next) => previous.countriesList != next.countriesList || previous.selectedCountry != next.selectedCountry || previous.isArabic != next.isArabic,
builder: (context, data, child) {
final authVM = context.read<AuthenticationViewModel>();
return DropdownWidget(
labelText: LocaleKeys.country.tr(context: context),
hintText: LocaleKeys.uae.tr(context: context),
isEnable: true,
dropdownItems: (data.countriesList ?? []).map((e) => data.isArabic ? e.nameN ?? "" : e.name ?? "").toList(),
selectedValue: data.selectedCountry != null
? data.isArabic
? data.selectedCountry!.nameN ?? ""
: data.selectedCountry!.name ?? ""
: "",
onChange: authVM.onUAEUserCountrySelection,
isBorderAllowed: false,
hasSelectionCustomIcon: true,
labelColor: AppColors.textColor,
isAllowRadius: false,
padding: EdgeInsets.only(top: 8.h, bottom: 8.h, left: 0, right: 0),
selectionCustomIcon: AppAssets.arrow_down,
leadingIcon: AppAssets.globe,
).withVerticalPadding(8.h);
},
)
: TextInputWidget(
labelText: LocaleKeys.nationality.tr(context: context),
hintText: appState.isArabic()
? (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "")
: (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""),
isEnable: true,
TextInputWidget(
labelText: LocaleKeys.mobileNumber.tr(context: context),
hintText: appState.getUserRegistrationPayload.patientMobileNumber.toString(),
controller: null,
isEnable: false,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.globe,
onChange: (value) {})
isReadOnly: true,
leadingIcon: AppAssets.call)
.paddingSymmetrical(0.h, 8.h),
// Show country error message if exists (for UAE users)
if (authVM!.isUserFromUAE() && authVM!.countryError != null)
Padding(
padding: EdgeInsets.only(left: 52.w, top: 4.h, bottom: 4.h, right: 16.w),
child: Text(
authVM!.countryError!,
style: TextStyle(
color: AppColors.primaryRedColor,
fontSize: 12.f,
),
Divider(
height: 1.h,
color: AppColors.greyColor,
),
),
Divider(
height: 1,
color: AppColors.greyColor,
),
TextInputWidget(
labelText: LocaleKeys.mobileNumber.tr(context: context),
hintText: appState.getUserRegistrationPayload.patientMobileNumber.toString(),
controller: null,
isEnable: false,
prefix: null,
isAllowRadius: false,
isBorderAllowed: false,
isAllowLeadingIcon: true,
labelColor: AppColors.textColor,
isReadOnly: true,
leadingIcon: AppAssets.call)
.paddingSymmetrical(0.h, 8.h),
Divider(
height: 1.h,
color: AppColors.greyColor,
TextInputWidget(
labelText: LocaleKeys.dob.tr(context: context),
hintText: authVM!.isUserFromUAE() ? (appState.getUserRegistrationPayload.dob ?? '') : (appState.getNHICUserData.dateOfBirth ?? ""),
controller: authVM!.isUserFromUAE() ? authVM!.dobController : null,
isEnable: false,
prefix: null,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.birthday_cake,
selectionType: null,
).paddingSymmetrical(0.h, 8.h),
],
),
TextInputWidget(
labelText: LocaleKeys.dob.tr(context: context),
hintText: authVM!.isUserFromUAE() ? (appState.getUserRegistrationPayload.dob ?? '') : (appState.getNHICUserData.dateOfBirth ?? ""),
controller: authVM!.isUserFromUAE() ? authVM!.dobController : null,
isEnable: false,
prefix: null,
isBorderAllowed: false,
isAllowLeadingIcon: true,
isReadOnly: true,
labelColor: AppColors.textColor,
leadingIcon: AppAssets.birthday_cake,
selectionType: null,
).paddingSymmetrical(0.h, 8.h),
],
),
);
);
},
),
SizedBox(height: 50.h),

@ -87,14 +87,12 @@ class _SavedLogin extends State<SavedLogin> {
LocaleKeys.welcomeBack.tr().toText16(color: AppColors.inputLabelTextColor),
SizedBox(height: 16.h),
appState.getSelectDeviceByImeiRespModelElement != null
? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase
.toText26(isBold: true, height: 26 / 36, color: AppColors.textColor, isEnglishOnly: true)
? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase.toText26(isBold: true, height: 26 / 36, color: AppColors.textColor, isEnglishOnly: true)
: SizedBox(),
SizedBox(height: 24.h),
Container(
padding: EdgeInsets.all(16.h),
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, isCustomShadow: [
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, isCustomShadow: [
BoxShadow(color: Color(0x0D000000), blurRadius: 16.h, offset: Offset(0, 0), spreadRadius: 5.h),
]),
child: Column(
@ -106,9 +104,7 @@ class _SavedLogin extends State<SavedLogin> {
textDirection: ui.TextDirection.ltr,
child: appState.getSelectDeviceByImeiRespModelElement != null
? (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null
? DateUtil.getFormattedDate(
DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!),
"d MMMM, y 'at' HH:mm")
? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm")
: '--')
.toText16(isBold: true, color: AppColors.textColor, isEnglishOnly: true)
: SizedBox(),
@ -118,14 +114,10 @@ class _SavedLogin extends State<SavedLogin> {
? Container(
margin: EdgeInsets.all(16.h),
child: Utils.buildSvgWithAssets(
icon: (isOther == true && loginType == LoginTypeEnum.sms)
? AppAssets.whatsapp
: getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!),
icon: (isOther == true && loginType == LoginTypeEnum.sms) ? AppAssets.whatsapp : getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!),
height: 54.h,
width: 54.w,
iconColor: (isOther == true && loginType == LoginTypeEnum.sms) || loginType.toInt == 4
? null
: AppColors.primaryRedColor))
iconColor: (isOther == true && loginType == LoginTypeEnum.sms) || loginType.toInt == 4 ? null : AppColors.primaryRedColor))
: SizedBox(),
// Main login button - for isOther with SMS, show WhatsApp, otherwise keep original login type
CustomButton(
@ -138,9 +130,7 @@ class _SavedLogin extends State<SavedLogin> {
} else {
// For isOther with SMS, use WhatsApp; otherwise use the original login type
authVm.checkUserAuthentication(
otpTypeEnum: (isOther == true && loginType == LoginTypeEnum.sms)
? OTPTypeEnum.whatsapp
: (loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp),
otpTypeEnum: (isOther == true && loginType == LoginTypeEnum.sms) ? OTPTypeEnum.whatsapp : (loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp),
);
}
},
@ -153,8 +143,7 @@ class _SavedLogin extends State<SavedLogin> {
height: 44.h,
padding: EdgeInsets.symmetric(vertical: 10.h),
icon: (isOther == true && loginType == LoginTypeEnum.sms) ? AppAssets.whatsapp : getTypeIcons(loginType.toInt),
iconColor:
(isOther == true && loginType == LoginTypeEnum.sms) || loginType == LoginTypeEnum.whatsapp ? null : Colors.white,
iconColor: (isOther == true && loginType == LoginTypeEnum.sms) || loginType == LoginTypeEnum.whatsapp ? null : Colors.white,
),
],
),
@ -189,13 +178,13 @@ class _SavedLogin extends State<SavedLogin> {
backgroundColor: Colors.transparent,
enableDrag: false,
// Prevent dragging to avoid focus conflicts
builder: (bottomSheetContext) =>
StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) {
builder: (bottomSheetContext) => StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) {
return Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom),
child: SingleChildScrollView(
child: GenericBottomSheet(
countryCode: "966",
countryCode: appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? "971" : "966",
// countryCode: "966",
initialPhoneNumber: "",
textController: TextEditingController(),
isFromSavedLogin: true,
@ -221,9 +210,7 @@ class _SavedLogin extends State<SavedLogin> {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.h),
child: (LocaleKeys.oR.tr()).toText16(color: AppColors.textColor)),
Padding(padding: EdgeInsets.symmetric(horizontal: 8.h), child: (LocaleKeys.oR.tr()).toText16(color: AppColors.textColor)),
],
),
Padding(

@ -58,10 +58,10 @@ class NavigationService {
}
Future<T?> pushToOtpScreen<T>(
{required String phoneNumber, required Function(int code) checkActivationCode, required Function(String phoneNumber) onResendOTPPressed, bool isFormFamilyFile = false}) {
{required String phoneNumber, required String zipCode, required Function(int code) checkActivationCode, required Function(String phoneNumber, String zipCode) onResendOTPPressed, bool isFormFamilyFile = false}) {
return navigatorKey.currentState!.push(
MaterialPageRoute(
builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed, isFormFamilyFile: isFormFamilyFile)),
builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, zipCode: zipCode, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed, isFormFamilyFile: isFormFamilyFile)),
);
}

@ -21,6 +21,7 @@ class DropdownWidget extends StatelessWidget {
final Color? labelColor;
final String? errorMessage;
final bool? hasError;
const DropdownWidget(
{Key? key,
required this.labelText,
@ -37,8 +38,7 @@ class DropdownWidget extends StatelessWidget {
this.leadingIcon,
this.labelColor,
this.errorMessage,
this.hasError =false
})
this.hasError = false})
: super(key: key);
@override
@ -46,32 +46,33 @@ class DropdownWidget extends StatelessWidget {
Widget content = Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [_buildLabelText(labelColor), _buildDropdown(context),],
children: [
_buildLabelText(labelColor),
_buildDropdown(context),
],
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Container(
padding: padding,
alignment: Alignment.center, // This might need adjustment based on layout
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Container(
padding: padding,
alignment: Alignment.center, // This might need adjustment based on layout
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: isAllowRadius ? 15.h : null,
side: isBorderAllowed ? BorderSide(color: hasError! ? Colors.red: const Color(0xffefefef), width: 1) : null,
),
child: Row(
// Wrap with a Row
crossAxisAlignment: CrossAxisAlignment.center, // Align items vertically in the center
children: [
if (leadingIcon != null) ...[
_buildLeadingIcon(),
SizedBox(width: 3.h),
side: isBorderAllowed ? BorderSide(color: hasError! ? Colors.red : const Color(0xffefefef), width: 1) : null,
),
child: Row(
// Wrap with a Row
crossAxisAlignment: CrossAxisAlignment.center, // Align items vertically in the center
children: [
if (leadingIcon != null) ...[
_buildLeadingIcon(),
SizedBox(width: 3.h),
],
Expanded(child: content),
],
Expanded(child: content),
],
),
),
),
if (hasError! && errorMessage != null)
Padding(
padding: EdgeInsets.only(top: 4.h, left: 12.h), // Adjust padding as needed
@ -82,16 +83,17 @@ class DropdownWidget extends StatelessWidget {
fontSize: 12.f,
),
),
)]);
)
]);
}
Widget _buildLeadingIcon() {
return Container(
height: 40.h,
width: 40.h,
margin: EdgeInsets.only(right: 10.h),
padding: EdgeInsets.all(8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h, color: AppColors.greyColor),
height: 40.h,
width: 40.h,
margin: EdgeInsets.only(right: 10.h),
padding: EdgeInsets.all(8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h, color: AppColors.greyColor),
child: Utils.buildSvgWithAssets(icon: leadingIcon!),
);
}
@ -116,35 +118,26 @@ class DropdownWidget extends StatelessWidget {
final renderBox = context.findRenderObject() as RenderBox;
final offset = renderBox.localToGlobal(Offset.zero);
final selected = await showMenu<String>(
context: context,
position: RelativeRect.fromLTRB(
offset.dx,
offset.dy + renderBox.size.height,
offset.dx + renderBox.size.width,
0,
),
items: dropdownItems
.map(
(e) => PopupMenuItem<String>(
value: e,
child: Text(
e,
style: TextStyle(
fontSize: 14.f,
height: 21 / 14,
fontWeight: FontWeight.w600,
letterSpacing: -0.2,
context: context,
position: RelativeRect.fromLTRB(
offset.dx,
offset.dy + renderBox.size.height,
offset.dx + renderBox.size.width,
0,
),
items: dropdownItems
.map(
(e) => PopupMenuItem<String>(
value: e,
child: Text(
e,
style: TextStyle(color: AppColors.textColor, fontSize: 14.f, height: 21 / 14, fontWeight: FontWeight.w600, letterSpacing: -0.2),
),
),
),
)
.toList(),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
color: Colors.black
);
)
.toList(),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
color: AppColors.whiteColor);
if (selected != null && onChange != null) {
onChange!(selected);
@ -165,7 +158,7 @@ class DropdownWidget extends StatelessWidget {
height: 21 / 14,
fontWeight: FontWeight.w600,
// color: (selectedValue != null && selectedValue!.isNotEmpty) ? const Color(0xff2E3039) : const Color(0xffB0B0B0),
color: AppColors.textColor,
color: (selectedValue == null || selectedValue!.isEmpty) ? AppColors.inputLabelTextColor :AppColors.textColor,
letterSpacing: -0.2,
),
),

Loading…
Cancel
Save