other country login done.

dev_sultan
Sultan khan 2 weeks ago
parent 80adf1bd2f
commit 4f303d8496

@ -814,6 +814,7 @@
"ready": "جاهز", "ready": "جاهز",
"enterValidNationalId": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح", "enterValidNationalId": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح",
"enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح", "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح",
"cannotEnterSaudiOrUAENumber": "لا يمكنك إدخال أرقام هواتف السعودية (00966) أو الإمارات (00971) عند اختيار دولة 'أخرى'",
"medicalCentersWithCount": "{count} مراكز طبية", "medicalCentersWithCount": "{count} مراكز طبية",
"medicalCenters": "مراكز طبية", "medicalCenters": "مراكز طبية",
"hospitalsWithCount": "{count} مستشفيات", "hospitalsWithCount": "{count} مستشفيات",

@ -804,6 +804,7 @@
"awaitingApproval": "Awaiting Approval", "awaitingApproval": "Awaiting Approval",
"enterValidNationalId": "Please enter a valid national ID or file number", "enterValidNationalId": "Please enter a valid national ID or file number",
"enterValidPhoneNumber": "Please enter a valid phone number", "enterValidPhoneNumber": "Please enter a valid phone number",
"cannotEnterSaudiOrUAENumber": "You cannot enter Saudi Arabia (00966) or UAE (00971) phone numbers when 'Others' country is selected",
"ready": "Ready", "ready": "Ready",
"medicalCentersWithCount": "{count} Medical Centers", "medicalCentersWithCount": "{count} Medical Centers",
"medicalCenters": " Medical Centers", "medicalCenters": " Medical Centers",

@ -129,8 +129,7 @@ class ApiClientImp implements ApiClient {
} else {} } else {}
if (body.containsKey('isDentalAllowedBackend')) { if (body.containsKey('isDentalAllowedBackend')) {
body['isDentalAllowedBackend'] = body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
} }
if (!body.containsKey('IsPublicRequest')) { if (!body.containsKey('IsPublicRequest')) {
@ -194,6 +193,11 @@ class ApiClientImp implements ApiClient {
body['TokenID'] = "@dm!n"; body['TokenID'] = "@dm!n";
} }
if (url == 'https://uat.hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo') {
url = "https://hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo";
body['TokenID'] = "@dm!n";
}
// body['TokenID'] = "@dm!n"; // body['TokenID'] = "@dm!n";
// body['PatientID'] = 4773715; // body['PatientID'] = 4773715;
// body['PatientTypeID'] = 1; // body['PatientTypeID'] = 1;
@ -207,7 +211,7 @@ class ApiClientImp implements ApiClient {
// body['PatientID'] = 809289; // body['PatientID'] = 809289;
} }
if(!url.contains("/paymentApi")) { if (!url.contains("/paymentApi")) {
body['IsNewFlutterApp'] = true; body['IsNewFlutterApp'] = true;
} }
@ -261,10 +265,9 @@ class ApiClientImp implements ApiClient {
ApiClient._navigationService.pushAndRemoveUntil( ApiClient._navigationService.pushAndRemoveUntil(
CustomPageRoute( CustomPageRoute(
page: AppUpdatePage( page: AppUpdatePage(
appUpdateMessage: parsed['ErrorEndUserMessage'], appUpdateMessage: parsed['ErrorEndUserMessage'],
)), )),
ModalRoute.withName("/appUpdate") ModalRoute.withName("/appUpdate"));
);
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
} }
if (parsed['ErrorType'] == 2) { if (parsed['ErrorType'] == 2) {
@ -272,24 +275,19 @@ class ApiClientImp implements ApiClient {
onFailure( onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode, statusCode,
failureType: failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
); );
// logApiEndpointError(endPoint, "session logged out", statusCode); // logApiEndpointError(endPoint, "session logged out", statusCode);
} }
if (isAllowAny) { if (isAllowAny) {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['IsAuthenticated'] == null) { } else if (parsed['IsAuthenticated'] == null) {
if (parsed['isSMSSent'] == true) { if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['MessageStatus'] == 1) { } else if (parsed['MessageStatus'] == 1) {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['Result'] == 'OK') { } else if (parsed['Result'] == 'OK') {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else { } else {
onFailure( onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
@ -299,19 +297,16 @@ class ApiClientImp implements ApiClient {
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
} }
} else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['IsAuthenticated'] == false) { } else if (parsed['IsAuthenticated'] == false) {
onFailure( onFailure(
"User is not Authenticated", "User is not Authenticated",
statusCode, statusCode,
failureType: failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
); );
} else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
if (parsed['SameClinicApptList'] != null) { if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else { } else {
if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
if (parsed['ErrorSearchMsg'] == null) { if (parsed['ErrorSearchMsg'] == null) {
@ -340,8 +335,7 @@ class ApiClientImp implements ApiClient {
} }
} else { } else {
if (parsed['SameClinicApptList'] != null) { if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode, onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else { } else {
if (parsed['message'] != null) { if (parsed['message'] != null) {
onFailure( onFailure(

@ -112,10 +112,13 @@ class ApiConsts {
static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; static final String selectDeviceImei = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI';
static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; static final String checkPatientAuth = 'Services/Authentication.svc/REST/CheckPatientAuthentication';
static final String checkPatientAuthOthers = 'Services/Authentication.svc/REST/CheckPatientAuthentication_Others';
static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; static final String sendActivationCode = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
static final String sendActivationCodeOthers = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType_Others';
static final String sendActivationCodeRegister = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; static final String sendActivationCodeRegister = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration';
static final String checkActivationCode = 'Services/Authentication.svc/REST/CheckActivationCode'; static final String checkActivationCode = 'Services/Authentication.svc/REST/CheckActivationCode';
static final String checkActivationCodeOthers = 'Services/Authentication.svc/REST/CheckActivationCode_Others';
static final String checkActivationCodeRegister = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; static final String checkActivationCodeRegister = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration';
static final String checkUsageAgreement = 'Services/Patients.svc/REST/CheckForUsageAgreement'; static final String checkUsageAgreement = 'Services/Patients.svc/REST/CheckForUsageAgreement';
static final String getUserAgreementContent = 'Services/Patients.svc/REST/GetUsageAgreementText'; static final String getUserAgreementContent = 'Services/Patients.svc/REST/GetUsageAgreementText';
@ -124,6 +127,7 @@ class ApiConsts {
static final String checkUserStatus = 'Services/NHIC.svc/REST/GetPatientInfo'; static final String checkUserStatus = 'Services/NHIC.svc/REST/GetPatientInfo';
static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI';
static final String insertPatientDeviceIMEIDataOthers = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI_Others';
static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo';
static final String getPatientMobileData = '/Services/Authentication.svc/REST/GetMobileLoginInfo'; static final String getPatientMobileData = '/Services/Authentication.svc/REST/GetMobileLoginInfo';
static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege'; static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege';

@ -16,6 +16,7 @@ class AppAssets {
static const String call = '$svgBasePath/call.svg'; static const String call = '$svgBasePath/call.svg';
static const String email = '$svgBasePath/email.svg'; static const String email = '$svgBasePath/email.svg';
static const String globe = '$svgBasePath/globe.svg'; static const String globe = '$svgBasePath/globe.svg';
static const String globeOther = '$svgBasePath/globe_other.svg';
static const String cancel = '$svgBasePath/cancel.svg'; static const String cancel = '$svgBasePath/cancel.svg';
static const String bell = '$svgBasePath/bell.svg'; static const String bell = '$svgBasePath/bell.svg';
static const String login1 = '$svgBasePath/login1.svg'; static const String login1 = '$svgBasePath/login1.svg';

@ -116,6 +116,7 @@ class AppState {
set setIsAuthenticated(v) => isAuthenticated = v; set setIsAuthenticated(v) => isAuthenticated = v;
String deviceTypeID = ""; String deviceTypeID = "";
set setDeviceTypeID(v) => deviceTypeID = v; set setDeviceTypeID(v) => deviceTypeID = v;

@ -12,7 +12,7 @@ enum AuthMethodTypesEnum { sms, whatsApp, fingerPrint, faceID, moreOptions }
enum ViewStateEnum { hide, idle, busy, error, busyLocal, errorLocal } enum ViewStateEnum { hide, idle, busy, error, busyLocal, errorLocal }
enum CountryEnum { saudiArabia, unitedArabEmirates } enum CountryEnum { saudiArabia, unitedArabEmirates, others }
enum CalenderEnum { gregorian, hijri } enum CalenderEnum { gregorian, hijri }

@ -27,14 +27,21 @@ class RequestUtils {
}) { }) {
bool fileNo = false; bool fileNo = false;
if (nationId.isNotEmpty) { if (nationId.isNotEmpty) {
fileNo = nationId.length < 10; final numericRegex = RegExp(r'^[0-9]+$');
fileNo = nationId.length < 10 && numericRegex.hasMatch(nationId);
//fileNo = nationId.length < 10 && nationId.isNumericOnly() ;
if (fileNo) { if (fileNo) {
patientId = int.tryParse(nationId); patientId = int.tryParse(nationId);
} }
} }
var request = SendActivationRequest(); var request = SendActivationRequest();
if (phoneNumber.isNotEmpty) { if (phoneNumber.isNotEmpty) {
request.patientMobileNumber = int.parse(phoneNumber); // If zipCode is "0", it means "Others" country is selected
if (zipCode == "0") {
request.patientMobileNumberOthers = phoneNumber;
} else {
request.patientMobileNumber = int.parse(phoneNumber);
}
} }
request.oTPSendType = otpTypeEnum.toInt(); // could map OTPTypeEnum if needed request.oTPSendType = otpTypeEnum.toInt(); // could map OTPTypeEnum if needed
request.zipCode = zipCode; // or countryCode if defined elsewhere request.zipCode = zipCode; // or countryCode if defined elsewhere
@ -53,9 +60,9 @@ class RequestUtils {
request.patientIdentificationID = request.nationalID; request.patientIdentificationID = request.nationalID;
request.searchType = 2; request.searchType = 2;
} else { } else {
request.patientID = 0; request.patientID = 0;
request.searchType = 1; request.searchType = 1;
request.patientIdentificationID = request.nationalID = nationId.isNotEmpty ? int.parse(nationId) : 0; request.patientIdentificationID = request.nationalID = nationId.isNotEmpty ? nationId : '0';
} }
request.isRegister = false; request.isRegister = false;
} }
@ -75,11 +82,18 @@ class RequestUtils {
required int loginType}) { required int loginType}) {
bool fileNo = false; bool fileNo = false;
if (nationIdText.isNotEmpty) { if (nationIdText.isNotEmpty) {
fileNo = nationIdText.length < 10; final numericRegex = RegExp(r'^[0-9]+$');
fileNo = nationIdText.length < 10 && numericRegex.hasMatch(nationIdText);
} }
var request = SendActivationRequest(); var request = SendActivationRequest();
request.patientMobileNumber = int.parse(phoneNumber); // If countryCode is "0", it means "Others" country is selected
request.mobileNo = '0$phoneNumber'; if (countryCode == "0") {
request.patientMobileNumberOthers = phoneNumber;
request.mobileNo = phoneNumber;
} else {
request.patientMobileNumber = int.parse(phoneNumber);
request.mobileNo = '0$phoneNumber';
}
request.deviceToken = deviceToken; request.deviceToken = deviceToken;
request.projectOutSA = patientOutSA; request.projectOutSA = patientOutSA;
request.loginType = loginType; request.loginType = loginType;
@ -102,14 +116,14 @@ class RequestUtils {
} else { } else {
if (fileNo) { if (fileNo) {
request.patientID = patientId ?? int.parse(nationIdText); request.patientID = patientId ?? int.parse(nationIdText);
request.patientIdentificationID = request.nationalID = 0; request.patientIdentificationID = request.nationalID = '0';
request.searchType = 2; request.searchType = 2;
//TODO: Issue HEre is Not Login //TODO: Issue HEre is Not Login
} else { } else {
request.patientID = 0; request.patientID = 0;
request.searchType = 1; request.searchType = 1;
//TODO: Issue HEre is Not Login //TODO: Issue HEre is Not Login
request.patientIdentificationID = request.nationalID = (nationIdText.isNotEmpty ? int.parse(nationIdText) : 0); request.patientIdentificationID = request.nationalID = (nationIdText.isNotEmpty ? nationIdText : '0');
} }
request.isRegister = false; request.isRegister = false;
} }
@ -123,7 +137,7 @@ class RequestUtils {
required String mobileNumber, required String mobileNumber,
required String zipCode, required String zipCode,
required int? patientId, required int? patientId,
required int? nationalId, required dynamic nationalId,
required bool patientOutSA, required bool patientOutSA,
required int selectedLoginType, required int selectedLoginType,
required bool isForRegister, required bool isForRegister,
@ -136,9 +150,15 @@ class RequestUtils {
AppState _appState = getIt.get<AppState>(); AppState _appState = getIt.get<AppState>();
var request = SendActivationRequest(); var request = SendActivationRequest();
if (mobileNumber.isNotEmpty) { if (mobileNumber.isNotEmpty) {
request.patientMobileNumber = int.parse(mobileNumber); // If zipCode is "0", it means "Others" country is selected
if (zipCode == "0") {
request.patientMobileNumberOthers = mobileNumber;
request.mobileNo = mobileNumber;
} else {
request.patientMobileNumber = int.parse(mobileNumber);
request.mobileNo = '0$mobileNumber';
}
} }
request.mobileNo = '0$mobileNumber';
request.projectOutSA = patientOutSA; request.projectOutSA = patientOutSA;
request.loginType = selectedLoginType; request.loginType = selectedLoginType;
request.oTPSendType = otpTypeEnum.toInt(); //this.selectedOption == 1 ? 1 : 2; request.oTPSendType = otpTypeEnum.toInt(); //this.selectedOption == 1 ? 1 : 2;
@ -159,7 +179,7 @@ class RequestUtils {
request.searchType = isFileNo ? 2 : 1; request.searchType = isFileNo ? 2 : 1;
request.patientID = patientId ?? 0; request.patientID = patientId ?? 0;
request.nationalID = nationalId ?? 0; request.nationalID = nationalId ?? 0;
request.patientIdentificationID = (nationalId ?? '0') as int?; request.patientIdentificationID = (nationalId ?? '0');
request.isRegister = false; request.isRegister = false;
} }
request.deviceTypeID = request.searchType; request.deviceTypeID = request.searchType;

@ -60,11 +60,23 @@ class ValidationUtils {
return isCorrectID; return isCorrectID;
} }
static bool isValidatePhone({String? phoneNumber, required Function() onOkPress}) { static bool isValidatePhone({String? phoneNumber, required Function() onOkPress, CountryEnum? selectedCountry}) {
if (phoneNumber == null || phoneNumber.isEmpty) { if (phoneNumber == null || phoneNumber.isEmpty) {
_dialogService.showExceptionBottomSheet(message: LocaleKeys.enterValidPhoneNumber.tr(), onOkPressed: onOkPress); _dialogService.showExceptionBottomSheet(message: LocaleKeys.enterValidPhoneNumber.tr(), onOkPressed: onOkPress);
return false; return false;
} }
// Check if "Others" country is selected and phone number starts with restricted codes
if (selectedCountry == CountryEnum.others) {
if (phoneNumber.startsWith('00966') || phoneNumber.startsWith('00971')) {
_dialogService.showExceptionBottomSheet(
message: LocaleKeys.cannotEnterSaudiOrUAENumber.tr(),
onOkPressed: onOkPress
);
return false;
}
}
return true; return true;
} }

@ -470,6 +470,8 @@ extension CountryExtension on CountryEnum {
return "Kingdom Of Saudi Arabia"; return "Kingdom Of Saudi Arabia";
case CountryEnum.unitedArabEmirates: case CountryEnum.unitedArabEmirates:
return "United Arab Emirates"; return "United Arab Emirates";
case CountryEnum.others:
return "Others";
} }
} }
@ -479,6 +481,8 @@ extension CountryExtension on CountryEnum {
return "المملكة العربية السعودية"; return "المملكة العربية السعودية";
case CountryEnum.unitedArabEmirates: case CountryEnum.unitedArabEmirates:
return "الإمارات العربية المتحدة"; return "الإمارات العربية المتحدة";
case CountryEnum.others:
return "آخرون";
} }
} }
@ -488,6 +492,8 @@ extension CountryExtension on CountryEnum {
return AppAssets.ksa; return AppAssets.ksa;
case CountryEnum.unitedArabEmirates: case CountryEnum.unitedArabEmirates:
return AppAssets.uae; return AppAssets.uae;
case CountryEnum.others:
return AppAssets.globeOther;
} }
} }
@ -497,6 +503,8 @@ extension CountryExtension on CountryEnum {
return "966"; return "966";
case CountryEnum.unitedArabEmirates: case CountryEnum.unitedArabEmirates:
return "971"; return "971";
case CountryEnum.others:
return "0";
} }
} }
@ -508,6 +516,9 @@ extension CountryExtension on CountryEnum {
case "United Arab Emirates": case "United Arab Emirates":
case "الإمارات العربية المتحدة": case "الإمارات العربية المتحدة":
return CountryEnum.unitedArabEmirates; return CountryEnum.unitedArabEmirates;
case "Others":
case "آخرون":
return CountryEnum.others;
default: default:
throw Exception("Invalid country name"); throw Exception("Invalid country name");
} }

@ -102,11 +102,16 @@ class AuthenticationRepoImp implements AuthenticationRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq, String? languageID}) async { Future<Either<Failure, GenericApiModel<dynamic>>> checkPatientAuthentication({required dynamic checkPatientAuthenticationReq, String? languageID}) async {
int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1;
checkPatientAuthenticationReq.patientOutSA = isOutKsa; checkPatientAuthenticationReq.patientOutSA = isOutKsa;
// Determine which API to use based on zipCode
final isOthersCountry = checkPatientAuthenticationReq.zipCode == '0';
final apiEndpoint = isOthersCountry ? ApiConsts.checkPatientAuthOthers : ApiConsts.checkPatientAuth;
try { try {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;
Failure? failure; Failure? failure;
await apiClient.post( await apiClient.post(
ApiConsts.checkPatientAuth, apiEndpoint,
body: checkPatientAuthenticationReq.toJson(), body: checkPatientAuthenticationReq.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) { onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType; failure = failureType;
@ -150,16 +155,25 @@ class AuthenticationRepoImp implements AuthenticationRepo {
// payload.remove("ResponseID"); // payload.remove("ResponseID");
} }
// Determine which API to use based on zipCode
final isOthersCountry = sendActivationCodeReq.zipCode == '0';
String apiEndpoint;
if (isFormFamilyFile) {
apiEndpoint = ApiConsts.sendFamilyFileActivation;
} else if (isRegister) {
apiEndpoint = ApiConsts.sendActivationCodeRegister;
} else if (isOthersCountry) {
apiEndpoint = ApiConsts.sendActivationCodeOthers;
} else {
apiEndpoint = ApiConsts.sendActivationCode;
}
try { try {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;
Failure? failure; Failure? failure;
await apiClient.post( await apiClient.post(
isFormFamilyFile apiEndpoint,
? ApiConsts.sendFamilyFileActivation
: isRegister
? ApiConsts.sendActivationCodeRegister
: ApiConsts.sendActivationCode,
body: isFormFamilyFile ? payload : sendActivationCodeReq.toJson(), body: isFormFamilyFile ? payload : sendActivationCodeReq.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) { onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType; failure = failureType;
@ -186,6 +200,8 @@ class AuthenticationRepoImp implements AuthenticationRepo {
} }
} }
@override @override
Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo( Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo(
{required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq {required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
@ -304,11 +320,16 @@ class AuthenticationRepoImp implements AuthenticationRepo {
} }
} }
// Determine which API to use based on zipCode
final zipCode = _getZipCodeFromRequest(newRequest);
final isOthersCountry = zipCode == '0';
final endpoint = isFormFamilyFile final endpoint = isFormFamilyFile
? ApiConsts.checkActivationCodeForFamily ? ApiConsts.checkActivationCodeForFamily
: isRegister : isRegister
? ApiConsts.checkActivationCodeRegister ? ApiConsts.checkActivationCodeRegister
: ApiConsts.checkActivationCode; : isOthersCountry
? ApiConsts.checkActivationCodeOthers
: ApiConsts.checkActivationCode;
try { try {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;
@ -521,8 +542,14 @@ class AuthenticationRepoImp implements AuthenticationRepo {
try { try {
GenericApiModel<dynamic>? apiResponse; GenericApiModel<dynamic>? apiResponse;
Failure? failure; Failure? failure;
// Determine which API to use based on zipCode
final zipCode = patientIMEIDataRequest['ZipCode'];
final isOthersCountry = zipCode == '0';
final apiEndpoint = isOthersCountry ? ApiConsts.insertPatientDeviceIMEIDataOthers : ApiConsts.insertPatientDeviceIMEIData;
return apiClient.post( return apiClient.post(
ApiConsts.insertPatientDeviceIMEIData, apiEndpoint,
body: patientIMEIDataRequest, body: patientIMEIDataRequest,
onFailure: (error, statusCode, {messageStatus, failureType}) { onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType; failure = failureType;
@ -648,4 +675,17 @@ class AuthenticationRepoImp implements AuthenticationRepo {
return Future.value(Left(UnknownFailure(e.toString()))); return Future.value(Left(UnknownFailure(e.toString())));
} }
} }
/// Helper method to safely get zipCode from dynamic request (Map or Object)
String _getZipCodeFromRequest(dynamic request) {
if (request is Map) {
return request['ZipCode']?.toString() ?? request['zipCode']?.toString() ?? '';
} else {
try {
return request.zipCode?.toString() ?? '';
} catch (e) {
return '';
}
}
}
} }

@ -70,7 +70,7 @@ class AuthenticationViewModel extends ChangeNotifier {
_errorHandlerService = errorHandlerService, _errorHandlerService = errorHandlerService,
_appState = appState, _appState = appState,
_authenticationRepo = authenticationRepo, _authenticationRepo = authenticationRepo,
_localAuthService = localAuthService; _localAuthService = localAuthService {}
final TextEditingController nationalIdController = TextEditingController(), final TextEditingController nationalIdController = TextEditingController(),
phoneNumberController = TextEditingController(), phoneNumberController = TextEditingController(),
dobController = TextEditingController(), dobController = TextEditingController(),
@ -182,6 +182,17 @@ class AuthenticationViewModel extends ChangeNotifier {
void onPhoneNumberChange(String? phoneNumber) { void onPhoneNumberChange(String? phoneNumber) {
phoneNumberController.text = phoneNumber!; phoneNumberController.text = phoneNumber!;
// Real-time validation for Others country - prevent entering Saudi/UAE numbers
if (selectedCountrySignup == CountryEnum.others) {
if (phoneNumber.startsWith('00966') || phoneNumber.startsWith('00971')) {
// Remove the restricted prefix
phoneNumberController.text = phoneNumber.replaceAll(RegExp(r'^(00966|00971)'), '');
phoneNumberController.selection = TextSelection.fromPosition(
TextPosition(offset: phoneNumberController.text.length),
);
}
}
} }
void onTermAccepted() { void onTermAccepted() {
@ -301,9 +312,11 @@ class AuthenticationViewModel extends ChangeNotifier {
patientOutSA: false, patientOutSA: false,
otpTypeEnum: otpTypeEnum, otpTypeEnum: otpTypeEnum,
patientId: 0, patientId: 0,
zipCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true zipCode: selectedCountrySignup == CountryEnum.others
? CountryEnum.unitedArabEmirates.countryCode ? "0"
: selectedCountrySignup.countryCode, : (_appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true
? CountryEnum.unitedArabEmirates.countryCode
: selectedCountrySignup.countryCode),
calenderType: calenderType); calenderType: calenderType);
final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq);
@ -368,7 +381,7 @@ class AuthenticationViewModel extends ChangeNotifier {
mobileNumber: phoneNumber, mobileNumber: phoneNumber,
selectedLoginType: otpTypeEnum.toInt(), selectedLoginType: otpTypeEnum.toInt(),
zipCode: selectedCountrySignup.countryCode, zipCode: selectedCountrySignup.countryCode,
nationalId: int.parse(nationalIdOrFileNumber), nationalId:nationalIdOrFileNumber,
isFileNo: isForRegister ? isPatientHasFile(request: payload) : false, isFileNo: isForRegister ? isPatientHasFile(request: payload) : false,
patientId: isFormFamilyFile ? _appState.getAuthenticatedUser()!.patientId : 0, patientId: isFormFamilyFile ? _appState.getAuthenticatedUser()!.patientId : 0,
isForRegister: isForRegister, isForRegister: isForRegister,
@ -607,6 +620,7 @@ class AuthenticationViewModel extends ChangeNotifier {
activation.list!.first.isParentUser = true; activation.list!.first.isParentUser = true;
} }
activation.list!.first.bloodGroup = activation.patientBlodType; activation.list!.first.bloodGroup = activation.patientBlodType;
activation.list!.first.zipCode = selectedCountrySignup == CountryEnum.others ? '0' : selectedCountrySignup.countryCode;
_appState.setAuthenticatedUser(activation.list!.first); _appState.setAuthenticatedUser(activation.list!.first);
_appState.setPrivilegeModelList(activation.list!.first.listPrivilege!); _appState.setPrivilegeModelList(activation.list!.first.listPrivilege!);
_appState.setUserBloodGroup = activation.patientBlodType ?? "N/A"; _appState.setUserBloodGroup = activation.patientBlodType ?? "N/A";
@ -854,7 +868,9 @@ class AuthenticationViewModel extends ChangeNotifier {
await clearDefaultInputValues(); // This will Clear All Default Values Of User. await clearDefaultInputValues(); // This will Clear All Default Values Of User.
Future.delayed(Duration(seconds: 1), () { Future.delayed(Duration(seconds: 1), () {
LoadingUtils.hideFullScreenLoader(); LoadingUtils.hideFullScreenLoader();
_navigationService.pushAndReplace(AppRoutes.loginScreen); // _navigationService.pushAndReplace(AppRoutes.loginScreen);
_navigationService.pushAndRemoveUntil(CustomPageRoute(page: LandingNavigation()), (r) => false);
_navigationService.push(CustomPageRoute(page: LoginScreen()));
}); });
} }
} }
@ -948,22 +964,24 @@ class AuthenticationViewModel extends ChangeNotifier {
Future<void> insertPatientIMEIData(int loginType) async { Future<void> insertPatientIMEIData(int loginType) async {
final resultEither = await _authenticationRepo.insertPatientIMEIData( final resultEither = await _authenticationRepo.insertPatientIMEIData(
patientIMEIDataRequest: PatientInsertDeviceImei( patientIMEIDataRequest: PatientInsertDeviceImei(
imei: _appState.deviceToken, imei: _appState.deviceToken,
deviceTypeId: _appState.getDeviceTypeID(), deviceTypeId: _appState.getDeviceTypeID(),
patientId: _appState.getAuthenticatedUser()!.patientId!, patientId: _appState.getAuthenticatedUser()!.patientId!,
patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!,
firstName: _appState.getAuthenticatedUser()!.firstName!, firstName: _appState.getAuthenticatedUser()!.firstName!,
lastName: _appState.getAuthenticatedUser()!.lastName!, lastName: _appState.getAuthenticatedUser()!.lastName!,
patientTypeId: _appState.getAuthenticatedUser()!.patientType, patientTypeId: _appState.getAuthenticatedUser()!.patientType,
mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!, mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!,
logInTypeId: loginType, logInTypeId: loginType,
patientOutSa: _appState.getAuthenticatedUser()!.outSa!, patientOutSa: _appState.getAuthenticatedUser()!.outSa!,
outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false, outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false,
biometricEnabled: loginType == 1 || loginType == 2 ? false : true, biometricEnabled: loginType == 1 || loginType == 2 ? false : true,
firstNameN: _appState.getAuthenticatedUser()!.firstNameN, firstNameN: _appState.getAuthenticatedUser()!.firstNameN,
lastNameN: _appState.getAuthenticatedUser()!.lastNameN, lastNameN: _appState.getAuthenticatedUser()!.lastNameN,
).toJson()); zipCode: _appState.getAuthenticatedUser()!.zipCode //selectedCountrySignup == CountryEnum.others ? '0': selectedCountrySignup.countryCode,
)
.toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.messageStatus == 1) { if (apiResponse.messageStatus == 1) {
log("Insert IMEI Success"); log("Insert IMEI Success");

@ -1,5 +1,6 @@
class CheckActivationCodeRegisterReq { class CheckActivationCodeRegisterReq {
int? patientMobileNumber; int? patientMobileNumber;
String? patientMobileNumberOthers;
String? mobileNo; String? mobileNo;
String? deviceToken; String? deviceToken;
bool? projectOutSA; bool? projectOutSA;
@ -9,8 +10,8 @@ class CheckActivationCodeRegisterReq {
String? logInTokenID; String? logInTokenID;
int? searchType; int? searchType;
int? patientID; int? patientID;
int? nationalID; dynamic nationalID;
int? patientIdentificationID; dynamic patientIdentificationID;
String? activationCode; String? activationCode;
bool? isSilentLogin; bool? isSilentLogin;
double? versionID; double? versionID;
@ -29,6 +30,7 @@ class CheckActivationCodeRegisterReq {
CheckActivationCodeRegisterReq({ CheckActivationCodeRegisterReq({
this.patientMobileNumber, this.patientMobileNumber,
this.patientMobileNumberOthers,
this.mobileNo, this.mobileNo,
this.deviceToken, this.deviceToken,
this.projectOutSA, this.projectOutSA,
@ -59,6 +61,7 @@ class CheckActivationCodeRegisterReq {
CheckActivationCodeRegisterReq.fromJson(Map<String, dynamic> json) { CheckActivationCodeRegisterReq.fromJson(Map<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber']; patientMobileNumber = json['PatientMobileNumber'];
patientMobileNumberOthers = json['PatientMobileNumber_Others'];
mobileNo = json['MobileNo']; mobileNo = json['MobileNo'];
deviceToken = json['DeviceToken']; deviceToken = json['DeviceToken'];
projectOutSA = json['ProjectOutSA']; projectOutSA = json['ProjectOutSA'];
@ -89,9 +92,14 @@ class CheckActivationCodeRegisterReq {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{}; final Map<String, dynamic> data = <String, dynamic>{};
data['PatientMobileNumber'] = patientMobileNumber; // Only send PatientMobileNumber_Others if it's set, otherwise send PatientMobileNumber
data['MobileNo'] = mobileNo; if (patientMobileNumberOthers != null) {
data['PatientMobileNumber_Others'] = patientMobileNumberOthers;
} else if (patientMobileNumber != null) {
data['PatientMobileNumber'] = patientMobileNumber;
}
data['DeviceToken'] = deviceToken; data['DeviceToken'] = deviceToken;
data['MobileNo'] = mobileNo;
data['ProjectOutSA'] = projectOutSA; data['ProjectOutSA'] = projectOutSA;
data['LoginType'] = loginType; data['LoginType'] = loginType;
data['ZipCode'] = zipCode; data['ZipCode'] = zipCode;

@ -28,6 +28,7 @@ class PatientInsertDeviceImei {
int? patientOutSa; int? patientOutSa;
String? sessionId; String? sessionId;
String? lastName; String? lastName;
String? zipCode;
PatientInsertDeviceImei({ PatientInsertDeviceImei({
this.setupId, this.setupId,
@ -56,7 +57,8 @@ class PatientInsertDeviceImei {
this.patientTypeId, this.patientTypeId,
this.patientOutSa, this.patientOutSa,
this.sessionId, this.sessionId,
this.lastName this.lastName,
this.zipCode,
}); });
factory PatientInsertDeviceImei.fromRawJson(String str) => PatientInsertDeviceImei.fromJson(json.decode(str)); factory PatientInsertDeviceImei.fromRawJson(String str) => PatientInsertDeviceImei.fromJson(json.decode(str));
@ -91,6 +93,7 @@ class PatientInsertDeviceImei {
patientOutSa: json["PatientOutSA"], patientOutSa: json["PatientOutSA"],
sessionId: json["SessionID"], sessionId: json["SessionID"],
lastName: json["LastName"], lastName: json["LastName"],
zipCode: json["ZipCode"],
); );
@ -122,5 +125,6 @@ class PatientInsertDeviceImei {
"PatientOutSA": patientOutSa, "PatientOutSA": patientOutSa,
"SessionID": sessionId, "SessionID": sessionId,
"LastName": lastName, "LastName": lastName,
"ZipCode": zipCode,
}; };
} }

@ -1,5 +1,6 @@
class SendActivationRequest { class SendActivationRequest {
int? patientMobileNumber; int? patientMobileNumber;
String? patientMobileNumberOthers;
String? mobileNo; String? mobileNo;
String? deviceToken; String? deviceToken;
bool? projectOutSA; bool? projectOutSA;
@ -9,8 +10,8 @@ class SendActivationRequest {
String? logInTokenID; String? logInTokenID;
int? searchType; int? searchType;
int? patientID; int? patientID;
int? nationalID; dynamic nationalID;
int? patientIdentificationID; dynamic patientIdentificationID;
int? oTPSendType; int? oTPSendType;
int? languageID; int? languageID;
double? versionID; double? versionID;
@ -32,6 +33,7 @@ class SendActivationRequest {
SendActivationRequest( SendActivationRequest(
{this.patientMobileNumber, {this.patientMobileNumber,
this.patientMobileNumberOthers,
this.mobileNo, this.mobileNo,
this.deviceToken, this.deviceToken,
this.projectOutSA, this.projectOutSA,
@ -64,6 +66,7 @@ class SendActivationRequest {
SendActivationRequest.fromJson(Map<String, dynamic> json) { SendActivationRequest.fromJson(Map<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber']; patientMobileNumber = json['PatientMobileNumber'];
patientMobileNumberOthers = json['PatientMobileNumber_Others'];
mobileNo = json['MobileNo']; mobileNo = json['MobileNo'];
deviceToken = json['DeviceToken']; deviceToken = json['DeviceToken'];
projectOutSA = json['ProjectOutSA']; projectOutSA = json['ProjectOutSA'];
@ -97,7 +100,12 @@ class SendActivationRequest {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = new Map<String, dynamic>();
data['PatientMobileNumber'] = patientMobileNumber; // Only send PatientMobileNumber_Others if it's set, otherwise send PatientMobileNumber
if (patientMobileNumberOthers != null) {
data['PatientMobileNumber_Others'] = patientMobileNumberOthers;
} else if (patientMobileNumber != null) {
data['PatientMobileNumber'] = patientMobileNumber;
}
data['MobileNo'] = mobileNo; data['MobileNo'] = mobileNo;
data['DeviceToken'] = deviceToken; data['DeviceToken'] = deviceToken;
data['ProjectOutSA'] = projectOutSA; data['ProjectOutSA'] = projectOutSA;

@ -19,7 +19,7 @@ class SelectDeviceByImeiRespModelElement {
bool? biometricEnabled; bool? biometricEnabled;
int? patientType; int? patientType;
int? preferredLanguage; int? preferredLanguage;
bool? isOther;
SelectDeviceByImeiRespModelElement({ SelectDeviceByImeiRespModelElement({
this.id, this.id,
this.imei, this.imei,
@ -35,6 +35,7 @@ class SelectDeviceByImeiRespModelElement {
this.biometricEnabled, this.biometricEnabled,
this.patientType, this.patientType,
this.preferredLanguage, this.preferredLanguage,
this.isOther
}); });
factory SelectDeviceByImeiRespModelElement.fromJson(Map<String, dynamic> json) => SelectDeviceByImeiRespModelElement( factory SelectDeviceByImeiRespModelElement.fromJson(Map<String, dynamic> json) => SelectDeviceByImeiRespModelElement(
@ -52,6 +53,7 @@ class SelectDeviceByImeiRespModelElement {
biometricEnabled: json["BiometricEnabled"] as bool?, biometricEnabled: json["BiometricEnabled"] as bool?,
patientType: json["PatientType"] as int?, patientType: json["PatientType"] as int?,
preferredLanguage: json["PreferredLanguage"] as int?, preferredLanguage: json["PreferredLanguage"] as int?,
isOther: json["IsOther"] as bool?
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -69,5 +71,6 @@ class SelectDeviceByImeiRespModelElement {
"BiometricEnabled": biometricEnabled, "BiometricEnabled": biometricEnabled,
"PatientType": patientType, "PatientType": patientType,
"PreferredLanguage": preferredLanguage, "PreferredLanguage": preferredLanguage,
"IsOther": isOther,
}; };
} }

@ -812,6 +812,7 @@ abstract class LocaleKeys {
static const ready = 'ready'; static const ready = 'ready';
static const enterValidNationalId = 'enterValidNationalId'; static const enterValidNationalId = 'enterValidNationalId';
static const enterValidPhoneNumber = 'enterValidPhoneNumber'; static const enterValidPhoneNumber = 'enterValidPhoneNumber';
static const cannotEnterSaudiOrUAENumber = 'cannotEnterSaudiOrUAENumber';
static const medicalCentersWithCount = 'medicalCentersWithCount'; static const medicalCentersWithCount = 'medicalCentersWithCount';
static const medicalCenters = 'medicalCenters'; static const medicalCenters = 'medicalCenters';
static const hospitalsWithCount = 'hospitalsWithCount'; static const hospitalsWithCount = 'hospitalsWithCount';

@ -79,7 +79,7 @@ class LoginScreenState extends State<LoginScreen> {
hintText: "xxxxxxxxx", hintText: "xxxxxxxxx",
controller: authVm.nationalIdController, controller: authVm.nationalIdController,
focusNode: _nationalIdFocusNode, focusNode: _nationalIdFocusNode,
keyboardType: TextInputType.number, keyboardType: TextInputType.text,
isEnable: true, isEnable: true,
prefix: null, prefix: null,
autoFocus: true, autoFocus: true,
@ -165,51 +165,60 @@ class LoginScreenState extends State<LoginScreen> {
child: SingleChildScrollView( child: SingleChildScrollView(
child: GenericBottomSheet( child: GenericBottomSheet(
countryCode: authViewModel.selectedCountrySignup.countryCode, countryCode: authViewModel.selectedCountrySignup.countryCode,
initialPhoneNumber: "", initialPhoneNumber: "",
textController: phoneNumberController, textController: phoneNumberController,
isEnableCountryDropdown: true, isEnableCountryDropdown: true,
onCountryChange: authViewModel.onCountryChange, onCountryChange: (country) {
authViewModel.onCountryChange(country);
setModalState(() {});
},
onChange: authViewModel.onPhoneNumberChange, onChange: authViewModel.onPhoneNumberChange,
buttons: [ buttons: [
Padding( if (authViewModel.selectedCountrySignup != CountryEnum.others)
padding: EdgeInsets.only(bottom: 10.h), Padding(
child: CustomButton( padding: EdgeInsets.only(bottom: 10.h),
text: LocaleKeys.sendOTPSMS.tr(context: context), child: CustomButton(
onPressed: () async { text: LocaleKeys.sendOTPSMS.tr(context: context),
if (ValidationUtils.isValidatePhone( onPressed: () async {
phoneNumber: phoneNumberController!.text, if (ValidationUtils.isValidatePhone(
onOkPress: () { phoneNumber: phoneNumberController!.text,
Navigator.of(context).pop(); selectedCountry: authViewModel.selectedCountrySignup,
})) { onOkPress: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
appState.setSelectDeviceByImeiRespModelElement(null); })) {
await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); Navigator.of(context).pop();
} appState.setSelectDeviceByImeiRespModelElement(null);
}, await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms);
backgroundColor: AppColors.primaryRedColor, }
borderColor: AppColors.primaryRedBorderColor, },
textColor: Colors.white, backgroundColor: AppColors.primaryRedColor,
iconColor: Colors.white, borderColor: AppColors.primaryRedBorderColor,
icon: AppAssets.message, textColor: Colors.white,
), iconColor: Colors.white,
), icon: AppAssets.message,
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),
), ),
], ),
), if (authViewModel.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(
padding: EdgeInsets.only(bottom: 10.h, top: 10.h), padding: EdgeInsets.only(bottom: 10.h, top: 10.h),
child: CustomButton( child: CustomButton(
text: LocaleKeys.sendOTPWHATSAPP.tr(context: context), text: LocaleKeys.sendOTPWHATSAPP.tr(context: context),
onPressed: () async { onPressed: () async {
if (ValidationUtils.isValidatePhone( if (ValidationUtils.isValidatePhone(
phoneNumber: phoneNumberController!.text, phoneNumber: phoneNumberController!.text,
selectedCountry: authViewModel.selectedCountrySignup,
onOkPress: () { onOkPress: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
})) { })) {
@ -220,7 +229,7 @@ class LoginScreenState extends State<LoginScreen> {
}, },
backgroundColor: Colors.white, backgroundColor: Colors.white,
borderColor: AppColors.borderOnlyColor, borderColor: AppColors.borderOnlyColor,
textColor: AppColors.whiteColor, textColor: AppColors.borderOnlyColor,
icon: AppAssets.whatsapp, icon: AppAssets.whatsapp,
iconColor: null, iconColor: null,
applyThemeColor: false, applyThemeColor: false,

@ -90,7 +90,7 @@ class _RegisterNew extends State<RegisterNew> {
child: Column( child: Column(
children: [ children: [
CustomCountryDropdown( CustomCountryDropdown(
countryList: CountryEnum.values, countryList: CountryEnum.values.where((c) => c != CountryEnum.others).toList(),
onCountryChange: authVm.onCountryChange, onCountryChange: authVm.onCountryChange,
// isRtl: Directionality.of(context) == TextDirection.LTR, // isRtl: Directionality.of(context) == TextDirection.LTR,
).withVerticalPadding(8.h), ).withVerticalPadding(8.h),

@ -31,7 +31,7 @@ class _SavedLogin extends State<SavedLogin> {
LoginTypeEnum loginType = LoginTypeEnum.sms; LoginTypeEnum loginType = LoginTypeEnum.sms;
late AuthenticationViewModel authVm; late AuthenticationViewModel authVm;
late AppState appState; late AppState appState;
bool? isOther;
@override @override
void initState() { void initState() {
authVm = context.read<AuthenticationViewModel>(); authVm = context.read<AuthenticationViewModel>();
@ -43,6 +43,15 @@ class _SavedLogin extends State<SavedLogin> {
: appState.getSelectDeviceByImeiRespModelElement!.mobile!; : appState.getSelectDeviceByImeiRespModelElement!.mobile!;
authVm.nationalIdController.text = appState.getSelectDeviceByImeiRespModelElement!.identificationNo!; authVm.nationalIdController.text = appState.getSelectDeviceByImeiRespModelElement!.identificationNo!;
// Check if this is an "Others" country user
isOther = appState.getSelectDeviceByImeiRespModelElement!.isOther == true;
// Set country to Others if isOther flag is true - this ensures _Others APIs are called
if (isOther!) {
authVm.phoneNumberController.text = appState.getSelectDeviceByImeiRespModelElement!.mobile!;
authVm.selectedCountrySignup = CountryEnum.others;
}
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(() {}); authVm.loginWithFingerPrintFace(() {});
} }
@ -90,9 +99,9 @@ class _SavedLogin extends State<SavedLogin> {
), ),
child: Column( child: Column(
children: [ children: [
// Last login info // Last login info - show WhatsApp only if isOther AND loginType is SMS
("${LocaleKeys.lastLoginBy.tr()} ${loginType.displayName}") ("${LocaleKeys.lastLoginBy.tr()} ${(isOther == true && loginType == LoginTypeEnum.sms) ? LoginTypeEnum.whatsapp.displayName : loginType.displayName}")
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1), .toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1),
Directionality( Directionality(
textDirection: ui.TextDirection.ltr, textDirection: ui.TextDirection.ltr,
@ -108,20 +117,27 @@ class _SavedLogin extends State<SavedLogin> {
? Container( ? Container(
margin: EdgeInsets.all(16.h), margin: EdgeInsets.all(16.h),
child: Utils.buildSvgWithAssets( child: Utils.buildSvgWithAssets(
icon: getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!), icon: (isOther == true && loginType == LoginTypeEnum.sms) ? AppAssets.whatsapp : getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!),
height: 54.h, height: 54.h,
width: 54.w, width: 54.w,
iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)) iconColor: (isOther == true && loginType == LoginTypeEnum.sms) || loginType.toInt == 4 ? null : AppColors.primaryRedColor))
: SizedBox(), : SizedBox(),
// Face ID login button // Main login button - for isOther with SMS, show WhatsApp, otherwise keep original login type
CustomButton( CustomButton(
text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}", text: (isOther == true && loginType == LoginTypeEnum.sms)
? "${LocaleKeys.loginBy.tr()} ${LoginTypeEnum.whatsapp.displayName}"
: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}",
onPressed: () { onPressed: () {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(() {}); authVm.loginWithFingerPrintFace(() {});
} else { } else {
authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp); // 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),
);
} }
}, },
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
@ -132,24 +148,25 @@ class _SavedLogin extends State<SavedLogin> {
borderRadius: 12.r, borderRadius: 12.r,
height: 40.h, height: 40.h,
padding: EdgeInsets.symmetric(vertical: 10.h), padding: EdgeInsets.symmetric(vertical: 10.h),
icon: getTypeIcons(loginType.toInt), icon: (isOther == true && loginType == LoginTypeEnum.sms) ? AppAssets.whatsapp : getTypeIcons(loginType.toInt),
//loginType == LoginTypeEnum.sms ? AppAssets.sms :AppAssets.whatsapp, iconColor: (isOther == true && loginType == LoginTypeEnum.sms) || loginType == LoginTypeEnum.whatsapp ? null : Colors.white,
iconColor: loginType != LoginTypeEnum.whatsapp ? Colors.white : null,
), ),
], ],
), ),
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
Padding( // Hide OR + OTP login options entirely when isOther is true
padding: EdgeInsets.symmetric(horizontal: 16.w), if (isOther != true) ...[
child: Text( Padding(
LocaleKeys.oR.tr(), padding: EdgeInsets.symmetric(horizontal: 16.w),
style: context.dynamicTextStyle(fontSize: 16.f, fontWeight: FontWeight.w500), child: Text(
LocaleKeys.oR.tr(),
style: context.dynamicTextStyle(fontSize: 16.f, fontWeight: FontWeight.w500),
),
), ),
), SizedBox(height: 24.h),
SizedBox(height: 24.h), // OTP login button
// OTP login button loginType.toInt != 1
loginType.toInt != 1
? Column( ? Column(
children: [ children: [
loginType.toInt != 1 loginType.toInt != 1
@ -256,9 +273,10 @@ class _SavedLogin extends State<SavedLogin> {
borderWidth: 2.w, borderWidth: 2.w,
padding: EdgeInsets.fromLTRB(0, 14.h, 0, 14.h), padding: EdgeInsets.fromLTRB(0, 14.h, 0, 14.h),
), ),
],
const Spacer(flex: 2), const Spacer(flex: 2),
// OR divider // OR divider
SizedBox(height: 24.h), SizedBox(height: 24.h),
// Guest and Switch account // Guest and Switch account
Row( Row(

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart'; import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; 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/core/utils/utils.dart';
@ -1051,6 +1052,7 @@ class _LandingPageState extends State<LandingPage> {
isDone: isDone, isDone: isDone,
onPressed: () { onPressed: () {
// sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true); // sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true);
authVM.loginWithFingerPrintFace(() async { authVM.loginWithFingerPrintFace(() async {
isDone = true; isDone = true;
cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: true); cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: true);

@ -158,7 +158,7 @@ class GenericBottomSheetState extends State<GenericBottomSheet> {
prefix: widget.isForEmail ? null : widget.countryCode, prefix: widget.isForEmail ? null : widget.countryCode,
isBorderAllowed: false, isBorderAllowed: false,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
fontSize: 18.f, fontSize: 14.f,
isCountryDropDown: widget.isEnableCountryDropdown, isCountryDropDown: widget.isEnableCountryDropdown,
leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone, leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone,
fontFamily: "Poppins", fontFamily: "Poppins",

@ -98,11 +98,12 @@ class CustomCountryDropdownState extends State<CustomCountryDropdown> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( if (selectedCountry != CountryEnum.others)
selectedCountry!.countryCode, Text(
style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5, fontFamily: "Poppins"), selectedCountry!.countryCode,
), style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5, fontFamily: "Poppins"),
SizedBox(width: 4.h), ),
if (selectedCountry != CountryEnum.others) SizedBox(width: 4.h),
if (widget.isEnableTextField) if (widget.isEnableTextField)
SizedBox( SizedBox(
height: 20.h, height: 20.h,
@ -112,7 +113,14 @@ class CustomCountryDropdownState extends State<CustomCountryDropdown> {
child: TextField( child: TextField(
focusNode: textFocusNode, focusNode: textFocusNode,
style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5, fontFamily: "Poppins"), style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5, fontFamily: "Poppins"),
decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none, contentPadding: EdgeInsets.zero),
decoration: InputDecoration(
hintText: selectedCountry == CountryEnum.others ? "001*******" : "",
isDense: true,
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
),
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
onChanged: widget.onPhoneNumberChanged, onChanged: widget.onPhoneNumberChanged,
), ),

@ -44,7 +44,7 @@ class _FamilyFileAddWidgetState extends State<FamilyFileAddWidget> {
child: Column( child: Column(
children: [ children: [
CustomCountryDropdown( CustomCountryDropdown(
countryList: CountryEnum.values, countryList: CountryEnum.values.where((c) => c != CountryEnum.others).toList(),
onCountryChange: authVm.onCountryChange, onCountryChange: authVm.onCountryChange,
).paddingOnly(top: 8.h, bottom: 16.h), ).paddingOnly(top: 8.h, bottom: 16.h),
Divider(height: 1.h, color: AppColors.spacerLineColor), Divider(height: 1.h, color: AppColors.spacerLineColor),

Loading…
Cancel
Save