You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_Patient_App/lib/pages/login/saved_login.dart

714 lines
28 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app/config/config.dart';
import 'package:hmg_patient_app/config/shared_pref_kay.dart';
import 'package:hmg_patient_app/core/service/client/base_app_client.dart';
import 'package:hmg_patient_app/core/viewModels/appointment_rate_view_model.dart';
import 'package:hmg_patient_app/core/viewModels/project_view_model.dart';
import 'package:hmg_patient_app/extensions/string_extensions.dart';
import 'package:hmg_patient_app/locator.dart';
import 'package:hmg_patient_app/models/Appointments/toDoCountProviderModel.dart';
import 'package:hmg_patient_app/models/Authentication/authenticated_user.dart';
import 'package:hmg_patient_app/models/Authentication/check_activation_code_response.dart';
import 'package:hmg_patient_app/models/Authentication/check_paitent_authentication_req.dart';
import 'package:hmg_patient_app/models/Authentication/select_device_imei_res.dart';
import 'package:hmg_patient_app/models/InPatientServices/get_admission_info_response_model.dart';
import 'package:hmg_patient_app/models/InPatientServices/get_admission_request_info_response_model.dart';
import 'package:hmg_patient_app/new_ui/otp/otp_validation_bootmsheet_widget.dart';
import 'package:hmg_patient_app/pages/landing/landing_page.dart';
import 'package:hmg_patient_app/pages/login/register_new.dart';
import 'package:hmg_patient_app/pages/login/user-login-agreement-page.dart';
import 'package:hmg_patient_app/pages/login/welcome.dart';
import 'package:hmg_patient_app/pages/rateAppointment/rate_appointment_doctor.dart';
import 'package:hmg_patient_app/services/authentication/auth_provider.dart' hide sharedPref;
import 'package:hmg_patient_app/services/clinic_services/get_clinic_service.dart';
import 'package:hmg_patient_app/theme/colors.dart';
import 'package:hmg_patient_app/uitl/app_toast.dart';
import 'package:hmg_patient_app/uitl/date_uitl.dart';
import 'package:hmg_patient_app/uitl/font_utils.dart';
import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart';
import 'package:hmg_patient_app/uitl/translations_delegate_base.dart';
import 'package:hmg_patient_app/uitl/utils.dart' hide sharedPref;
import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart';
import 'package:hmg_patient_app/widgets/otp/sms-popup.dart';
import 'package:hmg_patient_app/widgets/text/app_texts_widget.dart';
import 'package:hmg_patient_app/widgets/transitions/fade_page.dart';
import 'package:local_auth/local_auth.dart';
import 'package:provider/provider.dart';
import '../../widgets/dialogs/confirm_dialog.dart';
class SavedLogin extends StatefulWidget {
final SelectDeviceIMEIRES savedLoginData;
const SavedLogin(this.savedLoginData, {Key? key}) : super(key: key);
@override
_SavedLogin createState() => _SavedLogin();
}
class _SavedLogin extends State<SavedLogin> {
TextEditingController? phoneController;
final authService = AuthProvider();
late ProjectViewModel projectViewModel;
late ToDoCountProviderModel toDoProvider;
Country selectedCountry = Country.saudiArabia;
AppointmentRateViewModel appointmentRateViewModel = locator<AppointmentRateViewModel>();
String? phoneNumber;
@override
void initState() {
super.initState();
phoneController = TextEditingController(text: widget.savedLoginData.mobile!.startsWith('0') ? widget.savedLoginData.mobile!.substring(1) : widget.savedLoginData.mobile);
phoneNumber = widget.savedLoginData.mobile!.startsWith('0') ? widget.savedLoginData.mobile!.substring(1) : widget.savedLoginData.mobile;
if (widget.savedLoginData.logInType! == 2 || widget.savedLoginData.logInType! == 3) {
loginWithFingerPrintFace(widget.savedLoginData.logInType!, widget.savedLoginData.iMEI!);
}
}
@override
Widget build(BuildContext context) {
projectViewModel = Provider.of(context);
toDoProvider = Provider.of(context);
return AppScaffold(
appBarTitle: TranslationBase.of(context).register,
isShowDecPage: false,
isShowAppBar: true,
isshowBackButton: true,
showNewAppBar: true,
backgroundColor: Color(0xffF8F8F8),
showNewAppBarTitle: false,
showDropDown: true,
isShowLanguageChanger: true,
appBarIcons: [],
dropDownList: [],
resizeToAvoidBottomInset: true,
showCenteredLogo: true,
showLastLoginScreenBar: true,
dropDownIndexChange: (value) {
Utils.changeAppLanguage(context: context);
},
// backgroundColor: const Color(0xFFF8F8FA),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Spacer(flex: 2),
// Welcome back text
Text(
TranslationBase.of(context).welcomeBack,
style: context.dynamicTextStyle(
fontSize: 22,
color: Color(0xFF898A8D),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 16),
// Names
Column(
children: [
Text(
widget.savedLoginData.name!.toLowerCase().capitalizeFirstofEach,
style: context.dynamicTextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: Color(0xFF2E3039),
height: 26 / 36,
letterSpacing: -0.4,
),
),
// Text(
// 'Abdul Ghaffar',
// style: TextStyle(
// fontSize: 28,
// fontWeight: FontWeight.bold,
// color: Colors.grey[800],
// ),
// ),
],
),
const SizedBox(height: 24),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(24.0),
boxShadow: [
BoxShadow(
color: Color(0x0D000000),
blurRadius: 16,
offset: Offset(0, 0),
spreadRadius: 5,
),
],
),
child: Column(
children: [
// Last login info
Text(
TranslationBase.of(context).lastloginBy + ' ${getType(widget.savedLoginData.logInType!, context)}',
style: context.dynamicTextStyle(
fontSize: 16,
color: Color(0xFF8F9AA3),
fontWeight: FontWeight.w600,
),
),
Text(
widget.savedLoginData.createdOn != null ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(widget.savedLoginData.createdOn!), "d MMMM, y 'at' HH:mm") : '--',
style: context.dynamicTextStyle(
fontSize: 16,
color: Color(0xFF2E3039),
fontWeight: FontWeight.w600,
),
),
Container(
margin: EdgeInsets.all(16),
child: SvgPicture.asset(
getTypeIcons(widget.savedLoginData.logInType!, context),
color: widget.savedLoginData.logInType == 4 ? null : Color(0xFFED1C2B),
height: 64,
width: 64,
),
),
// Face ID login button
Container(
height: 45,
child: CustomButton(
text: "${TranslationBase.of(context).loginBy} ${getType(widget.savedLoginData.logInType!, context)}",
onPressed: () {
if (widget.savedLoginData.logInType! == 2 || widget.savedLoginData.logInType! == 3) {
loginWithFingerPrintFace(widget.savedLoginData.logInType!, widget.savedLoginData.iMEI!);
} else {
int? val = widget.savedLoginData.logInType!;
checkUserAuthentication(val);
}
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
fontSize: 12,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
// icon: "assets/images/svg/apple-finder.svg",
),
),
],
),
),
const SizedBox(height: 24),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
TranslationBase.of(context).oR,
style: context.dynamicTextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
),
const SizedBox(height: 24),
// OTP login button
widget.savedLoginData.logInType != null && widget.savedLoginData.logInType != 1
? CustomButton(
text: TranslationBase.of(context).loginByOTP,
onPressed: () {
if (widget.savedLoginData.logInType! == 2 || widget.savedLoginData.logInType! == 3) {
loginWithFingerPrintFace(widget.savedLoginData.logInType!, widget.savedLoginData.iMEI!);
} else {
widget.savedLoginData.logInType = 1;
int? val = widget.savedLoginData.logInType!;
checkUserAuthentication(val);
}
},
backgroundColor: Colors.white,
borderColor: Color(0xFF2E3039),
textColor: Color(0xFF2E3039),
borderWidth: 2,
padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
icon: "assets/images/svg/password-validation.svg",
)
: CustomButton(
text: "${TranslationBase.of(context).loginBy} ${getType(4, context)}",
onPressed: () {
if (widget.savedLoginData.logInType! == 2 || widget.savedLoginData.logInType! == 3) {
loginWithFingerPrintFace(widget.savedLoginData.logInType!, widget.savedLoginData.iMEI!);
} else {
widget.savedLoginData.logInType = 4;
int? val = widget.savedLoginData.logInType!;
checkUserAuthentication(val);
}
},
backgroundColor: Colors.white,
borderColor: Color(0xFF2E3039),
textColor: Color(0xFF2E3039),
borderWidth: 2,
padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
icon: "assets/images/svg/whatsapp.svg",
),
const Spacer(flex: 2),
// OR divider
const SizedBox(height: 24),
// Guest and Switch account
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (BuildContext context) => LandingPage(),
),
);
},
child: Text(
TranslationBase.of(context).guest,
style: context.dynamicTextStyle(color: CustomColors.bgRedColor, fontSize: 16, fontWeight: FontWeight.w500, height: 16 / 26),
),
),
const SizedBox(width: 24),
TextButton(
onPressed: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (BuildContext context) => WelcomeLogin(),
),
);
},
child: Text(
TranslationBase.of(context).switchAccount,
style: context.dynamicTextStyle(color: CustomColors.bgRedColor, fontSize: 16, fontWeight: FontWeight.w500, height: 16 / 26),
),
),
],
),
const SizedBox(height: 20),
],
),
),
),
);
}
String getType(int type, BuildContext context) {
final t = TranslationBase.of(context);
final types = {
1: t.verifySMS,
2: t.verifyFingerprint,
3: t.verifyFaceID,
4: t.verifyWhatsApp,
};
return types[type] ?? t.verifySMS;
}
//need to move this function on provider to avoid multiple repeat
loginWithFingerPrintFace(type, String deviceToken) async {
bool authenticated = false;
final LocalAuthentication auth = LocalAuthentication();
try {
authenticated = await auth.authenticate(
localizedReason: 'Scan your fingerprint to authenticate',
options: const AuthenticationOptions(
useErrorDialogs: true,
stickyAuth: true,
),
authMessages: [
// Optional: uncomment for iOS custom messages
// IOSAuthMessages(
// cancelButton: 'Cancel',
// goToSettingsButton: 'Settings',
// goToSettingsDescription: 'Please set up your Touch ID.',
// lockOut: 'Please re-enable your Touch ID.',
// ),
],
);
} on PlatformException catch (e) {
GifLoaderDialogUtils.hideDialog(context);
AppToast.showErrorToast(message: 'Please enable your Touch or Face ID');
return;
}
if (authenticated) {
int lastLogin = 1;
var availableBiometrics = await auth.getAvailableBiometrics();
if (availableBiometrics.contains(BiometricType.strong)) {
lastLogin = 3; // Assume Face or secure fingerprint
} else if (availableBiometrics.contains(BiometricType.weak)) {
lastLogin = 2; // Likely weak fingerprint
}
var request = authService.getCommonRequest(
type: type,
registerd_data: null,
deviceToken: widget.savedLoginData.iMEI,
mobileNumber: int.parse(widget.savedLoginData.mobile!),
zipCode: widget.savedLoginData.outSA == 1 ? '971' : '966',
patientOutSA: widget.savedLoginData.outSA,
loginTokenID: null,
selectedOption: lastLogin,
user: widget.savedLoginData,
);
getMobileInfo(request, lastLogin);
}
}
getMobileInfo(request, int lastLogin) async {
GifLoaderDialogUtils.showMyDialog(context);
this.authService.getLoginInfo(request).then((result) {
GifLoaderDialogUtils.hideDialog(context);
if (result['SMSLoginRequired'] == false) {
// this.loginTokenID = result['LogInTokenID'];
// this.patientOutSA = result['PatientOutSA'];
// setDefault();
sharedPref.setInt(LAST_LOGIN, lastLogin);
checkActivationCode(null, lastLogin, result['LogInTokenID']);
} else if (result['ErrorEndUserMessage'] != null) {
ConfirmDialog dialog = new ConfirmDialog(
context: context,
confirmMessage: result['ErrorEndUserMessage'],
okText: TranslationBase.of(context).confirm,
cancelText: TranslationBase.of(context).cancel_nocaps,
okFunction: () => {
ConfirmDialog.closeAlertDialog(context),
Navigator.of(context).pushReplacement(FadePage(page: WelcomeLogin())),
},
cancelFunction: () => {});
dialog.showAlertDialog(context);
}
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
print(err);
});
}
checkActivationCode(String? value, int loginType, String? loginToken) async {
AppGlobal.context = context;
GifLoaderDialogUtils.showMyDialog(context);
var request = authService
.getCommonRequest(
type: loginType,
registerd_data: null,
deviceToken: widget.savedLoginData.iMEI,
mobileNumber: int.parse(widget.savedLoginData.mobile!),
zipCode: widget.savedLoginData.outSA == 1 ? '971' : '966',
patientOutSA: widget.savedLoginData.outSA,
loginTokenID: loginToken ?? "",
selectedOption: loginType,
user: widget.savedLoginData,
)
.toJson();
dynamic res;
authService.checkActivationCode(request, value).then((result) async => {
res = result,
if (result is Map)
{
result = CheckActivationCode.fromJson(result as Map<String, dynamic>),
if (result.errorCode == '699')
{
//699 block run here
GifLoaderDialogUtils.hideDialog(context),
Future.delayed(Duration(seconds: 2), () {
AppToast.showErrorToast(message: result.errorEndUserMessage);
Navigator.pop(context);
})
}
else
{
sharedPref.remove(FAMILY_FILE),
result.list.isFamily = false,
// userData = result.list,
sharedPref.setString(BLOOD_TYPE, result.patientBloodType ?? ""),
//Remove o+ from here Added by Aamir
authenticatedUserObject.user = result.list,
projectViewModel.setPrivilege(privilegeList: res),
await sharedPref.setObject(MAIN_USER, result.list),
await sharedPref.setObject(USER_PROFILE, result.list),
// loginTokenID = result.logInTokenID,
await sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID),
await sharedPref.setString(TOKEN, result.authenticationTokenID),
checkIfUserAgreedBefore(result, loginType),
projectViewModel.analytics.loginRegistration.login_successful(),
}
}
else
{
// Navigator.of(context).pop(),
GifLoaderDialogUtils.hideDialog(context),
Future.delayed(Duration(seconds: 1), () {
AppToast.showErrorToast(message: result, localContext: context);
}),
projectViewModel.analytics.loginRegistration.login_fail(error: result),
projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result)
}
});
}
checkIfUserAgreedBefore(CheckActivationCode result, int type) {
if (projectViewModel.havePrivilege(109)) {
this.authService.checkIfUserAgreed().then((result) {
if (result['IsPatientAlreadyAgreed']) {
goToHome(type);
} else {
this.authService.getUserAgreementContent().then((result) {
GifLoaderDialogUtils.hideDialog(AppGlobal.context);
Navigator.pushAndRemoveUntil(
context,
FadePage(
page: UserLoginAgreementPage(
userAgreementText: result['UserAgreementContent'],
authenticatedUserObject: authenticatedUserObject,
appointmentRateViewModel: appointmentRateViewModel,
selectedOption: type,
isArabic: projectViewModel.isArabic,
),
),
(r) => false);
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
print(err);
});
}
}).catchError((err) {
GifLoaderDialogUtils.hideDialog(context);
print(err);
});
} else {
goToHome(type);
}
// if (result.isNeedUserAgreement == true) {
// // move to agreement page.
// } else {
// goToHome();
// }
}
goToHome(int type) async {
authenticatedUserObject.isLogin = true;
appointmentRateViewModel.isLogin = true;
projectViewModel.isLogin = true;
projectViewModel.user = authenticatedUserObject.user;
await authenticatedUserObject.getUser(getUser: true);
// GifLoaderDialogUtils.hideDialog(context);
getToDoCount();
checkIfIsInPatient();
appointmentRateViewModel.getIsLastAppointmentRatedList(projectViewModel.isArabic ? 1 : 2).then((_) {
GifLoaderDialogUtils.hideDialog(AppGlobal.context);
if (appointmentRateViewModel.isHaveAppointmentNotRate) {
Navigator.pushAndRemoveUntil(
context,
FadePage(page: RateAppointmentDoctor()),
(route) => false,
);
} else {
Navigator.pushAndRemoveUntil(
context,
FadePage(page: LandingPage()),
(route) => false,
);
}
insertIMEI(type);
}).catchError((error) {
print(error);
});
}
getToDoCount() {
toDoProvider.setState(0, 0, true, "0");
ClinicListService service = new ClinicListService();
service.getActiveAppointmentNo(context).then((res) {
if (res['MessageStatus'] == 1) {
toDoProvider.setState(res['AppointmentActiveNumber'], res['AncillaryOrderListCount'], true, "0");
// toDoProvider.setState(res['AppointmentActiveNumber'], true, "0");
} else {}
}).catchError((err) {
print(err);
});
}
insertIMEI(lastLogin) {
authService.insertDeviceImei(lastLogin).then((value) => {}).catchError((err) {
print(err);
});
}
checkUserAuthentication(type) async {
await GifLoaderDialogUtils.showMyDialog(context);
var req = this.authService.getCommonRequest(
type: type,
registerd_data: null,
deviceToken: widget.savedLoginData.iMEI,
mobileNumber: int.parse(widget.savedLoginData.mobile!),
zipCode: widget.savedLoginData.outSA == 1 ? '971' : '966',
patientOutSA: widget.savedLoginData.outSA,
loginTokenID: "",
selectedOption: type,
user: widget.savedLoginData,
);
var request = CheckPatientAuthenticationReq.fromJson(req.toJson());
sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request);
authService
.checkPatientAuthentication(request)
.then((value) => {
if (value['isSMSSent'])
{
sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']),
// this.loginTokenID = value['LogInTokenID'],
sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request),
// Future.delayed(Duration(seconds: 1), () {
this.sendActivationCode(type, value['LogInTokenID'])
// })
}
else
{
if (value['IsAuthenticated'])
{this.checkActivationCode(null, type, value['LogInTokenID'])}
else
{
AppToast.showErrorToast(message: value['errorMessage']),
Navigator.pushAndRemoveUntil(
context,
FadePage(
page: WelcomeLogin(),
),
(r) => false)
}
}
})
.catchError((err) {
print(err);
GifLoaderDialogUtils.hideDialog(context);
ConfirmDialog dialog = new ConfirmDialog(
context: context,
confirmMessage: err,
okText: TranslationBase.of(context).confirm,
cancelText: TranslationBase.of(context).cancel_nocaps,
okFunction: () => {
ConfirmDialog.closeAlertDialog(context),
Navigator.of(context).push(FadePage(page: RegisterNew())),
},
cancelFunction: () => {});
dialog.showAlertDialog(context);
projectViewModel.analytics.loginRegistration.login_fail(error: err.toString());
});
}
sendActivationCode(type, String loginToken) async {
var request = this.authService.getCommonRequest(
type: type,
registerd_data: null,
deviceToken: widget.savedLoginData.iMEI,
mobileNumber: int.parse(widget.savedLoginData.mobile!),
zipCode: widget.savedLoginData.outSA == 1 ? '971' : '966',
patientOutSA: widget.savedLoginData.outSA,
loginTokenID: loginToken,
selectedOption: type,
user: widget.savedLoginData,
);
request.sMSSignature = await SMSOTP.getSignature();
// GifLoaderDialogUtils.showMyDialog(context);
request.dob = "";
request.healthId = "";
request.isHijri = 0;
await this.authService.sendActivationCode(request).then((result) {
GifLoaderDialogUtils.hideDialog(context);
if (result != null && result['isSMSSent'] == true) {
this.startSMSService(type, loginToken);
}
}).catchError((r) {
GifLoaderDialogUtils.hideDialog(context);
AppToast.showErrorToast(message: r.toString());
});
}
var tempType;
//
// startSMSService(type, String loginToken) {
// tempType = type;
// SMSOTP(
// context,
// type,
// phoneController.text,
// (value) {
// this.checkActivationCode(value, type, loginToken);
// },
// () => {
// Navigator.pop(context),
// },
// ).displayDialog(context);
// }
startSMSService(type, String loginToken) {
tempType = type;
late SMSOTP smsOtp; // Declare the variable first
smsOtp = SMSOTP(
context,
type,
phoneController!.text,
(code) {
smsOtp.dispose(); // Now we can reference it
this.checkActivationCode(code, type, loginToken);
},
() {
smsOtp.dispose(); // Now we can reference it
Navigator.pop(context);
},
);
smsOtp.displayDialog(context);
}
void checkIfIsInPatient() {
final service = ClinicListService();
service.checkIfInPatientAPI(context).then((res) {
if (res['MessageStatus'] != 1) return;
final isAdmitted = res['isAdmitted'] == true;
final hasAdmissionRequest = res['hasAdmissionRequests'] == true;
print("IS ADMITTED: $isAdmitted");
print("Has Admission Request: $hasAdmissionRequest");
if (isAdmitted && res['PatientAdmittedInformation']?.isNotEmpty == true) {
final info = GetAdmissionInfoResponseModel.fromJson(res['PatientAdmittedInformation'][0]);
projectViewModel.setInPatientProjectID(res['PatientAdmittedInformation'][0]['ProjectID']);
projectViewModel.setInPatientAdmissionInfo(info);
projectViewModel.setIsPatientAdmitted(true);
}
if (hasAdmissionRequest && res['MedicalInstruction']?.isNotEmpty == true) {
final reqInfo = GetAdmissionRequestInfoResponseModel.fromJson(res['MedicalInstruction'][0]);
projectViewModel.setInPatientProjectID(res['MedicalInstruction'][0]['projectId']);
projectViewModel.setInPatientAdmissionRequest(reqInfo);
projectViewModel.setPatientHasAdmissionRequest(true);
}
});
}
String getTypeIcons(int type, BuildContext context) {
String path = 'assets/images/svg/';
final types = {
1: path + 'sms.svg',
2: path + 'fingerprint.svg',
3: path + 'apple-finder.svg',
4: path + 'whatsapp.svg',
};
return types[type] ?? path + 'sms.svg';
}
}