import 'dart:async'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get/get.dart'; import 'package:taxglide/consts/app_asstes.dart'; import 'package:taxglide/consts/app_colors.dart'; import 'package:taxglide/consts/comman_button.dart'; import 'package:taxglide/consts/comman_container_auth.dart'; import 'package:taxglide/consts/validation_popup.dart'; import 'package:taxglide/controller/api_contoller.dart'; import 'package:taxglide/router/consts_routers.dart'; import 'package:taxglide/view/Main_controller/main_controller.dart'; class RegisterOtpScreen extends ConsumerStatefulWidget { const RegisterOtpScreen({super.key}); @override ConsumerState createState() => _RegisterOtpScreenState(); } class _RegisterOtpScreenState extends ConsumerState { final ValidationPopup _validationPopup = ValidationPopup(); final int otpLength = 4; final List _controllers = []; final List _focusNodes = []; String otpValue = ''; // Timer variables Timer? _timer; int _remainingSeconds = 600; // 10 minutes = 600 seconds bool _canResend = false; // Get arguments passed from signup late String name; late String email; late String mobile; @override void initState() { super.initState(); // Get arguments from navigation final args = Get.arguments as Map; name = args['name'] ?? ''; email = args['email'] ?? ''; mobile = args['mobile'] ?? ''; for (int i = 0; i < otpLength; i++) { _controllers.add(TextEditingController()); _focusNodes.add(FocusNode()); } _startTimer(); } @override void dispose() { _timer?.cancel(); for (var c in _controllers) { c.dispose(); } for (var f in _focusNodes) { f.dispose(); } super.dispose(); } void _startTimer() { _canResend = false; _remainingSeconds = 30; // Reset to 30 seconds _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_remainingSeconds > 0) { setState(() { _remainingSeconds--; }); } else { setState(() { _canResend = true; }); timer.cancel(); } }); } String _formatTime(int seconds) { int minutes = seconds ~/ 60; int remainingSeconds = seconds % 60; return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}'; } void _resendOtp() async { if (!_canResend) return; for (var controller in _controllers) { controller.clear(); } setState(() { otpValue = ''; }); // Move focus to first field _focusNodes[0].requestFocus(); try { // Call signup API again to resend OTP await ref.read(signupProvider.notifier).signup(name, mobile, email); final signupState = ref.read(signupProvider); signupState.when( data: (result) { if (result['success'] == true) { _validationPopup.showSuccessMessage( context, "OTP has been resent successfully!", ); _startTimer(); // Clear OTP fields for (var controller in _controllers) { controller.clear(); } setState(() { otpValue = ''; }); } else { _validationPopup.showErrorMessage( context, result['error'] ?? "Failed to resend OTP", ); } }, loading: () { // Show loading indicator }, error: (error, stack) { _validationPopup.showErrorMessage( context, "Failed to resend OTP. Please try again.", ); }, ); } catch (e) { _validationPopup.showErrorMessage( context, "An error occurred. Please try again.", ); } } void _verifyOtp() async { if (otpValue.length != otpLength) { _validationPopup.showErrorMessage(context, "Please enter all OTP digits"); return; } // Call verify OTP API for signup await ref.read(signupProvider.notifier).verifySignupOtp(mobile, otpValue); final signupState = ref.read(signupProvider); signupState.when( data: (result) { if (result['success'] == true) { _validationPopup.showSuccessMessage( context, "Registration Successful!", ); // Navigate to main screen after successful verification Future.delayed(const Duration(seconds: 1), () { Get.offAll(() => MainController()); }); } else { _validationPopup.showErrorMessage( context, result['error'] ?? "Invalid OTP. Please try again.", ); } }, loading: () { // Loading is handled by the provider }, error: (error, stack) { _validationPopup.showErrorMessage( context, "Failed to verify OTP. Please try again.", ); }, ); } void _onOtpChange(int index, String value) { if (value.isNotEmpty && index < otpLength - 1) { _focusNodes[index + 1].requestFocus(); } if (value.isEmpty && index > 0) { _focusNodes[index - 1].requestFocus(); } setState(() { otpValue = _controllers.map((c) => c.text).join(); }); } @override Widget build(BuildContext context) { final signupState = ref.watch(signupProvider); final isLoading = signupState is AsyncLoading; return Scaffold( body: Stack( children: [ // Background gradient Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Color(0xFFFFF8F0), Color(0xFFEBC894), Color(0xFFE8DAF2), Color(0xFFB49EF4), ], stops: [0.0, 0.3, 0.6, 1.0], ), ), ), // Scrollable content SingleChildScrollView( child: SizedBox( height: MediaQuery.of(context).size.height, child: Center( child: CommonContainerAuth( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( AppAssets.taxgildelogoauth, width: 141, height: 100, fit: BoxFit.contain, ), const SizedBox(height: 20), Text( "Enter OTP", textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Gilroy-SemiBold', fontSize: 32, fontWeight: FontWeight.w600, height: 1.3, letterSpacing: 0.01 * 32, color: AppColors.authheading, ), ), const SizedBox(height: 20), Text( "OTP has been sent to your registered mobile number", textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Gilroy-SemiBold', fontSize: 14, fontWeight: FontWeight.w600, height: 1.4, letterSpacing: 0.03 * 14, color: AppColors.authleading, ), ), const SizedBox(height: 22), Text.rich( TextSpan( text: mobile, style: const TextStyle( fontFamily: 'Gilroy-Medium', fontWeight: FontWeight.w500, fontSize: 13, height: 1.8, letterSpacing: 0.01, color: AppColors.authleading, ), children: [ TextSpan( text: " ( Change Number )", style: const TextStyle( fontFamily: 'Gilroy-ExtraBold', fontWeight: FontWeight.w800, fontSize: 13, height: 1.8, letterSpacing: 0.04, color: AppColors.authchange, ), recognizer: TapGestureRecognizer() ..onTap = () { Get.offNamed( ConstRouters.signup, arguments: { 'name': name, 'email': email, 'mobile': mobile, }, ); }, ), ], ), textAlign: TextAlign.center, ), const SizedBox(height: 30), // OTP Boxes Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(otpLength, (index) { bool isFilled = _controllers[index].text.isNotEmpty; return Container( margin: const EdgeInsets.symmetric(horizontal: 6), width: 60, height: 56, decoration: BoxDecoration( color: isFilled ? AppColors.commanbutton : Colors.white, borderRadius: BorderRadius.circular(6), border: Border.all( color: const Color(0xFFDFDFDF), ), boxShadow: [ BoxShadow( color: const Color( 0xFFBDBDBD, ).withOpacity(0.25), blurRadius: 7, offset: const Offset(0, 1), ), ], ), child: Center( child: TextField( controller: _controllers[index], focusNode: _focusNodes[index], textAlign: TextAlign.center, keyboardType: TextInputType.number, maxLength: 1, enabled: !isLoading, style: TextStyle( fontFamily: 'Gilroy-Medium', fontWeight: FontWeight.w400, fontSize: 28, letterSpacing: 0.03 * 28, color: isFilled ? Colors.white : Colors.black, ), decoration: const InputDecoration( counterText: '', border: InputBorder.none, ), onChanged: (value) => _onOtpChange(index, value), ), ), ); }), ), const SizedBox(height: 10), // Resend OTP Button Align( alignment: Alignment.centerRight, child: GestureDetector( onTap: _canResend && !isLoading ? _resendOtp : null, child: Text( "Resend", textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Gilroy-Medium', fontWeight: FontWeight.w500, fontSize: 14, height: 1.4, letterSpacing: 0.02 * 14, color: _canResend && !isLoading ? AppColors.authchange : Colors.grey, ), ), ), ), const SizedBox(height: 20), // Timer Display Text( _formatTime(_remainingSeconds), style: TextStyle( fontFamily: 'Gilroy-Medium', fontWeight: FontWeight.w600, fontSize: 16, color: _remainingSeconds > 0 ? AppColors.authheading : Colors.red, ), ), const SizedBox(height: 30), // Verify Button isLoading ? const CircularProgressIndicator() : CommanButton(text: "Verify", onPressed: _verifyOtp), ], ), ), ), ), ), ], ), ); } }