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:http/http.dart' as http; import 'package:nhancepolicy/customAppBar/toastHelper.dart'; import 'package:nhancepolicy/hrVerify.dart'; import 'dart:convert'; import 'dart:io'; import 'package:nhancepolicy/responsive.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:flutter_animated_button/flutter_animated_button.dart'; import 'package:nhancepolicy/service/token_storage_service.dart'; import 'config/environment.dart'; import 'email_verify.dart'; class MyHrLogin extends StatefulWidget { const MyHrLogin({Key? key}); @override State createState() => _MyPhoneState(); } class _MyPhoneState extends State { final TextEditingController emailMobileController = TextEditingController(); // final TextEditingController emailController = TextEditingController(); // TextEditingController countryController = TextEditingController(); // TextEditingController mobileController = TextEditingController(); final _formKey = GlobalKey(); bool _isCheckingToken = false; dynamic empMobileNo; dynamic empEmailid; final FirebaseAuth _auth = FirebaseAuth.instance; late String _verificationId; int? _resendToken; bool _isLoading = false; bool isEmailFieldVisible = false; final tokenService = TokenStorageService(); @override void initState() { print('vndbbcbdskbvkjs1'); // countryController.text = "+91"; super.initState(); clearLocalStorageWhenStarts('initState'); } clearLocalStorageWhenStarts(fromData) async { print(fromData); print('Clearing secure storage on app start'); await tokenService.clearAll(); print('Secure Storage Cleared'); } void toggleField() { setState(() { isEmailFieldVisible = !isEmailFieldVisible; }); } Future verifyMobileAndEmailNumber() async { await tokenService.clearAll(); print('verifyMobileAndEmailNumber :- Local Storage Clear'); 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.apiUrl + 'verifyHrWithEmail' : Environment.apiUrl + 'verifyHrWithMobileNumber'; Map 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: { 'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y', HttpHeaders.contentTypeHeader: 'application/json', }, ); if (response.statusCode == 200) { Map data = json.decode(response.body); bool userVerification = data['data']['user_verification']; String message = data['data']['message']; if (userVerification) { if (isEmailFieldVisible) { print('isEmailFieldVisible $isEmailFieldVisible'); await tokenService.writeValue( 'empEmail', emailMobileController.text, ); // print('${emailMobileController.text}'); // final message = 'Verification code sent to ${emailMobileController.text}'; ToastHelper.showSuccessToast(context, 'Verification code sent to ${emailMobileController.text}'); Navigator.push( context, MaterialPageRoute( builder: (context) => MyEmailVerify( type: 'email', value: emailMobileController.text.trim(), // Pass the phone number ), ), ); } else { // final message = 'Verification code sent to ${emailMobileController.text}'; ToastHelper.showSuccessToast(context, 'Verification code sent to ${emailMobileController.text}'); Navigator.push( context, MaterialPageRoute( builder: (context) => MyEmailVerify( type: 'mobile', value: emailMobileController.text.trim(), // Pass the phone number ), ), ); } // 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 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 _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}'); // // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => MyHrVerify( // 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}'); // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => MyHrVerify( // 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; // }); // }, // ); // } @override Widget build(BuildContext context) { final Size _size = MediaQuery.of(context).size; return Scaffold( body: Container( width: double.infinity, height: _size.height, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ Color(0xFF00B6AC), Color(0xFF83E0DE), Color(0xFF01B4A8), ], ), ), child: Center( child: Container( width: double.infinity, // ✅ fixed web width height: _size.height, // ✅ fixed web height (IMPORTANT) margin: const EdgeInsets.all(60), clipBehavior: Clip.hardEdge, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40)), ), child: Row( children: [ // ================= LEFT IMAGE ================= Expanded( flex: 5, child: ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(40), bottomLeft: Radius.circular(40), ), child: Image.asset( 'assets/hrLogin.png', width: double.infinity, height: double.infinity, fit: BoxFit.cover, ), ), ), // ================= RIGHT FORM ================= Expanded( flex: 7, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/Nhance-Logo-Final 1.png', width: 300, height: 100, ), SizedBox(height: 25), Container( margin: EdgeInsets.symmetric( horizontal: 150), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Text( "Login with your ${isEmailFieldVisible ? 'email' : 'mobile number'} and OTP to review and enroll for exciting health benefits for you and your family", style: GoogleFonts.poppins( fontSize: 12, color: Color(0xFF000000)), textAlign: TextAlign.center, ), ) ], ), ), SizedBox(height: 20), Container( height: 55, margin: const EdgeInsets.symmetric(horizontal: 150) , 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: 20), Container( margin: EdgeInsets.symmetric( horizontal: 150), 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 ? const CircularProgressIndicator( valueColor: AlwaysStoppedAnimation< Color>( Color(0xFF00989E), ), ) : Text( "Login with Email / Mobile OTP", style: GoogleFonts .poppins( color: const Color( 0xFFFFFFFF), ), ), ), ), ), SizedBox(height: 20), Container( width: double .infinity, // Make the footer full width child: 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: [ TextSpan( text: 'privacy policy ', style: GoogleFonts.poppins( color: Color(0xFFE26828), fontSize: 9, ), ), TextSpan( text: 'and ', style: GoogleFonts.poppins( color: Colors.black, fontSize: 9, ), ), TextSpan( text: 'terms of use', style: GoogleFonts.poppins( color: Color(0xFFE26828), fontSize: 9, ), ), ], ), ), ), ), ], ), ), ), ), ], ), ), ) ) ); } }