import 'dart:convert'; import 'dart:io'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:jwt_decode/jwt_decode.dart'; import 'package:nhance_partner/core/config/env.dart'; import 'package:nhance_partner/core/services/platform_helper.dart'; import 'package:nhance_partner/data/utils/validators.dart'; import 'package:pinput/pinput.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../core/routing/routes.dart'; import '../../../data/services/auth_service.dart'; import '../../../data/utils/commonLoaderButton.dart'; import '../../../data/utils/toastNotification.dart'; import '../../layouts/responsive_layout.dart'; import '../../providers/manager_provider.dart'; import '../../providers/userRoleProvider.dart'; import '../../themes/indicators/text_field_theme.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class LoginScreen extends ConsumerStatefulWidget { const LoginScreen({super.key}); @override ConsumerState createState() => _LoginScreenState(); } class _LoginScreenState extends ConsumerState { final _formKey = GlobalKey(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _PhoneNumberController = TextEditingController(); final TextEditingController _otpController = TextEditingController(); final TextEditingController _countryController = TextEditingController(); final FirebaseAuth _auth = FirebaseAuth.instance; late String _verificationId; int? _resendToken; bool _isLoading = false; bool _obscurePassword = true; int switcherStatus = 1; int selectedIndex = 1; bool enteredEmailOrMobile = false; dynamic clickedButtonName; dynamic token; dynamic fCMToken; // Future _handleLogin() async { // if (!_formKey.currentState!.validate()) return; // // setState(() => _isLoading = true); // // // Simulate API call // await Future.delayed(const Duration(seconds: 2)); // // // TODO: Replace with your AuthService // final success = // _emailController.text == "test@example.com" && // // _passwordController.text == "password"; // // // setState(() => _isLoading = false); // // print("Succes - $success"); // if (success) { // print("Ckeck 1"); // if (mounted) { // print("Ckeck 2"); // await AuthService.saveToken('1234'); // final dynamic token = AuthService.saveToken('1234'); // print('token - $token'); // // print('AppRoutes.home'); // context.go(AppRoutes.home); // print("Ckeck 3"); // } // } else { // if (mounted) { // ScaffoldMessenger.of( // context, // ).showSnackBar(const SnackBar(content: Text("Invalid credentials"))); // } // } // } 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), ), ); @override void initState() { super.initState(); _countryController.text = "+91"; } Future initNotification() async { try { // await _firebaseMessaging.requestPermission(); fCMToken = await FirebaseMessaging.instance.getToken(); print('Token : $fCMToken'); if (fCMToken != null) { // await sendDeviceToken(fCMToken); } } catch (e) { print("Error getting FCM Token: $e"); } } Future _saveUserRole(String token) async { final prefs = await SharedPreferences.getInstance(); final decodedToken = Jwt.parseJwt(token); final Map? data = decodedToken['data']; String role; if (data == null || !data.containsKey('role_id')) { role = "agent"; } else { final dynamic roleId = data['role_id']; if (roleId.toString() == "1") { role = "manager"; } else if (roleId.toString() == "2") { role = "staff"; } else { role = "agent"; // fallback if unexpected value } } // Save globally ref.read(userRoleProvider.notifier).state = role; print("✅ User role set globally: $role"); await prefs.setString('userRole', role); // final userRole = ref.watch(userRoleProvider); } Future _saveIdsFromToken(String token) async { final prefs = await SharedPreferences.getInstance(); final Map decodedToken = Jwt.parseJwt(token); print('decodedToken : $decodedToken'); final dynamic data = decodedToken['data']; if (data != null) { // Manager ID final dynamic managerIdRaw = data['manager_id']; final int? managerId = managerIdRaw is int ? managerIdRaw : int.tryParse(managerIdRaw.toString()); if (managerId != null) { ref.read(managerIdProvider.notifier).state = managerId; print("✅ Manager ID saved globally: $managerId"); await prefs.setInt('managerId', managerId); } else { print("⚠️ Manager ID is null or invalid"); } // User ID final dynamic userIdRaw = data['id']; final int? userId = userIdRaw is int ? userIdRaw : int.tryParse(userIdRaw.toString()); if (userId != null) { ref.read(userIdProvider.notifier).state = userId; print("✅ User ID saved globally: $userId"); await prefs.setInt('userId', userId); } else { print("⚠️ User ID is null or invalid"); } } else { print("⚠️ No data found in decodedToken"); } // final managerId = ref.watch(managerIdProvider); // final userId = ref.watch(userIdProvider); } // Future _saveManagerId(String token) async { // Map? decodedToken = await Jwt.parseJwt(token); // print('decodedToken : $decodedToken'); // final dynamic managerIdRaw = decodedToken['data']?['manager_id']; // final int? managerId = managerIdRaw is int // ? managerIdRaw // : int.tryParse(managerIdRaw.toString()); // // if (managerId != null) { // ref.read(managerIdProvider.notifier).state = managerId; // print("Manager ID saved globally: $managerId"); // } else { // print("Manager ID is null or invalid"); // } // print(managerId); // // final managerId = ref.watch(managerIdProvider); // } Future sendMobileOrEmailVerify(String loginUser) async { // await Future.delayed(const Duration(seconds: 5)); try { if (_formKey.currentState!.validate()) { String apiEndpoint; if (loginUser == 'agent') { apiEndpoint = switcherStatus == 1 ? Env.apiUrl + 'auth/verifyAgentWithMobileNumber' : Env.apiUrl + 'auth/verifyAgentWithEmailId'; } else { apiEndpoint = switcherStatus == 1 ? Env.apiUrl + 'auth/verifyStaffWithMobileNumber' : Env.apiUrl + 'auth/verifyStaffWithEmailId'; } Map payload = switcherStatus == 1 ? {'mobile': _PhoneNumberController.text} : {'email': _emailController.text}; final response = await http.post( Uri.parse(apiEndpoint), body: json.encode(payload), headers: { HttpHeaders.contentTypeHeader: 'application/json', 'App-Signature': Env.App_Signature, }, ); if (response.statusCode == 200) { final data = json.decode(response.body); final verification = loginUser == 'agent' ? data['data']['agent_verification'] : data['data']['Staff_verification']; final message = data['data']['message']; if (verification == true) { if (switcherStatus == 1) { _verifyPhoneNumber(); } else { setState(() { enteredEmailOrMobile = true; }); ToastHelper.showSuccessToast(context, 'OTP sent successfully'); } return true; // ✅ success } else { ToastHelper.showErrorToast(context, message); return false; // ❌ fail } } else { ToastHelper.showErrorToast(context, 'Something went wrong'); return false; // ❌ fail } } return false; } catch (e) { ToastHelper.showErrorToast(context, 'Something went wrong'); print('Error: $e'); return false; } } Future verifyMobileOrMailOTP(otpVerifyStatus) async { try { // Select API endpoint final String apiEndpoint = (clickedButtonName == 'agent') ? '${Env.apiUrl}auth/getVerifiedAgentData' : '${Env.apiUrl}auth/getVerifiedStaffData'; // Build payload depending on switcher status final Map payload = (switcherStatus == 1) ? { 'otp_verification': otpVerifyStatus, 'mobile': _PhoneNumberController.text.trim(), } : {'otp': otpVerifyStatus, 'email': _emailController.text.trim()}; // Send request final response = await http.post( Uri.parse(apiEndpoint), body: json.encode(payload), headers: { HttpHeaders.contentTypeHeader: 'application/json', 'App-Signature': Env.App_Signature, }, ); // Check response if (response.statusCode == 200) { final Map data = json.decode(response.body); final String status = data['status']?.toString() ?? 'error'; token = data['data']; // can be string or object print('Response status: ${response.statusCode}'); print('Response body: $data'); if (status == 'success') { ToastHelper.showSuccessToast(context, 'OTP verified successfully'); await AuthService.saveToken(token); await _saveUserRole(token); await _saveIdsFromToken(token); final managerId = ref.watch(managerIdProvider); print('managerId -- $managerId'); final userRole = ref.watch(userRoleProvider); print('userRole -- $userRole'); context.go(AppRoutes.dashboard); } else { ToastHelper.showErrorToast(context, data['message'] ?? 'Invalid OTP'); } } else { ToastHelper.showErrorToast( context, 'Server error: ${response.statusCode}', ); } } catch (e, stacktrace) { print('Error verifying OTP: $e'); print(stacktrace); ToastHelper.showErrorToast( context, 'Something went wrong. Please try again.', ); } } Future verifyFirebaseMobileOTP() 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: _otpController.text, ); print('credential $credential'); final userCredential = await FirebaseAuth.instance.signInWithCredential( credential, ); // await FirebaseAuth.instance.signInWithCredential(credential); print('otp firebase check'); if (userCredential.user != null) { print('otp firebase check done'); bool otpVerifyStatus = true; await verifyMobileOrMailOTP(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.', ); } } Future _verifyPhoneNumber() async { var enteredMobileNumber = _PhoneNumberController.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); setState(() { enteredEmailOrMobile = true; }); ToastHelper.showSuccessToast( context, 'Verification code sent to ${enteredMobileNumber}', ); // 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}', ); }, codeAutoRetrievalTimeout: (String verificationId) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('verificationId', verificationId); setState(() { _verificationId = verificationId; }); }, ); } // 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) => 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}'); // 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; // }); // }, // ); // } // Future sendMobileOrEmailVerify() async { // if (!_formKey.currentState!.validate()) return; // setState(() { // enteredEmailOrMobile = true; // }); // } Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: LayoutBuilder( builder: (context, constraints) { if (!ResponsiveLayout.isMobile(context)) { // Web layout return Row( children: [ Expanded( child: Container( color: Colors.white, padding: const EdgeInsets.all(40), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.asset( "assets/login/nhance-partner-logo.png", height: 45, ), const SizedBox(height: 40), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Welcome Back", style: TextStyle( fontSize: 50, fontWeight: FontWeight.w600, color: Color(0xFF425C5C), ), ), const SizedBox(height: 20), Image.asset( "assets/login/login-content.png", height: MediaQuery.of(context).size.height * 0.5, // 40% of screen height fit: BoxFit.contain, ), const SizedBox(height: 10), const Text( '${'"'}Manage your policies, track quotations, and grow your business all in one place.${'"'}', textAlign: TextAlign.center, style: TextStyle( fontSize: 18, color: Color(0xFF000000), fontWeight: FontWeight.w500, ), ), ], ), ), ], ), ), ), // Right: Login form Expanded( child: Container( // padding: const EdgeInsets.all(40), decoration: const BoxDecoration( color: Colors.white, image: DecorationImage( image: AssetImage( "assets/login/login-bg.png", ), // <-- your image path fit: BoxFit.cover, // cover entire container ), borderRadius: BorderRadius.only( topLeft: Radius.circular(40), bottomLeft: Radius.circular(40), ), ), child: Center( // <-- center vertically + horizontally child: SizedBox( width: 600, // keep fixed width like first design child: _LoginForm(context), ), ), ), ), ], ); } else { // Mobile layout return SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 15), Image.asset( "assets/login/nhance-partner-logo.png", height: 35, ), const SizedBox(height: 10), Text( "Welcome Back", style: GoogleFonts.inter( fontSize: 24, fontWeight: FontWeight.w600, color: Color(0xFF425C5C), ), ), const SizedBox(height: 10), Image.asset("assets/login/login-content.png", height: 120), // const SizedBox(height: 10), Container( padding: EdgeInsets.symmetric(vertical: 10, horizontal: 50), child: Text( '${'"'}Manage your policies, track quotations, and grow your business all in one place.${'"'}', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, color: Color(0xFF000000), fontWeight: FontWeight.w500, ), ), ), const SizedBox(height: 10), Container( width: double.infinity, height: MediaQuery.of(context).size.height * 0.8, // full screen height padding: const EdgeInsets.all(20), decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF466F6C), Color(0xFF86D5CF)], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), borderRadius: BorderRadius.only( topLeft: Radius.circular(40), topRight: Radius.circular(40), ), ), child: _LoginForm(context), ), ], ), ); } }, ), ); } Widget _LoginForm(BuildContext context) { const focusedBorderColor = Colors.white; const fillColor = Color.fromRGBO(243, 246, 249, 0); const borderColor = Color.fromRGBO(23, 171, 144, 0.4); return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "Login to your account", style: TextStyle( fontSize: ResponsiveLayout.isMobile(context) ? 20 : 35, fontWeight: FontWeight.w600, color: Colors.white, ), ), const SizedBox(height: 10), Text( "Enter your email or mobile number to receive a one time password.", textAlign: TextAlign.center, style: TextStyle( fontSize: ResponsiveLayout.isMobile(context) ? 12 : 18, color: Colors.white, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(3), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(50), ), child: Row( children: [ buildTab("Mobile", 0), const SizedBox(width: 10), buildTab("Email", 1), ], ), ), ], ), const SizedBox(height: 30), Container( child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.max, children: [ SizedBox( width: 400, height: 70, child: Column( children: [ if (switcherStatus == 0) ThemedFormField( hintText: 'Email', backgroundColor: Colors.white, validator: (value) => Validators.email(value, "Email"), // imgPath: "MiscIconAssetPath.person", controller: _emailController, ), if (switcherStatus == 1) ThemedFormField( hintText: 'Mobile Number', backgroundColor: Colors.white, validator: (value) => Validators.phone(value, "Phone"), // imgPath: "MiscIconAssetPath.person", controller: _PhoneNumberController, // txtwidth: MediaQuery.of(context).size.width * 0.5, keyboardType: TextInputType.number, maxLength: 10, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, ], // readOnly: true, ), // const SizedBox(height: 16), // ThemedFormField( // hintText: 'Password', // backgroundColor: Colors.white, // validator: (value) => // Validators.passwordlogIn(value, "Password"), // // imgPath: "MiscIconAssetPath.person", // controller: _passwordController, // isObscurable: true, // // txtwidth: MediaQuery.of(context).size.width * 0.5, // // keyboardType: TextInputType.number, // // maxLength: 10, // // inputFormatters: [FilteringTextInputFormatter.digitsOnly], // // readOnly: true, // ), ], ), ), const SizedBox(height: 20), if (!enteredEmailOrMobile) SizedBox( width: 400, child: SizedBox( width: double.infinity, height: 50, child: CommonButton( text: "Login as Agent", backgroundColor: Color(0xFF436462), onPressed: () async { setState(() { clickedButtonName = 'agent'; }); // ⏳ Wait for API to finish final success = await sendMobileOrEmailVerify( 'agent', ); if (success) { // API success → loader stops immediately print("✅ API success"); } else { // API failed → loader also stops immediately print("❌ API failed"); } }, ), // ElevatedButton( // style: ElevatedButton.styleFrom( // backgroundColor: Color(0xFF436462), // padding: const EdgeInsets.symmetric(vertical: 16), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // ), // ), // onPressed: () { // sendMobileOrEmailVerify('agent'); // setState(() { // clickedButtonName = 'agent'; // }); // }, // child: Text( // 'Login as Agent', // style: TextStyle( // fontSize: ResponsiveLayout.isMobile(context) // ? 18 // : 20, // fontWeight: FontWeight.w600, // color: Colors.white, // ), // ), // ), ), ), if (!ResponsiveLayout.isMobile(context) && !enteredEmailOrMobile) ...[ SizedBox(height: 10), Container( child: Text( 'OR', style: TextStyle( fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), SizedBox(height: 10), SizedBox( width: 400, child: SizedBox( width: double.infinity, height: 50, child: CommonButton( text: "Login as Staff", backgroundColor: Color(0xFF436462), onPressed: () async { setState(() { clickedButtonName = 'staff'; }); // ⏳ Wait for API to finish final success = await sendMobileOrEmailVerify( 'staff', ); if (success) { // API success → loader stops immediately print("✅ API success"); } else { // API failed → loader also stops immediately print("❌ API failed"); } }, ), // ElevatedButton( // style: ElevatedButton.styleFrom( // backgroundColor: Color(0xFF436462), // padding: const EdgeInsets.symmetric(vertical: 16), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // ), // ), // onPressed: () { // sendMobileOrEmailVerify('staff'); // setState(() { // clickedButtonName = 'staff'; // }); // }, // child: Text( // 'Login as Staff', // style: TextStyle( // fontSize: ResponsiveLayout.isMobile(context) // ? 18 // : 20, // fontWeight: FontWeight.w600, // color: Colors.white, // ), // ), // ), ), ), ], // if (enteredEmailOrMobile) ...[ // Container( // child: Text( // 'OTP', // style: TextStyle( // fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, // fontWeight: FontWeight.w600, // color: Colors.white, // ), // ), // ), // Container( // child: Pinput( // length: 6, // defaultPinTheme: defaultPinTheme, // separatorBuilder: (index) => const SizedBox(width: 8), // showCursor: true, // controller: _otpController, // // validator: _validatePin, // errorPinTheme: defaultPinTheme.copyBorderWith( // border: Border.all(color: Colors.redAccent), // ), // hapticFeedbackType: HapticFeedbackType.lightImpact, // onCompleted: (pin) { // debugPrint('onCompleted: $pin'); // }, // onChanged: (value) { // debugPrint('onChanged: $value'); // }, // cursor: Column( // mainAxisAlignment: MainAxisAlignment.end, // children: [ // Container( // margin: const EdgeInsets.only(bottom: 9), // width: 22, // height: 1, // color: focusedBorderColor, // ), // ], // ), // focusedPinTheme: defaultPinTheme.copyWith( // decoration: defaultPinTheme.decoration!.copyWith( // borderRadius: BorderRadius.circular(8), // border: Border.all(color: focusedBorderColor), // ), // ), // submittedPinTheme: defaultPinTheme.copyWith( // decoration: defaultPinTheme.decoration!.copyWith( // color: fillColor, // borderRadius: BorderRadius.circular(19), // border: Border.all(color: focusedBorderColor), // ), // ), // ), // ), // const SizedBox(height: 20), // SizedBox( // width: 400, // child: SizedBox( // width: double.infinity, // height: 50, // child: ElevatedButton( // style: ElevatedButton.styleFrom( // backgroundColor: Color(0xFF436462), // padding: const EdgeInsets.symmetric(vertical: 16), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // ), // ), // onPressed: () { // // sendMobileOrEmailVerify('staff'); // }, // child: Text( // 'Continue', // style: TextStyle( // fontSize: ResponsiveLayout.isMobile(context) // ? 18 // : 20, // fontWeight: FontWeight.w600, // color: Colors.white, // ), // ), // ), // ), // ), // ], AnimatedSwitcher( duration: const Duration( milliseconds: 500, ), // animation speed switchInCurve: Curves.easeInOutCirc, switchOutCurve: Curves.easeOutCirc, child: enteredEmailOrMobile ? Column( key: const ValueKey('otp_block'), crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( child: Center( child: Text( 'OTP', style: TextStyle( fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), ), const SizedBox(height: 10), Container( alignment: Alignment.center, child: Pinput( length: 6, defaultPinTheme: defaultPinTheme, separatorBuilder: (index) => const SizedBox(width: 8), showCursor: true, controller: _otpController, errorPinTheme: defaultPinTheme.copyBorderWith( border: Border.all(color: Colors.redAccent), ), hapticFeedbackType: HapticFeedbackType.lightImpact, onCompleted: (pin) => debugPrint('onCompleted: $pin'), onChanged: (value) => debugPrint('onChanged: $value'), cursor: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Container( margin: const EdgeInsets.only(bottom: 9), width: 22, height: 1, color: focusedBorderColor, ), ], ), focusedPinTheme: defaultPinTheme.copyWith( decoration: defaultPinTheme.decoration! .copyWith( borderRadius: BorderRadius.circular(8), border: Border.all( color: focusedBorderColor, ), ), ), submittedPinTheme: defaultPinTheme.copyWith( decoration: defaultPinTheme.decoration! .copyWith( color: fillColor, borderRadius: BorderRadius.circular(19), border: Border.all( color: focusedBorderColor, ), ), ), ), ), const SizedBox(height: 20), Container( alignment: Alignment.center, // center the text child: RichText( textAlign: TextAlign.center, text: TextSpan( text: 'Didn’t Receive Code? ', // normal text style: TextStyle( fontSize: ResponsiveLayout.isMobile(context) ? 12 : 14, fontWeight: FontWeight.normal, color: Colors.white, ), children: [ TextSpan( text: 'Resend', // bold clickable part style: TextStyle( fontWeight: FontWeight.bold, color: Colors.white, decoration: TextDecoration .underline, // optional ), recognizer: TapGestureRecognizer() ..onTap = () { print('Resend clicked'); print(enteredEmailOrMobile); print(clickedButtonName); if (_PhoneNumberController .text .isNotEmpty) { print('1224'); _resendCode( _PhoneNumberController.text, _resendToken, ); } else if (_PhoneNumberController .text .isEmpty) { print('1227'); sendMobileOrEmailVerify( clickedButtonName, ); } else { print('data not found'); } }, ), ], ), ), ), const SizedBox(height: 20), Center( child: SizedBox( width: 400, child: CommonButton( text: "Continue", backgroundColor: Color(0xFF436462), onPressed: () async { if (switcherStatus == 1) { await verifyFirebaseMobileOTP(); } else { await verifyMobileOrMailOTP( _otpController.text, ); } }, ), // ElevatedButton( // style: ElevatedButton.styleFrom( // backgroundColor: const Color(0xFF436462), // padding: const EdgeInsets.symmetric( // vertical: 16, // ), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // ), // ), // onPressed: () { // if (switcherStatus == 1) { // verifyFirebaseMobileOTP(); // } else { // verifyMobileOrMailOTP(_otpController.text); // } // }, // child: Text( // 'Continue', // style: TextStyle( // fontSize: ResponsiveLayout.isMobile(context) // ? 18 // : 20, // fontWeight: FontWeight.w600, // color: Colors.white, // ), // ), // ), ), ), ], ) : const SizedBox.shrink(), // Empty widget when false ), SizedBox(height: 20), ], ), ), ), ], ); } Widget buildTab(String title, int index) { final isSelected = selectedIndex == index + 1; return GestureDetector( onTap: () { setState(() { selectedIndex = index + 1; enteredEmailOrMobile = false; _PhoneNumberController.text = ''; _emailController.text = ''; _otpController.text = ''; _PhoneNumberController.clear(); _emailController.clear(); _otpController.clear(); if (selectedIndex == 2) { switcherStatus = 0; } else { switcherStatus = 1; } }); _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(0xFF436462) : Colors.transparent, boxShadow: isSelected ? [ BoxShadow( color: isSelected ? const Color(0xFF436462) : 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, ), ), ), ); } } // // @override // Widget build(BuildContext context) { // final isWeb = MediaQuery.of(context).size.width > 600; // // return Scaffold( // body: Center( // child: Container( // constraints: const BoxConstraints(maxWidth: 400), // padding: const EdgeInsets.all(16.0), // decoration: isWeb // ? BoxDecoration( // color: Colors.white, // borderRadius: BorderRadius.circular(8), // boxShadow: [ // BoxShadow( // blurRadius: 12, // color: Colors.black.withOpacity(0.1), // ), // ], // ) // : null, // child: Form( // key: _formKey, // child: Column( // mainAxisSize: MainAxisSize.min, // children: [ // // App Logo // Image.asset('assets/logo.png', width: 80, height: 80), // const SizedBox(height: 20), // // // Environment label // Text( // "Environment: ${Env.envName.toUpperCase()}", // style: const TextStyle(fontSize: 14, color: Colors.grey), // ), // const SizedBox(height: 20), // // ThemedFormField( // hintText: 'Email', // backgroundColor: Colors.white, // validator: (value) => Validators.email(value, "Email"), // // imgPath: "MiscIconAssetPath.person", // controller: _emailController, // // txtwidth: MediaQuery.of(context).size.width * 0.5, // // keyboardType: TextInputType.number, // // maxLength: 10, // // inputFormatters: [FilteringTextInputFormatter.digitsOnly], // // readOnly: true, // ), // // const SizedBox(height: 16), // ThemedFormField( // hintText: 'Password', // backgroundColor: Colors.white, // validator: (value) => // Validators.passwordlogIn(value, "Password"), // // imgPath: "MiscIconAssetPath.person", // controller: _passwordController, // isObscurable: true, // // txtwidth: MediaQuery.of(context).size.width * 0.5, // // keyboardType: TextInputType.number, // // maxLength: 10, // // inputFormatters: [FilteringTextInputFormatter.digitsOnly], // // readOnly: true, // ), // // // Password // const SizedBox(height: 24), // // // Login Button // SizedBox( // width: double.infinity, // child: ElevatedButton( // onPressed: _isLoading ? null : _handleLogin, // child: _isLoading // ? const SizedBox( // height: 20, // width: 20, // child: CircularProgressIndicator( // strokeWidth: 2, // valueColor: AlwaysStoppedAnimation( // Colors.white, // ), // ), // ) // : const Text("Login"), // ), // ), // // const SizedBox(height: 12), // // // Forgot password link // TextButton( // onPressed: () { // // TODO: Navigate to forgot password screen // }, // child: const Text("Forgot password?"), // ), // ], // ), // ), // ), // ), // ); // }