login for other country done.

login_other_country
Sultan khan 2 weeks ago
parent 13cf05819e
commit 63e63baf7a

@ -21,8 +21,8 @@ var PACKAGES_ORDERS = '/api/orders';
var PACKAGES_ORDER_HISTORY = '/api/orders/items'; var PACKAGES_ORDER_HISTORY = '/api/orders/items';
var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara'; var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara';
// var BASE_URL = 'http://10.50.100.198:2018/'; // var BASE_URL = 'http://10.50.100.198:2018/';
// var BASE_URL = 'https://uat.hmgwebservices.com/'; var BASE_URL = 'https://uat.hmgwebservices.com/';
var BASE_URL = 'https://hmgwebservices.com/'; // var BASE_URL = 'https://hmgwebservices.com/';
// var BASE_URL = 'http://10.201.204.103/'; // var BASE_URL = 'http://10.201.204.103/';
// var BASE_URL = 'https://orash.cloudsolutions.com.sa/'; // var BASE_URL = 'https://orash.cloudsolutions.com.sa/';
// var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; // var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/';
@ -357,7 +357,7 @@ var CAN_PAY_FOR_FOR_WALKIN_APPOINTMENT = 'Services/Doctors.svc/REST/CanPayForWal
var CHANNEL = 3; var CHANNEL = 3;
var GENERAL_ID = 'Cs2020@2016\$2958'; var GENERAL_ID = 'Cs2020@2016\$2958';
var IP_ADDRESS = '10.20.10.20'; var IP_ADDRESS = '10.20.10.20';
var VERSION_ID = 19.4; var VERSION_ID = 20.5;
var SETUP_ID = '91877'; var SETUP_ID = '91877';
var LANGUAGE = 2; var LANGUAGE = 2;
// var PATIENT_OUT_SA = 0; // var PATIENT_OUT_SA = 0;

@ -1,5 +1,6 @@
class CheckActivationCodeReq { class CheckActivationCodeReq {
int? patientMobileNumber; int? patientMobileNumber;
String? patientMobileNumberOthers; // For Others country - string mobile number
String? mobileNo; String? mobileNo;
String? deviceToken; String? deviceToken;
bool? projectOutSA; bool? projectOutSA;
@ -26,6 +27,7 @@ class CheckActivationCodeReq {
CheckActivationCodeReq({ CheckActivationCodeReq({
this.patientMobileNumber, this.patientMobileNumber,
this.patientMobileNumberOthers,
this.mobileNo, this.mobileNo,
this.deviceToken, this.deviceToken,
this.projectOutSA, this.projectOutSA,
@ -53,6 +55,7 @@ class CheckActivationCodeReq {
CheckActivationCodeReq.fromJson(Map<String, dynamic> json) { CheckActivationCodeReq.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'];
@ -81,7 +84,12 @@ class CheckActivationCodeReq {
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'] = this.patientMobileNumber; data['PatientMobileNumber'] = this.patientMobileNumber;
data['MobileNo'] = this.mobileNo; if (this.patientMobileNumberOthers != null) {
data['PatientMobileNumber_Others'] = this.patientMobileNumberOthers;
// Don't include MobileNo for Others country
} else {
data['MobileNo'] = this.mobileNo;
}
data['DeviceToken'] = this.deviceToken; data['DeviceToken'] = this.deviceToken;
data['ProjectOutSA'] = this.projectOutSA; data['ProjectOutSA'] = this.projectOutSA;
data['LoginType'] = this.loginType; data['LoginType'] = this.loginType;

@ -1,5 +1,6 @@
class CheckPatientAuthenticationReq { class CheckPatientAuthenticationReq {
int? patientMobileNumber; int? patientMobileNumber;
String? patientMobileNumberOthers;
String? zipCode; String? zipCode;
bool? isRegister; bool? isRegister;
String? tokenID; String? tokenID;
@ -20,6 +21,7 @@ class CheckPatientAuthenticationReq {
String? healthId; String? healthId;
CheckPatientAuthenticationReq( CheckPatientAuthenticationReq(
{this.patientMobileNumber, {this.patientMobileNumber,
this.patientMobileNumberOthers,
this.zipCode, this.zipCode,
this.isRegister, this.isRegister,
this.tokenID, this.tokenID,
@ -42,6 +44,7 @@ class CheckPatientAuthenticationReq {
CheckPatientAuthenticationReq.fromJson(Map<String, dynamic> json) { CheckPatientAuthenticationReq.fromJson(Map<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber']; patientMobileNumber = json['PatientMobileNumber'];
patientMobileNumberOthers = json['PatientMobileNumber_Others'];
zipCode = json['ZipCode']; zipCode = json['ZipCode'];
isRegister = json['isRegister']; isRegister = json['isRegister'];
tokenID = json['TokenID']; tokenID = json['TokenID'];
@ -65,6 +68,7 @@ class CheckPatientAuthenticationReq {
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'] = this.patientMobileNumber; data['PatientMobileNumber'] = this.patientMobileNumber;
data['PatientMobileNumber_Others'] = this.patientMobileNumberOthers;
data['ZipCode'] = this.zipCode; data['ZipCode'] = this.zipCode;
data['isRegister'] = this.isRegister; data['isRegister'] = this.isRegister;
data['TokenID'] = this.tokenID; data['TokenID'] = this.tokenID;

@ -13,7 +13,7 @@ class SelectDeviceIMEIRES {
int? patientID; int? patientID;
int? patientType; int? patientType;
int? preferredLanguage; int? preferredLanguage;
bool? isOther;
SelectDeviceIMEIRES( SelectDeviceIMEIRES(
{this.biometricEnabled, {this.biometricEnabled,
this.createdOn, this.createdOn,
@ -28,7 +28,9 @@ class SelectDeviceIMEIRES {
this.outSA, this.outSA,
this.patientID, this.patientID,
this.patientType, this.patientType,
this.preferredLanguage}); this.preferredLanguage,
this.isOther
});
SelectDeviceIMEIRES.fromJson(Map<String, dynamic> json) { SelectDeviceIMEIRES.fromJson(Map<String, dynamic> json) {
biometricEnabled = json['BiometricEnabled']; biometricEnabled = json['BiometricEnabled'];
@ -45,6 +47,7 @@ class SelectDeviceIMEIRES {
patientID = json['PatientID']; patientID = json['PatientID'];
patientType = json['PatientType']; patientType = json['PatientType'];
preferredLanguage = json['PreferredLanguage']; preferredLanguage = json['PreferredLanguage'];
isOther =json["IsOther"];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -63,6 +66,8 @@ class SelectDeviceIMEIRES {
data['PatientID'] = this.patientID; data['PatientID'] = this.patientID;
data['PatientType'] = this.patientType; data['PatientType'] = this.patientType;
data['PreferredLanguage'] = this.preferredLanguage; data['PreferredLanguage'] = this.preferredLanguage;
data['IsOther'] = this.isOther;
return data; return data;
} }

@ -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;
@ -31,6 +32,7 @@ class SendActivationRequest {
bool? isPatientExcluded; bool? isPatientExcluded;
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'];
@ -98,6 +101,7 @@ 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'] = this.patientMobileNumber; data['PatientMobileNumber'] = this.patientMobileNumber;
data['PatientMobileNumber_Others'] = this.patientMobileNumberOthers;
data['MobileNo'] = this.mobileNo; data['MobileNo'] = this.mobileNo;
data['DeviceToken'] = this.deviceToken; data['DeviceToken'] = this.deviceToken;
data['ProjectOutSA'] = this.projectOutSA; data['ProjectOutSA'] = this.projectOutSA;

File diff suppressed because it is too large Load Diff

@ -63,7 +63,8 @@ class _ConfirmLogin extends State<ConfirmLogin> {
bool authenticated = false; bool authenticated = false;
final authService = AuthProvider(); final authService = AuthProvider();
PharmacyModuleViewModel pharmacyModuleViewModel = locator<PharmacyModuleViewModel>(); PharmacyModuleViewModel pharmacyModuleViewModel = locator<PharmacyModuleViewModel>();
late int mobileNumber; int? mobileNumber;
String? mobileNumberOthers;
String errorMsg = ''; String errorMsg = '';
SelectDeviceIMEIRES? user; SelectDeviceIMEIRES? user;
bool isLoading = false; bool isLoading = false;
@ -426,6 +427,17 @@ class _ConfirmLogin extends State<ConfirmLogin> {
request.dob = ""; request.dob = "";
request.healthId = ""; request.healthId = "";
request.isHijri = 0; request.isHijri = 0;
zipCode =='0' ? await this.authService.sendActivationCodeOthers(request).then((result) {
GifLoaderDialogUtils.hideDialog(context);
if (result != null && result['isSMSSent'] == true) {
this.startSMSService(type);
}
}).catchError((r) {
GifLoaderDialogUtils.hideDialog(context);
AppToast.showErrorToast(message: r.toString());
})
:
await this.authService.sendActivationCode(request).then((result) { await this.authService.sendActivationCode(request).then((result) {
GifLoaderDialogUtils.hideDialog(context); GifLoaderDialogUtils.hideDialog(context);
if (result != null && result['isSMSSent'] == true) { if (result != null && result['isSMSSent'] == true) {
@ -445,7 +457,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
new SMSOTP( new SMSOTP(
context, context,
type, type,
this.mobileNumber, zipCode =='0'? this.mobileNumberOthers : this.mobileNumber,
(value) { (value) {
this.checkActivationCode(value: value); this.checkActivationCode(value: value);
}, },
@ -532,7 +544,9 @@ class _ConfirmLogin extends State<ConfirmLogin> {
this.registerd_data = await CheckPatientAuthenticationReq.fromJson(await sharedPref.getObject(REGISTER_DATA_FOR_LOGIIN)); this.registerd_data = await CheckPatientAuthenticationReq.fromJson(await sharedPref.getObject(REGISTER_DATA_FOR_LOGIIN));
} }
this.mobileNumber = this.registerd_data != null ? this.registerd_data.patientMobileNumber : int.parse(this.user!.mobile!); this.mobileNumberOthers = this.registerd_data != null ? this.registerd_data.patientMobileNumberOthers : this.user!.mobile;
this.mobileNumber = this.registerd_data != null ? this.registerd_data.patientMobileNumber : int.parse(this.user!.mobile!);
this.zipCode = this.registerd_data != null this.zipCode = this.registerd_data != null
? this.registerd_data.zipCode ? this.registerd_data.zipCode
: this.user!.outSA == true : this.user!.outSA == true
@ -563,6 +577,10 @@ class _ConfirmLogin extends State<ConfirmLogin> {
? user!.logInType ? user!.logInType
: null; : null;
if(this.user !=null && this.user!.isOther!){
this.zipCode ='0';
}
showLoader(false); showLoader(false);
//this.cs.sharedService.getStorage(AuthenticationService.LAST_LOGIN); //this.cs.sharedService.getStorage(AuthenticationService.LAST_LOGIN);
} }
@ -570,13 +588,22 @@ class _ConfirmLogin extends State<ConfirmLogin> {
getCommonRequest({type}) { getCommonRequest({type}) {
var request = SendActivationRequest(); var request = SendActivationRequest();
request.patientMobileNumber = this.mobileNumber; request.patientMobileNumber = this.mobileNumber;
request.mobileNo = '0' + this.mobileNumber.toString();
if(this.zipCode=='0'){
request.patientMobileNumberOthers = this.mobileNumberOthers;
request.mobileNo = this.mobileNumberOthers;
}else {
request.mobileNo = '0' + this.mobileNumber.toString();
}
request.deviceToken = this.deviceToken; request.deviceToken = this.deviceToken;
request.projectOutSA = this.patientOutSA == true ? true : false; request.projectOutSA = this.patientOutSA == true ? true : false;
request.loginType = this.selectedOption; request.loginType = type ?? this.selectedOption;
request.oTPSendType = type == 1 ? type : 2; //this.selectedOption == 1 ? 1 : 2; request.oTPSendType = type == 1 ? type : 2; //this.selectedOption == 1 ? 1 : 2;
request.zipCode = this.zipCode; request.zipCode = this.zipCode;
//added new parameter for other country
request.logInTokenID = this.loginTokenID ?? ""; request.logInTokenID = this.loginTokenID ?? "";
if (this.registerd_data != null) { if (this.registerd_data != null) {
@ -644,8 +671,12 @@ class _ConfirmLogin extends State<ConfirmLogin> {
}); });
}); });
} else { } else {
authService // Check if Others country (zipCode == "0") and call appropriate API
.checkActivationCode(request, value) final activationCodeCall = (this.zipCode == "0")
? authService.checkActivationCodeOthers(request, value)
: authService.checkActivationCode(request, value);
activationCodeCall
.then((result) async => { .then((result) async => {
res = result, res = result,
if (result is Map) if (result is Map)
@ -783,7 +814,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
} }
insertIMEI() { insertIMEI() {
authService.insertDeviceImei(selectedOption).then((value) => {}).catchError((err) { authService.insertDeviceImei(selectedOption, isForOthers: this.zipCode == "0").then((value) => {}).catchError((err) {
print(err); print(err);
}); });
} }
@ -846,8 +877,9 @@ class _ConfirmLogin extends State<ConfirmLogin> {
}); });
} }
Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex, {bool isDisabledForOthers = false}) {
bool isDisable = (_flag == 3 && !checkIfBiometricAvailable(BiometricType.face) || bool isDisable = isDisabledForOthers ||
(_flag == 3 && !checkIfBiometricAvailable(BiometricType.face) ||
_flag == 2 && !checkIfBiometricAvailable(BiometricType.fingerprint) && _flag == 2 && !checkIfBiometricAvailable(BiometricType.strong)); _flag == 2 && !checkIfBiometricAvailable(BiometricType.fingerprint) && _flag == 2 && !checkIfBiometricAvailable(BiometricType.strong));
return InkWell( return InkWell(
onTap: isDisable onTap: isDisable
@ -894,18 +926,21 @@ class _ConfirmLogin extends State<ConfirmLogin> {
// todo 'sikander' optimize this after knowing usage // todo 'sikander' optimize this after knowing usage
Widget getButton(int flag) { Widget getButton(int flag) {
// Disable SMS for Others country (zipCode == "0")
bool isDisabledForOthers = (flag == 1 && this.zipCode == "0");
switch (flag) { switch (flag) {
case 4: case 4:
return _loginOptionButton(TranslationBase.of(context).verifyWhatsApp, 'assets/images/new/verify_whatsapp.svg', flag, null); return _loginOptionButton(TranslationBase.of(context).verifyWhatsApp, 'assets/images/new/verify_whatsapp.svg', flag, null, isDisabledForOthers: false);
break; break;
case 1: case 1:
return _loginOptionButton(TranslationBase.of(context).verifySMS, 'assets/images/new/verify_sms.svg', flag, null); return _loginOptionButton(TranslationBase.of(context).verifySMS, 'assets/images/new/verify_sms.svg', flag, null, isDisabledForOthers: isDisabledForOthers);
break; break;
case 2: case 2:
return _loginOptionButton(TranslationBase.of(context).verifyFingerprint, 'assets/images/new/verify_thumb.svg', flag, BiometricType.fingerprint.index); return _loginOptionButton(TranslationBase.of(context).verifyFingerprint, 'assets/images/new/verify_thumb.svg', flag, BiometricType.fingerprint.index, isDisabledForOthers: false);
break; break;
case 3: case 3:
return _loginOptionButton(TranslationBase.of(context).verifyFaceID, 'assets/images/new/verify_face.svg', flag, BiometricType.face.index); return _loginOptionButton(TranslationBase.of(context).verifyFaceID, 'assets/images/new/verify_face.svg', flag, BiometricType.face.index, isDisabledForOthers: false);
break; break;
default: default:

@ -198,7 +198,7 @@ class _Login extends State<Login> {
TextField( TextField(
enabled: isEnable, enabled: isEnable,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
keyboardType: TextInputType.number, keyboardType: countryCode =='0'? TextInputType.text: TextInputType.number,
controller: _controller, controller: _controller,
onChanged: (value) => {validateForm()}, onChanged: (value) => {validateForm()},
style: TextStyle( style: TextStyle(
@ -254,8 +254,13 @@ class _Login extends State<Login> {
} }
void validateForm() { void validateForm() {
if (util.validateIDBox(nationalIDorFile.text, loginType) == true && // For "Others" country, skip Saudi ID validation
(countryCode == "971" ? true : util.isSAUDIIDValid(nationalIDorFile.text, loginType) == true)) { bool idValidation = util.validateIDBox(nationalIDorFile.text, loginType) == true || countryCode == "0";
bool countrySpecificValidation = (countryCode == "971" || countryCode == "0")
? true
: util.isSAUDIIDValid(nationalIDorFile.text, loginType) == true;
if (idValidation && countrySpecificValidation && mobileNo != null && mobileNo!.isNotEmpty) {
setState(() { setState(() {
isButtonDisabled = false; isButtonDisabled = false;
}); });
@ -270,7 +275,18 @@ class _Login extends State<Login> {
// showLoader(true); // showLoader(true);
var request = CheckPatientAuthenticationReq(); var request = CheckPatientAuthenticationReq();
request.isRegister = false; request.isRegister = false;
request.patientMobileNumber = int.parse(mobileNo!);
// For Others country (countryCode == "0"), pass mobile number as STRING
// For KSA/UAE, pass mobile number as INT
if (countryCode == "0") {
// Mobile number as string for international format (e.g., "+1234567890")
request.patientMobileNumberOthers = mobileNo; // String
} else {
// Mobile number as integer for KSA/UAE (e.g., 501234567)
request.patientMobileNumber = int.parse(mobileNo!); // Int
}
request.zipCode = countryCode; request.zipCode = countryCode;
request.searchType = this.loginType; request.searchType = this.loginType;
request.deviceTypeID = this.loginType; request.deviceTypeID = this.loginType;
@ -283,7 +299,14 @@ class _Login extends State<Login> {
} }
sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request); sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request);
GifLoaderDialogUtils.showMyDialog(context); GifLoaderDialogUtils.showMyDialog(context);
authService.checkPatientAuthentication(request).then((value) {
// Use checkPatientAuthenticationOthers for Others country (countryCode == "0")
// Use checkPatientAuthentication for KSA/UAE (countryCode == "966" or "971")
final authCall = (countryCode == "0")
? authService.checkPatientAuthenticationOthers(request)
: authService.checkPatientAuthentication(request);
authCall.then((value) {
// if (value['UserAccountIsActivated']) { // if (value['UserAccountIsActivated']) {
if (value['isSMSSent']) { if (value['isSMSSent']) {
sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']);

@ -34,13 +34,17 @@ AppSharedPreferences sharedPref = AppSharedPreferences();
AppGlobal appGlobal = AppGlobal(); AppGlobal appGlobal = AppGlobal();
const String INSERT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; const String INSERT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI';
const INSERT_DEVICE_IMEI_OTHERS ='Services/Patients.svc/REST/Patient_INSERTDeviceIMEI_Others';
const String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; const String SELECT_DEVICE_IMEI = 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI';
const String CHECK_PATIENT_AUTH = 'Services/Authentication.svc/REST/CheckPatientAuthentication'; const String CHECK_PATIENT_AUTH = 'Services/Authentication.svc/REST/CheckPatientAuthentication';
const String CHECK_PATIENT_AUTH_OTHERS = 'Services/Authentication.svc/REST/CheckPatientAuthentication_Others';
const GET_MOBILE_INFO = 'Services/Authentication.svc/REST/GetMobileLoginInfo'; const GET_MOBILE_INFO = 'Services/Authentication.svc/REST/GetMobileLoginInfo';
const SEND_ACTIVATION_CODE = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType'; const SEND_ACTIVATION_CODE = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
const SEND_ACTIVATION_CODE_OTHERS = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationType_Others';
const SEND_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration'; const SEND_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/SendActivationCodebyOTPNotificationTypeForRegistration';
const CHECK_ACTIVATION_CODE = 'Services/Authentication.svc/REST/CheckActivationCode'; const CHECK_ACTIVATION_CODE = 'Services/Authentication.svc/REST/CheckActivationCode';
const CHECK_ACTIVATION_CODE_OTHERS = 'Services/Authentication.svc/REST/CheckActivationCode_Others';
const CHECK_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration'; const CHECK_ACTIVATION_CODE_REGISTER = 'Services/Authentication.svc/REST/CheckActivationCodeForRegistration';
const FORGOT_PASSWORD = 'Services/Authentication.svc/REST/CheckActivationCodeForSendFileNo'; const FORGOT_PASSWORD = 'Services/Authentication.svc/REST/CheckActivationCodeForSendFileNo';
@ -111,7 +115,7 @@ class AuthProvider with ChangeNotifier {
// } // }
// } // }
Future<dynamic> insertDeviceImei(lstLogin) async { Future<dynamic> insertDeviceImei(lstLogin,{ bool isForOthers = false}) async {
try { try {
dynamic localRes; dynamic localRes;
var lastLogin = lstLogin; //await sharedPref.getInt( var lastLogin = lstLogin; //await sharedPref.getInt(
@ -137,9 +141,8 @@ class AuthProvider with ChangeNotifier {
newRequest.patientType = request.patientType; newRequest.patientType = request.patientType;
newRequest.setupID = request.setupID; newRequest.setupID = request.setupID;
newRequest.tokenID = await sharedPref.getString(TOKEN); newRequest.tokenID = await sharedPref.getString(TOKEN);
// }
await new BaseAppClient().post(INSERT_DEVICE_IMEI, onSuccess: (dynamic response, int statusCode) { await new BaseAppClient().post(isForOthers ? INSERT_DEVICE_IMEI_OTHERS : INSERT_DEVICE_IMEI, onSuccess: (dynamic response, int statusCode) {
localRes = response; localRes = response;
}, onFailure: (String error, int statusCode) { }, onFailure: (String error, int statusCode) {
throw error; throw error;
@ -196,7 +199,7 @@ class AuthProvider with ChangeNotifier {
request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1; request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1;
try { try {
dynamic localRes; dynamic localRes;
await new BaseAppClient().post(CHECK_PATIENT_AUTH, onSuccess: (dynamic response, int statusCode) { await new BaseAppClient().post( request.zipCode =='0' ? CHECK_PATIENT_AUTH_OTHERS : CHECK_PATIENT_AUTH, onSuccess: (dynamic response, int statusCode) {
localRes = response; localRes = response;
}, onFailure: (String error, int statusCode) { }, onFailure: (String error, int statusCode) {
throw error; throw error;
@ -208,6 +211,27 @@ class AuthProvider with ChangeNotifier {
} }
} }
// New function for Others country authentication
Future<dynamic> checkPatientAuthenticationOthers(CheckPatientAuthenticationReq request) async {
request.versionID = VERSION_ID;
request.channel = CHANNEL;
request.iPAdress = IP_ADDRESS;
request.generalid = GENERAL_ID;
request.languageID = (languageID == 'ar' ? 1 : 2);
request.patientOutSA = 1; // Always set to 1 for Others (outside KSA/UAE)
try {
dynamic localRes;
await new BaseAppClient().post(CHECK_PATIENT_AUTH_OTHERS, onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
throw error;
}, body: request.toJson());
return Future.value(localRes);
} catch (error) {
throw error;
}
}
Future<dynamic> getLoginInfo(request) async { Future<dynamic> getLoginInfo(request) async {
request.versionID = VERSION_ID; request.versionID = VERSION_ID;
request.channel = CHANNEL; request.channel = CHANNEL;
@ -249,6 +273,28 @@ class AuthProvider with ChangeNotifier {
return Future.value(localRes); return Future.value(localRes);
} }
// New method for Others country activation code
Future<dynamic> sendActivationCodeOthers(request) async {
request.versionID = VERSION_ID;
request.channel = CHANNEL;
request.iPAdress = IP_ADDRESS;
request.generalid = GENERAL_ID;
// request.languageID = (languageID == 'ar' ? 1 : 2);
request.languageID = 2;
request.deviceTypeID = Platform.isIOS ? 1 : 2;
request.patientOutSA = 1; // Always 1 for Others (outside KSA/UAE)
request.isDentalAllowedBackend = false;
dynamic localRes;
await new BaseAppClient().post(SEND_ACTIVATION_CODE_OTHERS, onSuccess: (dynamic response, int statusCode) {
localRes = response;
authenticatedUser = CheckActivationCode.fromJson(localRes);
}, onFailure: (String error, int statusCode) {
throw error;
}, body: request.toJson());
return Future.value(localRes);
}
Future<dynamic> sendActivationCodeRegister(request) async { Future<dynamic> sendActivationCodeRegister(request) async {
request.versionID = VERSION_ID; request.versionID = VERSION_ID;
request.channel = CHANNEL; request.channel = CHANNEL;
@ -282,6 +328,8 @@ class AuthProvider with ChangeNotifier {
neRequest.patientOutSA = neRequest.zipCode == '966' ? 0 : 1; neRequest.patientOutSA = neRequest.zipCode == '966' ? 0 : 1;
neRequest.projectOutSA = neRequest.zipCode == '966' ? false : true; neRequest.projectOutSA = neRequest.zipCode == '966' ? false : true;
neRequest.isDentalAllowedBackend = false; neRequest.isDentalAllowedBackend = false;
// neRequest.zipCode ='966'; //hardcoded for testing
// request.languageID = (languageID == 'ar' ? 1 : 2)
// neRequest.deviceToken = null; // neRequest.deviceToken = null;
neRequest.forRegisteration = neRequest.isRegister != null ? neRequest.isRegister : false; neRequest.forRegisteration = neRequest.isRegister != null ? neRequest.isRegister : false;
neRequest.isRegister = false; neRequest.isRegister = false;
@ -300,6 +348,35 @@ class AuthProvider with ChangeNotifier {
} }
} }
Future<dynamic> checkActivationCodeOthers(request, [value]) async {
var neRequest = CheckActivationCodeReq.fromJson(request);
neRequest.activationCode = value ?? "0000";
neRequest.isSilentLogin = value != null ? false : true;
neRequest.versionID = VERSION_ID;
neRequest.channel = CHANNEL;
neRequest.iPAdress = IP_ADDRESS;
neRequest.generalid = GENERAL_ID;
neRequest.deviceTypeID = Platform.isIOS ? 1 : 2;
neRequest.patientOutSA = 1; // Always 1 for Others (outside KSA/UAE)
neRequest.projectOutSA = true; // Always true for Others
neRequest.isDentalAllowedBackend = false;
neRequest.forRegisteration = neRequest.isRegister != null ? neRequest.isRegister : false;
neRequest.isRegister = false;
dynamic localRes;
try {
await new BaseAppClient().post(CHECK_ACTIVATION_CODE_OTHERS, onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
localRes = error;
return Future.value(error);
}, body: neRequest.toJson());
return Future.value(localRes);
} catch (error) {
throw localRes;
}
}
Future<dynamic> checkActivationCodeRegister(request, [value]) async { Future<dynamic> checkActivationCodeRegister(request, [value]) async {
var neRequest = CheckActivationCodeRegisterReq.fromJson(request); var neRequest = CheckActivationCodeRegisterReq.fromJson(request);
@ -574,8 +651,7 @@ class AuthProvider with ChangeNotifier {
// { // {
// "ID": 12, // "ID": 12,
// "ServiceName": "Precriptions", // "ServiceName": "Precriptions",
// "Previlege": true, // "Previlege": true,// "Region": null
// "Region": null
// }, // },
// { // {
// "ID": 13, // "ID": 13,

@ -30,6 +30,11 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
List<Countries> counties = []; List<Countries> counties = [];
ProjectViewModel? projectProvider; ProjectViewModel? projectProvider;
TextEditingController textController = new TextEditingController(); TextEditingController textController = new TextEditingController();
String? validationError;
// Regular expression to detect KSA (+966) or UAE (+971) phone numbers
// Matches: +966, 966, 00966, +971, 971, 00971 at the start
final RegExp ksaUaePattern = RegExp(r'^(\+|00)?(966|971)');
@override @override
void initState() { void initState() {
@ -38,6 +43,19 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
super.initState(); super.initState();
} }
// Validate phone number when "Others" is selected
String? validatePhoneNumber(String value) {
if (countryCode == "0" && value.isNotEmpty) {
// Check if the number starts with KSA or UAE country code
if (ksaUaePattern.hasMatch(value)) {
return projectProvider?.isArabic == true
? "يرجى عدم إدخال أرقام السعودية أو الإمارات. استخدم الخيار المناسب من القائمة"
: "Please do not enter KSA or UAE numbers. Use the appropriate option from the list";
}
}
return null;
}
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
@ -56,16 +74,43 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
} }
} }
// Check if "Others" is selected (code == "0")
bool isOthersSelected = countryCode == "0";
return Column( return Column(
children: [ children: [
inputWidget(TranslationBase.of(context).country, countryName!, isEnable: true, hasSelection: true), inputWidget(TranslationBase.of(context).country, countryName!, isEnable: true, hasSelection: true),
SizedBox(height: 12), SizedBox(height: 12),
Directionality(textDirection: TextDirection.ltr, child: inputWidget(TranslationBase.of(context).phoneNumber, isEnable: widget.isEnable, widget.mobileNo ?? "5xxxxxxxx", prefix: countryCode)), Directionality(
textDirection: TextDirection.ltr,
child: inputWidget(
TranslationBase.of(context).phoneNumber,
isEnable: widget.isEnable,
widget.mobileNo ?? (isOthersSelected ? "" : "5xxxxxxxx"),
prefix: isOthersSelected ? null : countryCode
)
),
if (validationError != null)
Container(
width: double.infinity,
margin: EdgeInsets.only(top: 8),
child: Text(
validationError!,
style: TextStyle(
color: Colors.red,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
], ],
); );
} }
Widget inputWidget(String _labelText, String _hintText, {String? prefix, bool isEnable = true, bool hasSelection = false}) { Widget inputWidget(String _labelText, String _hintText, {String? prefix, bool isEnable = true, bool hasSelection = false}) {
// Check if "Others" is selected
bool isOthersSelected = countryCode == "0";
return Container( return Container(
padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15),
alignment: Alignment.center, alignment: Alignment.center,
@ -73,8 +118,8 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
color: Colors.white, color: Colors.white,
border: Border.all( border: Border.all(
color: Color(0xffefefef), color: validationError != null ? Colors.red : Color(0xffefefef),
width: 1, width: validationError != null ? 1.5 : 1,
), ),
), ),
child: PopupMenuButton( child: PopupMenuButton(
@ -99,8 +144,20 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
controller: hasSelection ? null : textController, controller: hasSelection ? null : textController,
enabled: isEnable, enabled: isEnable,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
keyboardType: TextInputType.number, keyboardType: isOthersSelected ? TextInputType.phone : TextInputType.number,
onChanged: (value) => widget.onNumberChange!(value), onChanged: (value) {
// Validate the phone number
setState(() {
validationError = validatePhoneNumber(value);
});
// Only call the callback if validation passes
if (validationError == null) {
widget.onNumberChange!(value);
} else {
// Call with empty value to invalidate the form
widget.onNumberChange!("");
}
},
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
height: 21 / 14, height: 21 / 14,
@ -135,6 +192,8 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
border: InputBorder.none, border: InputBorder.none,
focusedBorder: InputBorder.none, focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
), ),
), ),
], ],
@ -151,6 +210,11 @@ class _PhoneNumberSelectorWidgetState extends State<PhoneNumberSelectorWidget> {
setState(() { setState(() {
this.countryCode = countryCode; this.countryCode = countryCode;
_selectedType = countryCode; _selectedType = countryCode;
// Clear the text field and validation error when switching to/from "Others"
if (countryCode == "0" || this.countryCode == "0") {
textController.clear();
validationError = null;
}
}); });
widget.onCountryChange!(countryCode); widget.onCountryChange!(countryCode);
}, },

@ -265,15 +265,26 @@ class SMSOTP {
startTimer(setState) { startTimer(setState) {
this.remainingTime--; this.remainingTime--;
setState(() { // Check if the widget is still mounted before calling setState
displayTime = this.getSecondsAsDigitalClock(this.remainingTime); try {
}); setState(() {
displayTime = this.getSecondsAsDigitalClock(this.remainingTime);
});
} catch (e) {
// Widget is no longer mounted, stop the timer
return;
}
timer = Future.delayed(Duration(seconds: 1), () { timer = Future.delayed(Duration(seconds: 1), () {
if (this.remainingTime > 0) { if (this.remainingTime > 0) {
startTimer(setState); startTimer(setState);
} else { } else {
Navigator.pop(context); // Check if context is still valid before trying to pop
try {
Navigator.pop(context);
} catch (e) {
// Context is no longer valid, ignore
}
} }
}); });
} }

Loading…
Cancel
Save