import 'dart:async'; import 'package:flutter/material.dart'; import '../theme.dart'; import '../route_transitions.dart'; import '../feedback_helper.dart'; import 'business_setup_screen.dart'; class OtpVerificationScreen extends StatefulWidget { final String mobileNumber; const OtpVerificationScreen({super.key, required this.mobileNumber}); @override State createState() => _OtpVerificationScreenState(); } class _OtpVerificationScreenState extends State { late Timer _timer; int _timeLeft = 45; final List _controllers = List.generate(6, (_) => TextEditingController()); final List _focusNodes = List.generate(6, (_) => FocusNode()); @override void initState() { super.initState(); _startCountdown(); } void _startCountdown() { _timeLeft = 45; _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_timeLeft <= 0) { _timer.cancel(); } else { setState(() { _timeLeft--; }); } }); } @override void dispose() { _timer.cancel(); for (var controller in _controllers) { controller.dispose(); } for (var node in _focusNodes) { node.dispose(); } super.dispose(); } void _verifyOtp() { final code = _controllers.map((c) => c.text.trim()).join(); if (code.length < 6) { AppFeedback.error(); showTopAlert(context, 'Please enter a valid 6-digit OTP code.', isError: true); return; } AppFeedback.success(); showTopAlert(context, 'OTP Verified Successfully!'); Navigator.pushReplacement( context, FadeSlidePageRoute(child: const BusinessSetupScreen()), ); } String _getFormattedTime() { return '00:${_timeLeft.toString().padLeft(2, '0')}'; } @override Widget build(BuildContext context) { final theme = Theme.of(context); final padding = context.responsivePadding; final displayMobile = widget.mobileNumber.length == 10 ? '+91 ${widget.mobileNumber.substring(0, 5)} ${widget.mobileNumber.substring(5)}' : '+91 ${widget.mobileNumber}'; return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back, color: Color(0xFFBA1A20)), onPressed: () { AppFeedback.click(); Navigator.pop(context); }, ), title: Text( 'PozoApp', style: theme.textTheme.headlineMedium?.copyWith( color: theme.colorScheme.primary, fontWeight: FontWeight.bold, ), ), actions: [ Padding( padding: EdgeInsets.symmetric(horizontal: padding), child: Center( child: Text( 'Step 2.5 of 5', style: theme.textTheme.labelMedium?.copyWith( fontWeight: FontWeight.bold, ), ), ), ) ], bottom: PreferredSize( preferredSize: const Size.fromHeight(6), child: Row( children: List.generate(5, (index) { return Expanded( child: Container( height: 6, margin: const EdgeInsets.symmetric(horizontal: 2.0), decoration: BoxDecoration( color: index <= 1 ? theme.colorScheme.primary : (index == 2 ? theme.colorScheme.primary.withOpacity(0.5) : theme.colorScheme.surfaceContainerHighest), borderRadius: BorderRadius.circular(3), ), ), ); }), ), ), ), body: SafeArea( child: Column( children: [ Expanded( child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 600), child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // Alert envelope pulse symbol with SlideFadeEntrance SlideFadeEntrance( delay: Duration.zero, child: Center( child: Container( width: 96, height: 96, decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerHigh, shape: BoxShape.circle, ), child: Center( child: Container( width: 72, height: 72, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.06), blurRadius: 10, ) ], ), child: Icon( Icons.sms, color: theme.colorScheme.primary, size: 38, ), ), ), ), ), ), const SizedBox(height: 16), SlideFadeEntrance( delay: const Duration(milliseconds: 100), child: Text( 'Verifying your number', textAlign: TextAlign.center, style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 16), SlideFadeEntrance( delay: const Duration(milliseconds: 150), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "Sent code to $displayMobile", style: theme.textTheme.bodyMedium, ), const SizedBox(width: 8), InteractiveScale( onTap: () { AppFeedback.click(); Navigator.pop(context); }, child: Text( 'Edit', style: TextStyle( color: theme.colorScheme.primary, fontWeight: FontWeight.bold, fontSize: 14, ), ), ), ], ), ), const SizedBox(height: 20), // 6 Custom Inputs Fields with SlideFadeEntrance SlideFadeEntrance( delay: const Duration(milliseconds: 200), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(11, (index) { if (index.isOdd) { return const SizedBox(width: 8); } final fieldIndex = index ~/ 2; return SizedBox( width: 44, child: TextField( controller: _controllers[fieldIndex], focusNode: _focusNodes[fieldIndex], keyboardType: TextInputType.number, textAlign: TextAlign.center, maxLength: 1, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), decoration: InputDecoration( counterText: '', contentPadding: const EdgeInsets.symmetric(vertical: 12), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: theme.colorScheme.outlineVariant), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: theme.colorScheme.primary, width: 2), ), ), onChanged: (value) { AppFeedback.subtleHaptic(); if (value.isNotEmpty) { if (fieldIndex < 5) { _focusNodes[fieldIndex + 1].requestFocus(); } else { _verifyOtp(); } } else if (value.isEmpty && fieldIndex > 0) { _focusNodes[fieldIndex - 1].requestFocus(); } }, ), ); }), ), ), const SizedBox(height: 24), // Auto detect loader card with SlideFadeEntrance SlideFadeEntrance( delay: const Duration(milliseconds: 250), child: Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(16), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 14, height: 14, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(theme.colorScheme.primary), ), ), const SizedBox(width: 12), Text( 'Auto-detecting OTP...', style: theme.textTheme.bodySmall?.copyWith( fontWeight: FontWeight.bold, ), ), ], ), ), ), const SizedBox(height: 24), // Resending timer action row SlideFadeEntrance( delay: const Duration(milliseconds: 300), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.schedule, size: 16, color: Colors.grey), const SizedBox(width: 6), Text( _timeLeft > 0 ? 'Resend code in ${_getFormattedTime()}' : 'Resend Code via SMS', style: theme.textTheme.bodyMedium, ), ], ), ), const SizedBox(height: 16), // WhatsApp custom CTA button with InteractiveScale SlideFadeEntrance( delay: const Duration(milliseconds: 350), child: InteractiveScale( child: OutlinedButton.icon( onPressed: () { AppFeedback.click(); showTopAlert( context, 'WhatsApp verification request sent!', icon: Icons.chat_bubble_outline, ); }, icon: const Icon(Icons.forum, color: Colors.green, size: 18), label: const Text( 'Resend via WhatsApp', style: TextStyle( fontSize: 13, fontWeight: FontWeight.bold, color: Colors.black87, ), ), style: OutlinedButton.styleFrom( backgroundColor: Colors.white, side: const BorderSide(color: Color(0xFFE2E2E2)), elevation: 1, minimumSize: const Size(220, 48), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ), ) ], ), ), ), ), ), ), // Pinned Bottom Dock Container( height: 80, decoration: BoxDecoration( color: Colors.white, border: Border(top: BorderSide(color: Colors.grey[200]!)), ), child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 600), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildFooterAction(Icons.help_outline, 'Help', () { showTopAlert( context, 'Support agent contacted. We will call you shortly.', icon: Icons.support_agent_outlined, ); }), _buildFooterAction(Icons.save, 'Save Draft', () { showTopAlert( context, 'Onboarding draft saved successfully!', icon: Icons.save_outlined, ); }), InteractiveScale( child: TextButton.icon( onPressed: _verifyOtp, icon: const Text( 'Verify Manually', style: TextStyle(fontWeight: FontWeight.bold), ), label: const Icon(Icons.arrow_forward, size: 16), style: TextButton.styleFrom( foregroundColor: Colors.white, backgroundColor: theme.colorScheme.primary, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), ), ), ) ], ), ), ), ), ) ], ), ), ); } Widget _buildFooterAction(IconData icon, String label, VoidCallback onTap) { return InteractiveScale( onTap: () { AppFeedback.click(); onTap(); }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, color: Colors.grey[600], size: 22), const SizedBox(height: 4), Text( label, style: TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: Colors.grey[600], ), ) ], ), ); } }