import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:qpay/models/responsive_policy.dart'; import 'package:qpay/screens/onboarding/verify/verify_controller.dart'; import 'package:skeletonizer/skeletonizer.dart'; class VerifyScreen extends StatefulWidget { const VerifyScreen({super.key}); @override State createState() => _VerifyScreenState(); } class _VerifyScreenState extends State { late VerifyController verifyController; String? errorMessage; @override void initState() { super.initState(); verifyController = VerifyController(context); } final List _codeControllers = List.generate( 6, (index) => TextEditingController(), ); final List _focusNodes = List.generate(6, (index) => FocusNode()); @override void dispose() { for (var controller in _codeControllers) { controller.dispose(); } for (var node in _focusNodes) { node.dispose(); } super.dispose(); } void showErrorMessage(String? message) { setState(() { errorMessage = message; }); } void _onCodeChanged(String value, int index) { if (value.length == 1 && index < 5) { _focusNodes[index + 1].requestFocus(); } } @override Widget build(BuildContext context) { return ListenableBuilder( listenable: verifyController, builder: (context, child) { return Scaffold( body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(25), child: Center( child: LayoutBuilder( builder: (context, constraints) { final maxWidth = constraints.maxWidth > ResponsivePolicy.md ? ResponsivePolicy.md.toDouble() : constraints.maxWidth; return SizedBox( width: maxWidth, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 75), Text( 'Verify Your Account', style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary, ), ), SizedBox(height: 5), Text( 'Enter the 6-digit code sent to your phone/email', style: TextStyle(fontSize: 18), textAlign: TextAlign.center, ), Image.asset('assets/verify.png', width: 300), // Verification Code Input Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: List.generate( 6, (index) => SizedBox( width: 50, child: TextFormField( controller: _codeControllers[index], focusNode: _focusNodes[index], textAlign: TextAlign.center, keyboardType: TextInputType.number, maxLength: 1, decoration: InputDecoration( counterText: '', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, width: 2, ), ), contentPadding: EdgeInsets.symmetric(vertical: 16), ), onChanged: (value) => _onCodeChanged(value, index), ), ), ), ), SizedBox(height: 5), if(errorMessage != null) Text(errorMessage ?? '', style: TextStyle(color: Colors.red)), SizedBox(height: 30), // Resend Code Section Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Didn't receive the code? ", style: TextStyle(color: Colors.grey.shade600, fontSize: 16), ), TextButton( onPressed: () { verifyController.resendOtp(); }, child: Text( 'Resend Code', style: TextStyle( color: Theme.of(context).colorScheme.primary, fontSize: 16, fontWeight: FontWeight.w600, ), ), ), ], ), // SizedBox(height: 20), // // Timer for resend (optional) // Text( // 'Resend available in 2:30', // style: TextStyle(color: Colors.grey.shade500, fontSize: 14), // ), SizedBox(height: 40), Padding( padding: const EdgeInsets.symmetric(horizontal: 25), child: Skeletonizer( enabled: verifyController.model.isLoading, child: Row( children: [ Expanded( child: ElevatedButton( onPressed: () async { showErrorMessage(null); String code = ''; for (var controller in _codeControllers) { code += controller.text; } if(code.length != 6) { showErrorMessage('Invalid code'); return; } verifyController.updateCode(code); await verifyController.verifyOtp(); if(verifyController.model.status == 'done') { context.go('/onboarding/complete'); } }, child: Text( 'Verify Code', style: TextStyle(fontSize: 16), ), ), ), SizedBox(width: 16), Expanded( child: OutlinedButton( onPressed: () { context.go('/onboarding/login'); }, child: Text( 'Back to Login', style: TextStyle(fontSize: 16), ), ), ), ], ), ), ), SizedBox(height: 10), TextButton( onPressed: () { context.go('/'); }, child: Text('Continue as guest?', style: TextStyle(fontSize: 14)), ), ], ), ); } ), ), ), ), ); } ); } }