import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:nhancepolicy/customAppBar/toastHelper.dart'; import 'package:nhancepolicy/models/environment.dart'; import 'package:nhancepolicy/service/api_service.dart'; import 'package:nhancepolicy/service/token_storage_service.dart'; import 'package:pinput/pinput.dart'; import 'dart:async'; import 'package:flutter/gestures.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'dart:io'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:nhancepolicy/responsive.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'branch/branch_selection_page.dart'; class MyHrVerify extends StatefulWidget { final String verificationId; final String mobileNumber; final int? resendToken; final Function(String, int?) onResendCode; const MyHrVerify({ Key? key, required this.verificationId, required this.mobileNumber, required this.resendToken, required this.onResendCode, }) : super(key: key); @override State createState() => _MyVerifyState(); } class _MyVerifyState extends State { TextEditingController countryController = TextEditingController(); late ApiService apiService; TextEditingController _otpController = TextEditingController(); final _formKey = GlobalKey(); late Timer _timer; int _secondsRemaining = 60; bool _isTimerRunning = false; dynamic enrollmentEmpClientBranchId; dynamic enrollmentEmpCodeString; dynamic enrollmentEmpPrimaryId; dynamic enrollmentGpaEmpName; dynamic enrollmentClient_id; dynamic enrollmentHrId; List enrollmentAllowed_modules = []; dynamic enrollmentEmp_status; dynamic empClientBranchId; dynamic empCodeString; dynamic empPrimaryId; dynamic gpaEmpName; dynamic client_id; dynamic empHrId; List empAllowed_modules = []; dynamic emp_status; dynamic _token; dynamic _postToken; dynamic clientName; dynamic clientLogo; dynamic fCMToken; late String verificationId; late String mobileNumber; final FirebaseAuth _auth = FirebaseAuth.instance; bool _isLoading = false; dynamic empMobileNo; dynamic empEmailid; late String _verificationId; @override void initState() { super.initState(); countryController.text = "+91"; apiService = ApiService(context); // checkTokenAvailability(); verificationId = widget.verificationId; mobileNumber = widget.mobileNumber; print('Received verificationId: $verificationId'); print('Received mobileNumber: $mobileNumber'); if (verificationId.isEmpty) { // Handle the case where verificationId is not provided Navigator.pop(context); } startTimer(); // Equivalent to componentDidMount _auth.authStateChanges().listen((User? user) { if (user != null) { // If user is already signed in, log them out logOutFirebase(); } }); } void logOutFirebase() async { await _auth.signOut(); print('User signed out'); } @override void dispose() { _timer.cancel(); super.dispose(); } void startTimer() { _isTimerRunning = true; _timer = Timer.periodic(Duration(seconds: 1), (Timer timer) { setState(() { if (_secondsRemaining > 0) { _secondsRemaining--; } else { _isTimerRunning = false; _timer.cancel(); } }); }); } void generateToken(bool otpVerifyStatus) async { try { final response = await http.post( Uri.parse(Environment.apiUrl + 'getVerifiedHrData'), body: json.encode( {'mobile_no': mobileNumber, 'otp_verification': otpVerifyStatus}), headers: { HttpHeaders.contentTypeHeader: 'application/json', }, ); if (response.statusCode == 200) { setState(() { _isLoading = false; }); Map data = json.decode(response.body); print('Response data: $data'); // Extract enrollment data List preEnrollmentData = data['data'] ?? []; Map postEnrollment = data['post_enrollment'] ?? {}; List postEnrollmentData = postEnrollment['data'] ?? []; // Save to global storage final tokenStorage = TokenStorageService(); await tokenStorage.saveEnrollmentData( preEnrollmentData, postEnrollmentData, ); // Navigate to branch selection Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => BranchSelectionPage(), ), ); // print('data: $data'); // _token = data['data']; // String status = data['status']; // // // Directly access the post_enrollment data // Map post = data['post_enrollment']; // print('post: $post'); // // _postToken = post['data']; // 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; // }); // ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again'); // // Show a Snackbar if the OTP is invalid // print('Invalid OTP. Please try again'); // } } else { setState(() { _isLoading = false; }); ToastHelper.showWarningToast(context, 'Something went wrong'); throw Exception('Failed to verify OTP'); } } catch (e) { setState(() { _isLoading = false; }); 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(); prefs.setString('_postToken', post['data']); // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(post['data']); print('postdecodedToken : $decodedToken'); empClientBranchId = decodedToken['ref_id']; prefs.setString('empClientBranchId', empClientBranchId); empCodeString = decodedToken['emp_code'].toString(); prefs.setString('empCode', empCodeString); empPrimaryId = decodedToken['id']; prefs.setString('empPrimaryId', empPrimaryId); gpaEmpName = decodedToken['name'].toString(); prefs.setString('gpaEmpName', gpaEmpName); client_id = decodedToken['client_id']; prefs.setString('client_id', client_id); empHrId = decodedToken['id']; prefs.setString('empHrId', empHrId); empAllowed_modules = decodedToken['allowed_modules']; prefs.setString('empAllowed_modules', jsonEncode(empAllowed_modules)); emp_status = decodedToken['emp_status']; prefs.setString('emp_status', emp_status); } if (status == 'success') { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('enrollToken', data['data']); // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(data['data']); print('decodedToken : $decodedToken'); enrollmentEmpClientBranchId = decodedToken['ref_id']; prefs.setString( 'enrollmentEmpClientBranchId', enrollmentEmpClientBranchId); enrollmentEmpCodeString = decodedToken['emp_code'].toString(); prefs.setString('enrollmentEmpCodeString', enrollmentEmpCodeString); enrollmentEmpPrimaryId = decodedToken['id']; prefs.setString('enrollmentEmpPrimaryId', enrollmentEmpPrimaryId); enrollmentGpaEmpName = decodedToken['name'].toString(); prefs.setString('enrollmentGpaEmpName', enrollmentGpaEmpName); enrollmentClient_id = decodedToken['client_id']; prefs.setString('enrollmentClient_id', enrollmentClient_id); enrollmentHrId = decodedToken['id']; prefs.setString('enrollmentHrId', enrollmentHrId); enrollmentAllowed_modules = decodedToken['allowed_modules']; prefs.setString( 'enrollmentAllowed_modules', jsonEncode(enrollmentAllowed_modules)); // enrollmentEmp_status = decodedToken['emp_status']; // prefs.setString('enrollmentEmp_status', enrollmentEmp_status); } final SharedPreferences prefs = await SharedPreferences.getInstance(); final _postToken = prefs.getString('_postToken'); if (_postToken != null && _postToken.isNotEmpty) { ToastHelper.showSuccessToast(context, 'Successfully Login'); // if (emp_status == 'enrolled' || emp_status == 'active') { Navigator.pushReplacementNamed(context, 'hrDashboard'); // } else { // Navigator.pushReplacementNamed(context, 'empDetails'); // } } } void enrollmentSuccessData(data) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('enrollToken', data['data']); // Decode the JWT token received from the API response Map? decodedToken = Jwt.parseJwt(data['data']); print('enrolldecodedToken : $decodedToken'); enrollmentEmpClientBranchId = decodedToken['ref_id']; prefs.setString('enrollmentEmpClientBranchId', enrollmentEmpClientBranchId); enrollmentEmpCodeString = decodedToken['emp_code'].toString(); prefs.setString('enrollmentEmpCodeString', enrollmentEmpCodeString); enrollmentEmpPrimaryId = decodedToken['id']; prefs.setString('enrollmentEmpPrimaryId', enrollmentEmpPrimaryId); enrollmentGpaEmpName = decodedToken['name'].toString(); prefs.setString('enrollmentGpaEmpName', enrollmentGpaEmpName); enrollmentClient_id = decodedToken['client_id']; prefs.setString('enrollmentClient_id', enrollmentClient_id); enrollmentHrId = decodedToken['id']; prefs.setString('enrollmentHrId', enrollmentHrId); enrollmentAllowed_modules = decodedToken['allowed_modules']; prefs.setString( 'enrollmentAllowed_modules', jsonEncode(enrollmentAllowed_modules)); // enrollmentEmp_status = decodedToken['emp_status']; // prefs.setString('enrollmentEmp_status', enrollmentEmp_status); print('Successfully Login'); // Redirect to another page final enrollToken = prefs.getString('enrollToken'); if (enrollToken != null && enrollToken.isNotEmpty) { ToastHelper.showSuccessToast(context, 'Successfully Login'); // if (emp_status == 'enrolled' || emp_status == 'active') { // Navigator.pushReplacementNamed(context, 'home'); // } else { Navigator.pushReplacementNamed(context, 'hrDashboard'); // } } } void verifyOTP(String otp) async { try { // setState(() { // _isLoading = true; // }); // Later, in verify screen: SharedPreferences prefs = await SharedPreferences.getInstance(); dynamic verificationId = prefs.getString('verificationId'); final credential = PhoneAuthProvider.credential( verificationId: verificationId, // Make sure this is up-to-date smsCode: otp, ); // final userCredential = await FirebaseAuth.instance.signInWithCredential(credential); // await FirebaseAuth.instance.signInWithCredential(credential); // if (userCredential.user != null) { bool otpVerifyStatus = true; generateToken(otpVerifyStatus); // } else { // ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again.'); // } // await FirebaseAuth.instance.signInWithCredential(credential).then((userCredential) async { // if (userCredential.user != null) { // bool otpVerifyStatus = true; // generateToken(otpVerifyStatus); // } else { // setState(() { // _isLoading = false; // }); // ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again'); // } // }); } on FirebaseAuthException catch (e) { if (e.code == 'code-expired') { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('OTP expired. Please request a new one.'), duration: Duration(seconds: 2), ), ); ToastHelper.showErrorToast( context, 'OTP expired. Please request a new one.'); } else if (e.code == 'invalid-verification-code') { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Invalid OTP entered. Please try again.'), duration: Duration(seconds: 2), ), ); ToastHelper.showErrorToast( context, 'Invalid OTP entered. Please try again.'); } else if (e.code == 'session-expired') { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Session expired. Try restarting the verification.'), duration: Duration(seconds: 2), ), ); ToastHelper.showErrorToast( context, 'Session expired. Try restarting the verification.'); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error: ${e.message}'), duration: Duration(seconds: 2), ), ); ToastHelper.showErrorToast(context, 'Error: ${e.message}'); } } catch (e) { // setState(() { // _isLoading = false; // }); print('Error: $e'); ToastHelper.showErrorToast( context, 'Failed to verify OTP. Please try again.'); } } void _resendOTP() { setState(() { _secondsRemaining = 60; _isTimerRunning = true; }); startTimer(); widget.onResendCode(widget.mobileNumber, widget.resendToken); } @override Widget build(BuildContext context) { // Retrieve the passed mobile number value // final String mobileNumber = // ModalRoute.of(context)!.settings.arguments as String; Size _size = MediaQuery.of(context).size; EdgeInsets marginInsets = EdgeInsets.zero; 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 ); } 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), ), ); final focusedPinTheme = defaultPinTheme.copyDecorationWith( border: Border.all(color: Color.fromRGBO(114, 178, 238, 1)), borderRadius: BorderRadius.circular(8), ); final submittedPinTheme = defaultPinTheme.copyWith( decoration: defaultPinTheme.decoration?.copyWith( color: Color.fromRGBO(234, 239, 243, 1), ), ); return 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(0xFF00989E), child: Stack( children: [ Column( children: [ SizedBox( height: _size.height / 6.4), // Adjust the spacing between the rows 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( _size.width <= 1100 ? 'assets/mobileViewLogo.png' : 'assets/Nhance-Logo-Final 1.png', width: 150, height: 150, ), ), ), 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: [ 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/hrLogin.jpg', height: _size.height, fit: BoxFit.cover, ); } else { return SizedBox(); } }, ), ), 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: 8, child: Align( alignment: Alignment.center, // Align to the start child: _size.width <= 1100 ? Image.asset( 'assets/Nhance-Logo-Final-mobile.png', width: 150, height: 70, ) : _size.width > 1100 ? Image.asset( 'assets/Nhance-Logo-Final 1.png', width: 150, height: 70, ) : Image.asset( 'assets/Nhance-Logo-Final 1.png', width: 150, height: 70, ), )), ], ), SizedBox(height: 80), Container( margin: Responsive.isDesktop(context) ? EdgeInsets.symmetric( horizontal: 150) : EdgeInsets.symmetric(horizontal: 0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Welcome to Nhance", 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: RichText( textAlign: TextAlign.center, text: TextSpan( text: "Please enter the one-time usage code sent to your mobile number $mobileNumber", style: GoogleFonts.poppins( fontSize: 12, height: 1.5, color: Color(0xFF000000)), children: [ TextSpan( text: " (Change Number)", style: GoogleFonts.poppins( fontSize: 12, color: Color( 0xFFE26728)), // Change color as desired recognizer: TapGestureRecognizer() ..onTap = () { // Navigate to the page where the user can change the phone number Navigator.pushNamed( context, 'hrLogin'); }, ), ], ), ), ), SizedBox(height: 15), Container( margin: Responsive.isDesktop(context) ? EdgeInsets.symmetric( horizontal: 150) : EdgeInsets.symmetric(horizontal: 0), child: Pinput( length: 6, // defaultPinTheme: defaultPinTheme, // focusedPinTheme: focusedPinTheme, // submittedPinTheme: submittedPinTheme, showCursor: true, controller: _otpController, ), ), SizedBox(height: 10), Container( margin: Responsive.isDesktop(context) ? EdgeInsets.symmetric( horizontal: 150) : EdgeInsets.symmetric(horizontal: 0), child: Row( mainAxisAlignment: MainAxisAlignment .end, // Align text to the right children: [ _isTimerRunning ? Text( "Resend OTP in $_secondsRemaining seconds", style: GoogleFonts.poppins( color: Colors.black), ) : InkWell( onTap: () { _resendOTP(); }, child: Text( "Resend OTP", style: GoogleFonts.poppins( color: Colors.blue), ), ), ], ), ), SizedBox(height: 10), 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: () { if (_formKey.currentState! .validate()) { _formKey.currentState! .save(); // Save form fields before calling verifyOTP verifyOTP(_otpController.text); } }, child: Text( "Submit", style: GoogleFonts.poppins( color: Color(0xFFFFFFFF)), ), ), ), ), SizedBox( height: _size.width <= 1100 ? 0 : 0, ), // _size.width > 1100 // ? Container( // margin: EdgeInsets.symmetric( // horizontal: 150), // child: Column( // children: [ // SizedBox(height: 30), // Text( // "Benefits of Login", // style: GoogleFonts.poppins( // fontSize: 20, // fontWeight: FontWeight.bold, // ), // ), // SizedBox(height: 15), // ], // )) // : SizedBox(), // _size.width > 1100 // ? Container( // margin: EdgeInsets.symmetric( // horizontal: 150), // child: Row( // mainAxisAlignment: // MainAxisAlignment.center, // children: [ // Expanded( // flex: 6, // child: Container( // padding: // EdgeInsets.symmetric( // vertical: 8), // child: Row( // mainAxisAlignment: // MainAxisAlignment // .center, // children: [ // Expanded( // child: Container( // padding: EdgeInsets // .symmetric( // vertical: // 12), // decoration: // BoxDecoration( // border: Border( // right: // BorderSide( // width: 1, // color: Colors // .black, // ), // ), // ), // child: Column( // children: [ // Icon( // Icons // .policy, // color: Color( // 0xFFE26728)), // SizedBox( // height: 10), // Text( // "View Policy"), // ], // ), // ), // ), // Expanded( // child: Container( // padding: EdgeInsets // .symmetric( // vertical: // 12), // child: Column( // children: [ // Icon(Icons.edit, // color: Color( // 0xFFE26728)), // SizedBox( // height: 10), // Text( // "Manage Claims"), // ], // ), // ), // ), // ], // ), // ), // ), // ], // ), // ) // : SizedBox( // height: // Responsive.isDesktop(context) // ? _size.height * 0.1 // : _size.height * 0.2, // ), SizedBox( height: Responsive.isDesktop(context) ? _size.height * 0.3 : _size.height * 0.2, ), // SizedBox( // height: _size.height * 0.1, // ), Align( alignment: Alignment.bottomCenter, child: 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(0xFF00989E), fontSize: 9, ), ), TextSpan( text: 'and ', style: GoogleFonts.poppins( color: Colors.black, fontSize: 9, ), ), TextSpan( text: 'terms of use', style: GoogleFonts.poppins( color: Color(0xFF00989E), fontSize: 9, ), ), ], ), ), ), ), ), ], ), ), ), ], ), ], ), ), ), ), ], )), )); } }