post_enrollment_app/lib/pages/login.dart
2026-02-13 10:25:27 +05:30

2215 lines
114 KiB
Dart
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:nhance_app_pwa/pages/email_verify.dart';
import 'package:nhance_app_pwa/pages/service/SessionManager.dart';
import 'package:nhance_app_pwa/pages/service/TokenService.dart';
import 'package:nhance_app_pwa/pages/verify.dart';
import 'dart:convert';
import 'dart:io';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:google_fonts/google_fonts.dart';
import '../config/environment.dart';
import '../customAppBar/responsive.dart';
import '../customAppBar/toastHelper.dart';
import '../models/platform_helper_mobile.dart'
if (dart.library.html) '../models/platform_helper_other.dart';
import 'package:pinput/pinput.dart';
class login extends StatefulWidget {
const login({Key? key});
@override
State<login> createState() => _loginState();
}
class _loginState extends State<login> {
final TextEditingController emailMobileController = TextEditingController();
final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final TextEditingController resetPasswordController = TextEditingController();
final TextEditingController confirmPasswordController =
TextEditingController();
final TextEditingController _otpController = TextEditingController();
TextEditingController countryController = TextEditingController();
TextEditingController mobileController = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool _isCheckingToken = false;
dynamic empMobileNo;
dynamic empEmailid;
int switcherStatus = 1;
int selectedIndex = 1;
dynamic _preToken;
dynamic _postToken;
dynamic clientName;
dynamic clientLogo;
late String _verificationId;
int? _resendToken;
bool _isLoading = false;
bool isEmailFieldVisible = false;
bool _obscurePassword = true;
bool _resetObscurePassword = true;
bool _obscureConfirmPassword = true;
late SessionManager session;
bool clickedForgotPassword = false;
bool resetPasswordEnable = false;
bool otpFieldShow = false;
bool otpValueStatus = false;
final defaultPinTheme = PinTheme(
width: 56,
height: 56,
textStyle: TextStyle(
fontSize: 20,
color: Color.fromRGBO(30, 60, 87, 1),
fontWeight: FontWeight.w600,
),
decoration: BoxDecoration(
border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
borderRadius: BorderRadius.circular(20),
),
);
bool hasMinLength = false;
bool hasUpperLower = false;
bool hasNumber = false;
bool hasSpecialChar = false;
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
@override
void initState() {
countryController.text = "+91";
super.initState();
// checkLoginPinOnMobile();
}
void validatePassword(String password) {
setState(() {
hasMinLength = password.length >= 8;
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
hasSpecialChar = RegExp(r'(?=.*[@$!%*#?&])').hasMatch(password);
});
}
Future<void> checkLoginPinOnMobile() async {
if (isMobilePlatform()) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
// final skipStatus = prefs.getInt('skipStatus') ?? 1;
// if(skipStatus == 0){
empMobileNo = prefs.getString('empMobileNo');
empEmailid = prefs.getString('empEmailid');
if ((empMobileNo != null && empMobileNo.isNotEmpty) ||
(empEmailid != null && empEmailid.isNotEmpty)) {
checkLoginPin(context);
}
// }
} else {
if (kIsWeb) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.clear();
print('Local Storage Clear');
}
}
}
Future<void> checkLoginPin(BuildContext context) async {
print('checkLoginPin');
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
empMobileNo = prefs.getString('empMobileNo');
empEmailid = prefs.getString('empEmailid');
print('empMobileNo $empMobileNo');
print('empEmailid $empEmailid');
// _token = prefs.getString('token');
var params = {};
if (empMobileNo != null && empMobileNo.isNotEmpty) {
params = {'mobile_number': empMobileNo};
} else if (empEmailid != null && empEmailid.isNotEmpty) {
params = {'email_id': empEmailid};
}
final response = await http.post(
Uri.parse(Environment.apiUrlEnrollment + 'checkMpin'),
body: json.encode(params),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
if (data['status'] == 'success') {
print('data');
if (data['data'] != null) {
prefs.setString('mpinText', data['data']);
}
if (data['Mpin'] != null) {
prefs.setString('mpin', data['Mpin']);
}
if (data['is_biometric_enabled'] != null) {
prefs.setString(
'is_biometric_enabled', data['is_biometric_enabled']);
}
if (data['is_mpin_skipped'] != null) {
prefs.setString('is_mpin_skipped', data['is_mpin_skipped']);
}
if (data['is_mpin_skipped'] != null &&
data['is_mpin_skipped'] == '0') {
context.go('/pinPage');
// Navigator.pushReplacementNamed(context, 'pinPage');
}
} else {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.clear();
}
} else {
ToastHelper.showErrorToast(context, 'Something went wrong');
throw Exception('Failed to verify pin number');
}
} catch (e) {
// ToastHelper.showErrorToast(context, 'Something went wrong');
print('Error: $e');
}
}
void toggleField() async {
// final SharedPreferences prefs = await SharedPreferences.getInstance();
if (isEmailFieldVisible) {
mobileController.text = '';
} else {
emailController.text = '';
}
setState(() {
isEmailFieldVisible = !isEmailFieldVisible;
});
}
Future<void> verifyMobileAndEmailNumber() async {
try {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});
String input = emailMobileController.text.trim();
bool isEmail = RegExp(r'^[^@]+@[^@]+\.[^@]+$').hasMatch(input);
bool isMobile = RegExp(r'^[0-9]{10}$').hasMatch(input);
if (isEmail) {
setState(() {
isEmailFieldVisible = true;
});
print("User entered Email: $input");
} else if (isMobile) {
isEmailFieldVisible = false;
print("User entered Mobile: $input");
}
// Determine the API and the payload based on the visible field
String apiEndpoint = isEmailFieldVisible
? Environment.apiUrlEnrollment + 'verifyEmployeeEmailId'
: Environment.apiUrlEnrollment + 'verifyEmployeeNumber';
Map<String, dynamic> payload = isEmailFieldVisible
? {'email': emailMobileController.text}
: {'mobile_number': emailMobileController.text};
// var enteredMobileNumber = mobileController.text;
final response = await http.post(
Uri.parse(apiEndpoint),
body: json.encode(payload),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
bool userVerification = data['data']['user_verification'];
String message = data['data']['message'];
if (userVerification) {
final SharedPreferences prefs =
await SharedPreferences.getInstance();
// var enteredMobileNumber = mobileController.text;
// prefs.setString('empMobileNo', enteredMobileNumber);
ToastHelper.showSuccessToast(
context, 'Verification code sent to ${emailMobileController.text}');
if (isEmailFieldVisible) {
print('isEmailFieldVisible $isEmailFieldVisible');
// prefs.setString('empEmail', emailController.text);
print('${emailMobileController.text}');
context.push(
'/mailVerify',
extra: {
'type': 'email',
'value': emailMobileController.text.trim(),
},
);
} else {
// _verifyPhoneNumber();
context.push(
'/mailVerify',
extra: {
'type': 'mobile',
'value': emailMobileController.text.trim(),
},
);
}
setState(() {
_isLoading = false;
});
// ToastHelper.showSuccessToast(context, message);
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, message);
print('Invalid mobile number');
}
} else if (response.statusCode == 429) {
setState(() {
_isLoading = false;
});
Map<String, dynamic> data = json.decode(response.body);
final message = data['message'];
ToastHelper.showErrorToast(context, message);
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
throw Exception('Failed to verify mobile number');
}
}
} catch (e) {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
print('Error: $e');
}
}
// Future<void> _verifyPhoneNumber() async {
// var enteredMobileNumber = mobileController.text;
// var countryCode = countryController.text;
// print('${countryCode + enteredMobileNumber}');
// await _auth.verifyPhoneNumber(
// phoneNumber: '${countryCode + enteredMobileNumber}',
// timeout: const Duration(seconds: 60),
// verificationCompleted: (PhoneAuthCredential credential) async {
// await _auth.signInWithCredential(credential);
// // ToastHelper.showSuccessToast(context, 'Verified Successfully!');
// // setState(() {
// // _isLoading = false;
// // });
// },
// verificationFailed: (FirebaseAuthException e) {
// print('Verification Failed: ${e.code} - ${e.message}');
// String errorMessage;
// if (e.code == 'invalid-app-credential') {
// errorMessage = 'Invalid Credential. Please try again.';
// } else if (e.code == 'invalid-phone-number') {
// errorMessage = 'The provided phone number is not valid.';
// } else if (e.code == 'too-many-requests') {
// errorMessage = 'Too many requests. Try again later.';
// } else {
// errorMessage = 'Verification Failed: ${e.message}';
// }
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(errorMessage),
// duration: Duration(seconds: 2),
// ),
// );
//
// ToastHelper.showSuccessToast(context, errorMessage);
// setState(() {
// _isLoading = false;
// });
// },
// codeSent: (String verificationId, int? resendToken) async {
// setState(() {
// _verificationId = verificationId;
// _resendToken = resendToken;
// });
//
// // When getting the verificationId
// SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('verificationId', _verificationId);
//
//
// ToastHelper.showSuccessToast(
// context, 'Verification code sent to ${enteredMobileNumber}');
//
// context.go(
// '/verify',
// extra: {
// 'verificationId': _verificationId,
// 'mobileNumber': enteredMobileNumber,
// 'resendToken': _resendToken,
// 'onResendCode': _resendCode,
// },
// );
//
// // Navigator.push(
// // context,
// // MaterialPageRoute(
// // builder: (context) => MyVerify(
// // verificationId: _verificationId,
// // mobileNumber: enteredMobileNumber,
// // resendToken: _resendToken,
// // onResendCode: _resendCode, // Pass the phone number
// // ),
// // ),
// // );
// setState(() {
// _isLoading = false;
// });
// },
// codeAutoRetrievalTimeout: (String verificationId) async{
// setState(() {
// _verificationId = verificationId;
// });
// final prefs = await SharedPreferences.getInstance();
// await prefs.setString('verificationId', verificationId);
// ToastHelper.showSuccessToast(context, 'Code auto-retrieval timed out.');
// setState(() {
// _isLoading = false;
// });
// },
// );
// }
//
// void _resendCode(String mobileNumber, int? resendToken) async {
// await _auth.verifyPhoneNumber(
// phoneNumber: '${countryController.text + mobileNumber}',
// timeout: const Duration(seconds: 60),
// forceResendingToken: resendToken,
// verificationCompleted: (PhoneAuthCredential credential) async {
// await _auth.signInWithCredential(credential);
// },
// verificationFailed: (FirebaseAuthException e) {
// if (e.code == 'invalid-phone-number') {
// print('The provided phone number is not valid.');
// }
// },
// codeSent: (String verificationId, int? resendToken) async{
// final prefs = await SharedPreferences.getInstance();
// await prefs.setString('verificationId', verificationId);
// setState(() {
// _verificationId = verificationId;
// _resendToken = resendToken;
// });
// ToastHelper.showSuccessToast(
// context, 'Verification code resent to ${mobileNumber}');
// context.push(
// '/verify',
// extra: {
// 'verificationId': _verificationId,
// 'mobileNumber': mobileNumber,
// 'resendToken': _resendToken,
// 'onResendCode': _resendCode,
// },
// );
//
// // Navigator.push(
// // context,
// // MaterialPageRoute(
// // builder: (context) => MyVerify(
// // verificationId: _verificationId,
// // mobileNumber: mobileNumber,
// // resendToken: _resendToken,
// // onResendCode: _resendCode,
// // ),
// // ),
// // );
// },
// codeAutoRetrievalTimeout: (String verificationId) async{
// final prefs = await SharedPreferences.getInstance();
// await prefs.setString('verificationId', verificationId);
// setState(() {
// _verificationId = verificationId;
// });
// },
// );
// }
//starts Login with UserName and Pasword
void loginWithUsernameAndPw() async {
try {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});
// print('EMAIL PARAMS : ${widget.email} - OTP : $otp');
final Map<String, dynamic> payload = {
'email_id': emailController.text,
'password': passwordController.text
};
final response = await http.post(
Uri.parse(Environment.apiUrlEnrollment + 'verifyPassword'),
body: json.encode(payload),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
print('response : ${response.statusCode}');
if (response.statusCode == 200) {
setState(() {
_isLoading = false;
});
Map<String, dynamic> data = json.decode(response.body);
print('data: $data');
/// Check API response status first
if (data['status'] == 'Invalid Password') {
final SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.clear();
ToastHelper.showErrorToast(
context, data['message'] ?? 'Invalid Password');
print('API error → ${data['message']}');
return; // stop execution
}
// --- Extract tokens safely ---
String? preToken;
if (data['data'] is String) {
preToken = data['data'];
}
String? postToken;
if (data['post_enrollment'] != null &&
data['post_enrollment']['data'] is String) {
postToken = data['post_enrollment']['data'];
}
// Save tokens
await TokenService.saveTokens(
preToken: preToken, postToken: postToken);
print('Tokens saved → preToken: $preToken, postToken: $postToken');
_preToken = preToken;
String status = data['status'];
// Directly access the post_enrollment data
Map<String, dynamic> post = data['post_enrollment'];
print('post: $post');
_postToken = postToken;
String postStatus = post['status'];
if (postStatus == 'success') {
setState(() {
_isLoading = false;
});
postSuccessData(post, data);
} else if (status == 'success') {
setState(() {
_isLoading = false;
});
enrollmentSuccessData(data);
} else {
setState(() {
_isLoading = false;
});
final SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.clear();
ToastHelper.showErrorToast(
context, 'Invalid Passsword. Please try again');
// Show a Snackbar if the OTP is invalid
print('Invalid Password. Please try again');
}
} else {
setState(() {
_isLoading = false;
});
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.clear();
ToastHelper.showWarningToast(context, 'Something went wrong');
throw Exception('Failed to verify OTP');
}
}
} catch (e) {
setState(() {
_isLoading = false;
});
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.clear();
print('Error: $e');
ToastHelper.showWarningToast(context, 'Something went wrong');
// Show a Snackbar if there's an error while verifying OTP
print('Failed to verify OTP. Please try again.');
}
}
void postSuccessData(post, data) async {
String status = data['status'];
String postStatus = post['status'];
if (postStatus == 'success') {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await SessionManager().initializeFromPostToken(post['data']);
session = await SessionManager();
print('Successfully Login');
}
if (status == 'success') {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await SessionManager().initializeFromPreToken(data['data']);
session = await SessionManager();
getClientLogoAndDetails();
}
if (_postToken != null && _postToken.isNotEmpty) {
ToastHelper.showSuccessToast(context, 'Successfully Logged In');
context.go('/home');
// Navigator.pushReplacementNamed(context, 'home');
} else {
context.go('/empDetails');
// Navigator.pushReplacementNamed(context, 'empDetails');
}
}
void enrollmentSuccessData(data) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await SessionManager().initializeFromPreToken(data['data']);
session = await SessionManager();
getClientLogoAndDetails();
print('Successfully Login');
print(isMobilePlatform());
if (_preToken != null && _preToken.isNotEmpty) {
ToastHelper.showSuccessToast(context, 'Successfully Logged In');
context.go('/home');
// Navigator.pushReplacementNamed(context, 'home');
} else {
context.go('/empDetails');
// Navigator.pushReplacementNamed(context, 'empDetails');
}
}
Future<void> getClientLogoAndDetails() async {
var url = Uri.parse(Environment.apiUrlEnrollment +
'getClientDetails?post_client_id=${session.client_id}&post_branch_id=${session.empClientBranchId}&pre_client_id=${session.enrollmentClient_id}&pre_branch_id=${session.enrollmentEmpClientBranchId}');
try {
var response = await http.get(
url,
headers: {
'Authorization':
'Bearer $_preToken', // Add token to the Authorization header
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
// print('response.statusCode == 200');
Map<String, dynamic> data = json.decode(response.body);
// print(data);
if (data.containsKey('data')) {
dynamic clientDetails = data['data'];
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString(
'clientLogo', clientDetails['client']['client_logo']);
await prefs.setString(
'clientName', clientDetails['client']['client_name']);
await prefs.setString(
'addon_subheading', clientDetails['client']['addon_subheading']);
setState(() {
// dynamic clientDetails = data['data'];
// print(clientDetails);
clientName = clientDetails['client']['client_name'];
print(clientName);
clientLogo = clientDetails['client']['client_logo'];
print(clientLogo);
});
} else {
// Handle other status messages if needed
// ToastHelper.showErrorToast(
// context, 'API request failed with status: ${data['status']}');
print('API request failed with status: ${data['status']}');
}
} else {
// Handle other status codes
// ToastHelper.showErrorToast(
// context, 'Request failed with status: ${response.statusCode}');
print('Request failed with status: ${response.statusCode}');
}
} catch (e) {
// Handle exceptions
print('Exception occurred: $e');
}
}
Future<void> forgotPassword() async {
setState(() {
clickedForgotPassword = true;
passwordController.text = '';
passwordController.clear();
});
}
Future<void> mailVerify() async {
try {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});
// Determine the API and the payload based on the visible field
String apiEndpoint =
Environment.apiUrlEnrollment + 'verifyEmployeeEmailId';
Map<String, dynamic> payload = {'email': emailController.text};
// var enteredMobileNumber = mobileController.text;
final response = await http.post(
Uri.parse(apiEndpoint),
body: json.encode(payload),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
bool userVerification = data['data']['user_verification'];
String message = data['data']['message'];
if (userVerification) {
final SharedPreferences prefs =
await SharedPreferences.getInstance();
// var enteredMobileNumber = mobileController.text;
// prefs.setString('empMobileNo', enteredMobileNumber);
ToastHelper.showSuccessToast(
context, 'OTP send to registered email');
setState(() {
otpFieldShow = true;
_isLoading = false;
});
// ToastHelper.showSuccessToast(context, message);
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, message);
print('Invalid mobile number');
}
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
throw Exception('Failed to verify mobile number');
}
}
} catch (e) {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
print('Error: $e');
}
}
Future<void> otpVerify() async {
try {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});
// Determine the API and the payload based on the visible field
String apiEndpoint = Environment.apiUrlEnrollment + 'verifyOtp';
Map<String, dynamic> payload = {
'email_id': emailController.text,
'otp': _otpController.text
};
// var enteredMobileNumber = mobileController.text;
final response = await http.post(
Uri.parse(apiEndpoint),
body: json.encode(payload),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
print(data);
String? verificationStatus = data['status'];
print(verificationStatus);
String? message = data['message'];
print(message);
if (verificationStatus == 'success') {
final SharedPreferences prefs =
await SharedPreferences.getInstance();
// var enteredMobileNumber = mobileController.text;
// prefs.setString('empMobileNo', enteredMobileNumber);
ToastHelper.showSuccessToast(context, message!);
setState(() {
otpValueStatus = false;
otpFieldShow = false;
clickedForgotPassword = false;
resetPasswordEnable = true;
_isLoading = false;
});
// ToastHelper.showSuccessToast(context, message);
} else {
setState(() {
otpValueStatus = true;
_isLoading = false;
});
ToastHelper.showErrorToast(context, message!);
print('Invalid mobile number');
}
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
throw Exception('Failed to verify mobile number');
}
}
} catch (e) {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
print('Error: $e');
}
}
Future<void> resetYourPassword() async {
final password = resetPasswordController.text.trim();
final confirmPassword = confirmPasswordController.text.trim();
try {
if (confirmPassword != password) {
ToastHelper.showErrorToast(context, 'Passwords do not match');
return;
}
setState(() {
_isLoading = true;
});
// Determine the API and the payload based on the visible field
String apiEndpoint = Environment.apiUrlEnrollment + 'savePassword';
Map<String, dynamic> payload = {
'email_id': emailController.text,
'password': password,
'confirm_password': confirmPassword
};
// var enteredMobileNumber = mobileController.text;
final response = await http.post(
Uri.parse(apiEndpoint),
body: json.encode(payload),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
bool userVerification = data['data']['user_verification'];
String message = data['data']['message'];
if (userVerification) {
ToastHelper.showSuccessToast(context, message!);
setState(() {
_isLoading = false;
resetPasswordEnable = false;
clickedForgotPassword = false;
otpFieldShow = false;
});
// ToastHelper.showSuccessToast(context, message);
} else {
setState(() {
resetPasswordEnable = true;
_isLoading = false;
});
ToastHelper.showErrorToast(context, message!);
print('Invalid mobile number');
}
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
throw Exception('Failed to verify mobile number');
}
} catch (e) {
setState(() {
_isLoading = false;
});
// ToastHelper.showErrorToast(context, 'Something went wrong');
print('Error: $e');
}
// 🔹 Password validation
// if (password.isEmpty) {
// ToastHelper.showErrorToast(context, 'Please enter your password');
// return;
// }
// if (password.length < 6) {
// ToastHelper.showErrorToast(context, 'Password must be at least 6 characters');
// return;
// }
// if (!RegExp(r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$').hasMatch(password)) {
// ToastHelper.showErrorToast(context, 'Include at least 1 uppercase letter and 1 number');
// return;
// }
//
// // 🔹 Confirm password validation
// if (confirmPassword.isEmpty) {
// ToastHelper.showErrorToast(context, 'Please confirm your password');
// return;
// }
}
Future<void> resendOTP() async {
try {
if (emailController.text.isNotEmpty) {
setState(() {
otpFieldShow = true;
_isLoading = true;
});
// Determine the API and the payload based on the visible field
String apiEndpoint =
Environment.apiUrlEnrollment + 'verifyEmployeeEmailId';
Map<String, dynamic> payload = {'email': emailController.text};
// var enteredMobileNumber = mobileController.text;
final response = await http.post(
Uri.parse(apiEndpoint),
body: json.encode(payload),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
},
);
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
bool userVerification = data['data']['user_verification'];
String message = data['data']['message'];
if (userVerification) {
final SharedPreferences prefs =
await SharedPreferences.getInstance();
// var enteredMobileNumber = mobileController.text;
// prefs.setString('empMobileNo', enteredMobileNumber);
ToastHelper.showSuccessToast(
context, 'OTP send to registered email');
setState(() {
otpFieldShow = true;
_isLoading = false;
});
// ToastHelper.showSuccessToast(context, message);
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, message);
print('Invalid mobile number');
}
} else {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
throw Exception('Failed to verify mobile number');
}
}
} catch (e) {
setState(() {
_isLoading = false;
});
ToastHelper.showErrorToast(context, 'Something went wrong');
print('Error: $e');
}
}
String getLoginDescription() {
if (switcherStatus == 1) {
return "Login with your email / mobile number and OTP to review and enroll for exciting health benefits for you and your family";
}
if (clickedForgotPassword) {
return "Enter your registered email to receive a OTP";
}
if (switcherStatus == 0 && resetPasswordEnable) {
return "Set your new password to continue accessing your Nhance account securely";
}
return "Login with your Username and Password to review and enroll for exciting health benefits for you and your family";
}
String getLoginHeading() {
if (switcherStatus == 1) {
return "Welcome to Nhance";
}
if (clickedForgotPassword) {
return "Forgot Password";
}
if (switcherStatus == 0 && resetPasswordEnable) {
return "Reset Password";
}
return "Welcome to Nhance";
}
//Ends Login with UserName and Password
@override
Widget build(BuildContext context) {
Size _size = MediaQuery.of(context).size;
EdgeInsets marginInsets = EdgeInsets.zero;
// const focusedBorderColor = Colors.white;
// const fillColor = Color.fromRGBO(243, 246, 249, 0);
// const borderColor = Color.fromRGBO(23, 171, 144, 0.4);
if (Responsive.isDesktop(context)) {
marginInsets = const EdgeInsets.only(
left: 0,
right: 0,
bottom: 0,
top: 0,
);
} else if (Responsive.isMobile(context)) {
marginInsets = const EdgeInsets.only(
left: 25, // Example value for mobile
right: 25, // Example value for mobile
bottom: 0, // Example value for mobile
top: 0, // Example value for mobile
);
} else if (Responsive.isTablet(context)) {
marginInsets = const EdgeInsets.only(
left: 25, //// Example value for mobile
right: 25, // Example value for mobile
bottom: 0, // Example value for mobile
top: 0, // Example value for mobile
);
}
return WillPopScope(
onWillPop: () async {
// Close the app on mobile back button press
exit(0); // This will exit the app
return false; // Return false to prevent any other actions
},
child: Scaffold(
body: SingleChildScrollView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
child: Container(
height: _size.height,
color: Colors.white,
child: Stack(
children: [
Visibility(
visible: _size.width <= 1100,
child: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
child: Container(
height: _size.height / 3,
width: double.infinity,
color: Color(0xFFFFFCE5),
child: Stack(
children: [
Column(
children: [
SizedBox(height: _size.height / 6.4),
Row(
mainAxisAlignment: MainAxisAlignment
.center, // Align to the center
children: [
Expanded(
flex: Responsive.isDesktop(context)
? 10
: 12,
child: Align(
alignment:
Responsive.isDesktop(context)
? Alignment.centerLeft
: Alignment.bottomCenter,
child: Image.asset(
'assets/nhance_app_logo.png',
width: 150,
height: 100,
)),
),
if (!Responsive.isMobile(context) &&
!Responsive.isTablet(context))
Expanded(
flex: 2,
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
// Add your navigation logic here
// For example, you can use Navigator.push to navigate to another page
Navigator.pushNamed(
context, 'hrLogin');
},
child: Row(
mainAxisAlignment: MainAxisAlignment
.end, // Align to the end (right)
children: [
Text(
'HR Login',
style: TextStyle(
color: Color(
0xFF000000), // Text color
// Add other text styles as needed
),
),
SizedBox(width: 5),
Icon(
Icons
.east, // Icon for customer login
color: Colors
.black, // Adjust color as needed
),
],
),
),
),
),
],
),
],
),
],
),
),
),
),
Container(
margin: marginInsets,
alignment: Alignment.bottomCenter,
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: [
Row(
children: [
Expanded(
flex: _size.width < 1100 ? 6 : 12,
child: Container(
margin: _size.width > 1100
? EdgeInsets.only(left: 20, right: 20)
: EdgeInsets.only(left: 0, right: 0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
if (!Responsive.isMobile(context) &&
!Responsive.isTablet(context))
Row(
children: [
Expanded(
flex: 12,
child: Align(
alignment: Alignment.center,
child: _size.width <= 1100
? Image.asset(
'assets/nhance_app_logo.png',
width: 150,
height: 150,
)
: _size.width > 1100
? Image.asset(
'assets/nhance_app_logo.png',
width: 150,
height: 150,
)
: Image.asset(
'assets/nhance_app_logo.png',
width: 150,
height: 150,
),
),
),
],
),
SizedBox(
height: Responsive.isDesktop(context)
? _size.height * 0.0
: 10,
),
SizedBox(height: 10),
if (Responsive.isDesktop(context))
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Container(
padding:
const EdgeInsets.all(3),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius:
BorderRadius.circular(50),
),
child: Row(
children: [
buildTab(
"Login with OTP", 0),
const SizedBox(width: 10),
buildTab(
"Login with Password",
1),
],
),
),
],
),
SizedBox(height: 10),
Container(
margin: Responsive.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
getLoginHeading(),
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
),
SizedBox(
height: 10,
),
Container(
margin: Responsive.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Expanded(
child: Text(
getLoginDescription(),
style: GoogleFonts.poppins(
fontSize: 12,
color: Color(0xFF000000)),
textAlign: TextAlign.center,
),
)
],
),
),
SizedBox(
height: 20,
),
if (switcherStatus == 1) ...[
Column(
children: [
Container(
height: 55,
margin: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 0),
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
child: TextFormField(
controller: emailMobileController,
keyboardType: TextInputType.text,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "Email / Mobile Number ",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return "Please enter email or mobile number";
}
String input = value.trim();
// ❌ Reject all spaces
if (input.contains(' ')) {
return "No spaces allowed";
}
final emailRegex = RegExp(r'^[^@]+@[^@]+\.[^@]+$');
final mobileRegex = RegExp(r'^[0-9]{10}$');
bool isEmailFormat = emailRegex.hasMatch(input);
bool isMobileFormat = mobileRegex.hasMatch(input);
// ---------------------------
// 🛑 MOBILE VALIDATION
// ---------------------------
if (RegExp(r'^[0-9]+$').hasMatch(input)) {
if (input.length != 10) {
return "Mobile number must be exactly 10 digits";
}
}
// ---------------------------
// 🛑 EMAIL VALIDATION
// ---------------------------
// Reject anything that has '@' but is NOT a valid email format
if (input.contains('@') && !isEmailFormat) {
return "Enter a valid email address";
}
// Reject email with extra digits at the end
if (input.contains('@') && RegExp(r'\d+$').hasMatch(input)) {
return "Email cannot contain extra numbers";
}
// Reject email+mobile combination
if (input.contains('@') && RegExp(r'\d{10}$').hasMatch(input)) {
return "Enter only email OR mobile number";
}
// ---------------------------
// 🛑 MIXED CONTENT (letters + digits but NOT email)
// ---------------------------
bool hasLetters = RegExp(r'[A-Za-z]').hasMatch(input);
bool hasDigits = RegExp(r'[0-9]').hasMatch(input);
if ((hasLetters && hasDigits) && !input.contains('@')) {
return "Enter only email OR 10-digit mobile number";
}
// ---------------------------
// 🟢 FINAL CHECK
// ---------------------------
if (!isEmailFormat && !isMobileFormat) {
return "Enter a valid email or 10-digit mobile number";
}
return null;
}
),
),
SizedBox(height: 15),
Container(
margin: Responsive.isDesktop(
context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: SizedBox(
width: double.infinity,
height: 45,
child: ElevatedButton(
style: ElevatedButton
.styleFrom(
backgroundColor:
Color(0xFF00989E),
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius
.circular(10),
),
),
onPressed: _isLoading
? null
: verifyMobileAndEmailNumber,
child: _isLoading
? CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<
Color>(
Color(0xFF00989E),
),
)
: Text( "Login with Email / Mobile OTP",
style: GoogleFonts
.poppins(
color: Color(
0xFFFFFFFF),
),
),
),
),
),
SizedBox(height: 15),
// MouseRegion(
// cursor:
// SystemMouseCursors.click,
// child: GestureDetector(
// onTap: toggleField,
// child: Text(
// isEmailFieldVisible
// ? "Login with Mobile No"
// : "Login with Email",
// style: TextStyle(
// color: Color(0xFF00989E),
// ),
// ),
// ),
// ),
],
),
] else if (switcherStatus == 0) ...[
if (!resetPasswordEnable)
Column(
children: [
if (!clickedForgotPassword) ...[
Container(
height: 55,
margin: Responsive
.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
),
child: TextFormField(
controller:
emailController,
keyboardType:
TextInputType
.emailAddress,
decoration:
InputDecoration(
border:
InputBorder.none,
hintText:
"Enter your email",
contentPadding:
EdgeInsets
.symmetric(
horizontal:
10),
),
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Please enter your email';
}
if (!RegExp(
r'^[^@]+@[^@]+\.[^@]+')
.hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
},
),
),
SizedBox(height: 10),
Container(
height: 55,
margin: Responsive
.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
),
child: TextFormField(
controller:
passwordController,
obscureText:
_obscurePassword,
textAlignVertical:
TextAlignVertical
.center, // ✅ THE FIX
decoration:
InputDecoration(
border:
InputBorder.none,
hintText:
"Enter your password",
contentPadding:
EdgeInsets
.symmetric(
horizontal: 10,
),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? Icons
.visibility_off
: Icons
.visibility,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscurePassword =
!_obscurePassword;
});
},
),
),
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Please enter your password';
}
// if (value.length < 6) {
// return 'Password must be at least 6 characters';
// }
// // Optional strong password rule
// if (!RegExp(
// r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$')
// .hasMatch(value)) {
// return 'Include at least 1 uppercase letter and 1 number';
// }
return null;
},
),
),
SizedBox(height: 15),
Container(
margin: Responsive
.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.end, // Align text to the right
children: [
InkWell(
onTap: () {
forgotPassword();
},
child: Text(
"Forgot Password?",
style: GoogleFonts
.poppins(
color: Colors
.blue),
),
),
],
),
),
SizedBox(height: 15),
Container(
margin: Responsive
.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: SizedBox(
width: double.infinity,
height: 40,
child: ElevatedButton(
style: ElevatedButton
.styleFrom(
backgroundColor:
Color(0xFF00989E),
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius
.circular(
10),
),
),
onPressed: _isLoading
? null
: loginWithUsernameAndPw,
child: _isLoading
? CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<
Color>(
Color(
0xFF00989E),
),
)
: Text(
"Login",
style:
GoogleFonts
.poppins(
color: Color(
0xFFFFFFFF),
),
),
),
),
),
],
if (clickedForgotPassword) ...[
Container(
height: 55,
margin: Responsive
.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
),
child: TextFormField(
controller:
emailController,
keyboardType:
TextInputType
.emailAddress,
decoration:
InputDecoration(
border:
InputBorder.none,
hintText:
"Enter your email",
contentPadding:
EdgeInsets
.symmetric(
horizontal:
10),
),
readOnly: otpFieldShow,
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Please enter your email';
}
if (!RegExp(
r'^[^@]+@[^@]+\.[^@]+')
.hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
},
),
),
if (otpFieldShow) ...[
SizedBox(height: 10),
AnimatedSwitcher(
duration: const Duration(
milliseconds: 500,
), // animation speed
switchInCurve:
Curves.easeInOutCirc,
switchOutCurve:
Curves.easeOutCirc,
child:
clickedForgotPassword
? Column(
key: const ValueKey(
'otp_block'),
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Container(
child: Center(
child:
Text(
'OTP',
style:
TextStyle(
fontSize: Responsive.isMobile(context)
? 14
: 18,
fontWeight:
FontWeight.w600,
color:
Colors.black,
),
),
),
),
const SizedBox(
height:
10),
Container(
alignment: Alignment.center,
margin: Responsive.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: Pinput(
length: 6,
// defaultPinTheme: defaultPinTheme,
// focusedPinTheme: focusedPinTheme,
// submittedPinTheme: submittedPinTheme,
inputFormatters: [
FilteringTextInputFormatter
.digitsOnly, // ✅ allows only 09
],
keyboardType: TextInputType.number,
showCursor: true,
controller: _otpController,
validator:
(value) {
if (value == null ||
value.isEmpty) {
return 'Please enter OTP';
}
if (value.length <
6) {
return 'OTP must be 6 digits';
}
// if (otpValueStatus) {
// // example
// return 'Invalid OTP';
// }
return null;
},
),
),
const SizedBox(
height:
10),
Container(
margin: Responsive.isDesktop(context)
? EdgeInsets.symmetric(
horizontal:
150)
: EdgeInsets.symmetric(
horizontal:
0),
alignment:
Alignment
.centerRight, // center the text
child:InkWell(
onTap: (){
setState(() {
otpFieldShow = false;
});
print('ABCDEF');
resendOTP();
},
mouseCursor: SystemMouseCursors.click,
child: Text(
'Didnt Receive Code?',
style: GoogleFonts.poppins(
color: Colors.blue,
fontSize: 14,
),
),
),
// RichText(
// textAlign:
// TextAlign.right,
// text:
// TextSpan(
// text:
// 'Didnt Receive Code? ', // normal text
// style:
// TextStyle(
// fontSize: Responsive.isMobile(context)
// ? 12
// : 14,
// fontWeight:
// FontWeight.normal,
// color:
// Colors.black,
// ),
// children: [
// TextSpan(
// text: 'Resend', // bold clickable part
// style: TextStyle(
// fontWeight: FontWeight.bold,
// color: Colors.white,
// decoration: TextDecoration.underline, // optional
// ),
// // recognizer: TapGestureRecognizer()
// // ..onTap = () {
// //
// // },
// ),
// ],
// ),
// ),
),
],
)
: const SizedBox
.shrink(), // Empty widget when false
),
],
SizedBox(height: 20),
Container(
margin: Responsive
.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: SizedBox(
width: double.infinity,
height: 40,
child: ElevatedButton(
style: ElevatedButton
.styleFrom(
backgroundColor:
Color(0xFF00989E),
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius
.circular(
10),
),
),
onPressed: _isLoading
? null
: () => {
otpFieldShow
? otpVerify()
: mailVerify()
},
child: _isLoading
? CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<
Color>(
Color(
0xFF00989E),
),
)
: Text(
otpFieldShow
? "Verify OTP "
: "Verify Mail",
style:
GoogleFonts
.poppins(
color: Color(
0xFFFFFFFF),
),
),
),
),
),
],
],
),
if (resetPasswordEnable) ...[
Column(
children: [
Container(
height: 55,
margin: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 0),
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
child: TextFormField(
controller: resetPasswordController,
obscureText: _resetObscurePassword,
onChanged: validatePassword,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "New Password",
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
suffixIcon: IconButton(
icon: Icon(
_resetObscurePassword ? Icons.visibility_off : Icons.visibility,
color: Colors.grey,
),
onPressed: () {
setState(() {
_resetObscurePassword = !_resetObscurePassword;
});
},
),
),
),
),
const SizedBox(height: 8),
// 🔹 VALIDATION LIST
Padding(
padding: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: _buildCheckItem(hasMinLength, "Minimum 8 characters")),
Expanded(child: _buildCheckItem(hasSpecialChar, "1 special character")),
],
),
Row(
children: [
Expanded(child: _buildCheckItem(hasUpperLower, "1 UPPER or lower case")),
Expanded(child: _buildCheckItem(hasNumber, "1 numerical")),
],
),
],
),
),
const SizedBox(height: 10),
Container(
height: 55,
margin: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 0),
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
child: TextFormField(
controller: confirmPasswordController,
obscureText: _obscureConfirmPassword,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Confirm Password",
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
suffixIcon: IconButton(
icon: Icon(
_obscureConfirmPassword
? Icons.visibility_off
: Icons.visibility,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscureConfirmPassword = !_obscureConfirmPassword;
});
},
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please confirm your password';
}
if (value != resetPasswordController.text) {
return 'Passwords do not match';
}
return null;
},
),
),
],
),
SizedBox(height: 15),
Container(
margin:
Responsive.isDesktop(context)
? EdgeInsets.symmetric(
horizontal: 150)
: EdgeInsets.symmetric(
horizontal: 0),
child: SizedBox(
width: double.infinity,
height: 40,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: isPasswordValid ? Color(0xFF00989E) : Colors.grey.shade400,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
onPressed: _isLoading || !isPasswordValid
? null
: () {
resetYourPassword();
},
child: _isLoading
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
)
: Text(
"Reset Password",
style: GoogleFonts.poppins(color: Colors.white),
),
),
),
),
]
],
SizedBox(
height: _size.width <= 1100 ? 0 : 0,
),
SizedBox(
height: Responsive.isDesktop(context)
? _size.height * 0.1
: _size.height * 0.2,
),
// SizedBox(
// height: _size.height * 0.1,
// ),
Container(
alignment: Alignment.bottomCenter,
padding:
EdgeInsets.symmetric(vertical: 8),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text:
'By continuing, you agree with our ',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 9,
),
children: <InlineSpan>[
WidgetSpan(
child: MouseRegion(
cursor: SystemMouseCursors
.click,
child: GestureDetector(
onTap: () {
context.go(
'/privacypolicy');
// Navigator.pushNamed(
// context,
// 'privacypolicy');
},
child: Text(
'privacy policy ',
style:
GoogleFonts.poppins(
color:
Color(0xFF00989E),
fontSize: 9,
decoration:
TextDecoration
.underline,
),
),
),
),
),
TextSpan(
text: 'and ',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 9,
),
),
WidgetSpan(
child: MouseRegion(
cursor: SystemMouseCursors
.click,
child: GestureDetector(
onTap: () {
context
.go('/termsofuse');
// Navigator.pushNamed(
// context,
// 'termsofuse');
},
child: Text(
'terms of use',
style:
GoogleFonts.poppins(
color:
Color(0xFF00989E),
fontSize: 9,
decoration:
TextDecoration
.underline,
),
),
),
),
),
],
),
),
),
],
),
),
),
if (_size.width > 1100)
Expanded(
flex: _size.width < 1100 ? 6 : 12,
child: LayoutBuilder(
builder: (BuildContext context,
BoxConstraints constraints) {
if (constraints.maxWidth > 600) {
return Image.asset(
'assets/login_web.jpg',
height: _size.height,
fit: BoxFit.cover,
);
} else {
return SizedBox();
}
},
),
),
],
),
],
),
),
),
),
],
)),
)));
}
Widget _buildCheckItem(bool status, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
Icon(
status ? Icons.check : Icons.close,
color: status ? Colors.green : Colors.red,
size: 18,
),
const SizedBox(width: 6),
Text(
text,
style: TextStyle(
color: status ? Colors.green : Colors.red,
fontSize: 14,
),
),
],
),
);
}
Widget buildTab(String title, int index) {
final isSelected = selectedIndex == index + 1;
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index + 1;
if (selectedIndex == 2) {
switcherStatus = 0;
clickedForgotPassword = false;
passwordController.text = '';
passwordController.clear();
resetPasswordController.text = '';
resetPasswordController.clear();
confirmPasswordController.text = '';
confirmPasswordController.clear();
_otpController.text = '';
_otpController.clear();
otpFieldShow = false;
otpValueStatus = false;
resetPasswordEnable = false;
emailController.text = '';
emailController.clear();
_formKey.currentState?.reset();
} else {
switcherStatus = 1;
emailMobileController.text = '';
emailMobileController.clear();
_formKey.currentState?.reset();
}
});
_formKey.currentState?.reset();
},
child: Container(
padding: EdgeInsets.only(
top: 6.5,
bottom: 6.0,
left: 40.0,
right: 40.0,
),
decoration: BoxDecoration(
color: isSelected ? const Color(0xFF00989E) : Colors.transparent,
boxShadow: isSelected
? [
BoxShadow(
color: isSelected
? const Color(0xFF00989E)
: Colors.transparent, // Grey shadow
spreadRadius: 0.2,
blurRadius: 1,
offset: const Offset(0, 1), // Horizontal, Vertical
),
]
: [],
borderRadius: BorderRadius.circular(16),
),
child: Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.w500,
),
),
),
);
}
}