import 'dart:async'; import 'package:flutter/material.dart'; import 'package:prosapp_web_app/providers/auth_provider.dart'; import 'package:prosapp_web_app/router/router.dart'; import 'package:provider/provider.dart'; class PhoneLoginView extends StatefulWidget { const PhoneLoginView({super.key}); @override State createState() => _PhoneLoginViewState(); } class _PhoneLoginViewState extends State { final _phoneController = TextEditingController(); final _otpController = TextEditingController(); bool _codeSent = false; bool _loading = false; String _phone = ''; int _resendSeconds = 0; Timer? _timer; @override void dispose() { _phoneController.dispose(); _otpController.dispose(); _timer?.cancel(); super.dispose(); } void _startResendTimer() { setState(() => _resendSeconds = 60); _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 1), (t) { if (_resendSeconds == 0) { t.cancel(); } else { setState(() => _resendSeconds--); } }); } Future _sendCode() async { final raw = _phoneController.text.trim(); if (raw.length < 7) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Ingresa un número válido')), ); return; } _phone = '+57$raw'; setState(() => _loading = true); try { await Provider.of(context, listen: false).verifyPhoneNumber(_phone); setState(() => _codeSent = true); _startResendTimer(); } catch (_) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Error al enviar código. Verifica el número.')), ); } finally { setState(() => _loading = false); } } Future _verifyOtp() async { final otp = _otpController.text.trim(); if (otp.length != 6) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Ingresa el código de 6 dígitos')), ); return; } setState(() => _loading = true); await Provider.of(context, listen: false).signInWithOTP(_phone, otp); setState(() => _loading = false); } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; final cardColor = isDark ? const Color(0xFF1E293B) : Colors.white; final titleColor = isDark ? Colors.white : const Color(0xFF0F172A); final subtitleColor = isDark ? const Color(0xFF94A3B8) : const Color(0xFF64748B); final inputFill = isDark ? const Color(0xFF0F172A) : const Color(0xFFF8FAFF); final inputBorder = isDark ? const Color(0xFF334155) : const Color(0xFFCDD5F0); final inputTextColor = isDark ? Colors.white : const Color(0xFF0F172A); final prefixFill = isDark ? const Color(0xFF0F172A) : const Color(0xFFEEF0FF); final prefixBorder = isDark ? const Color(0xFF334155) : const Color(0xFFCDD5F0); return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 420), child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 32), child: Container( decoration: BoxDecoration( color: cardColor, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(isDark ? 0.3 : 0.08), blurRadius: 24, offset: const Offset(0, 4), ), ], ), padding: const EdgeInsets.all(28), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!_codeSent) _buildPhoneForm(titleColor, subtitleColor, inputFill, inputBorder, inputTextColor, prefixFill, prefixBorder) else _buildOtpForm(titleColor, subtitleColor, inputFill, inputBorder, inputTextColor), ], ), ), ), ), ); } Widget _buildPhoneForm( Color titleColor, Color subtitleColor, Color inputFill, Color inputBorder, Color inputTextColor, Color prefixFill, Color prefixBorder, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Iniciar sesión', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: titleColor), ), const SizedBox(height: 4), Text( 'Te enviaremos un código de 6 dígitos', style: TextStyle(color: subtitleColor, fontSize: 13), ), const SizedBox(height: 24), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 18), decoration: BoxDecoration( color: prefixFill, borderRadius: BorderRadius.circular(10), border: Border.all(color: prefixBorder), ), child: Text( '+57', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: titleColor), ), ), const SizedBox(width: 10), Expanded( child: TextField( controller: _phoneController, keyboardType: TextInputType.phone, style: TextStyle(color: inputTextColor, fontSize: 15), decoration: InputDecoration( hintText: '300 123 4567', hintStyle: TextStyle(color: subtitleColor), filled: true, fillColor: inputFill, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: inputBorder), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFF42A4EF), width: 2), ), ), ), ), ], ), const SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _loading ? null : _sendCode, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF42A4EF), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), elevation: 0, ), child: _loading ? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) : const Text('Enviar código', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ), ), const SizedBox(height: 24), Row(children: [ const Expanded(child: Divider()), Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Text('o', style: TextStyle(color: subtitleColor)), ), const Expanded(child: Divider()), ]), const SizedBox(height: 16), SizedBox( width: double.infinity, child: OutlinedButton( onPressed: () => Navigator.pushReplacementNamed(context, Flurorouter.loginRoute), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), side: const BorderSide(color: Color(0xFF42A4EF)), ), child: const Text( 'Iniciar sesión con email', style: TextStyle(color: Color(0xFF42A4EF), fontWeight: FontWeight.w600), ), ), ), const SizedBox(height: 12), Center( child: TextButton( onPressed: () => Navigator.pushReplacementNamed(context, Flurorouter.registerRoute), child: RichText( text: TextSpan( style: TextStyle(color: subtitleColor, fontSize: 13), children: const [ TextSpan(text: '¿No tienes cuenta? '), TextSpan( text: 'Regístrate', style: TextStyle(color: Color(0xFF42A4EF), fontWeight: FontWeight.w600), ), ], ), ), ), ), ], ); } Widget _buildOtpForm( Color titleColor, Color subtitleColor, Color inputFill, Color inputBorder, Color inputTextColor, ) { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon(Icons.sms_outlined, size: 52, color: Color(0xFF42A4EF)), const SizedBox(height: 12), Text( 'Código de verificación', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: titleColor), ), const SizedBox(height: 8), Text( 'Enviamos un SMS a $_phone', textAlign: TextAlign.center, style: TextStyle(color: subtitleColor, fontSize: 13), ), const SizedBox(height: 28), TextField( controller: _otpController, keyboardType: TextInputType.number, textAlign: TextAlign.center, maxLength: 6, style: TextStyle( fontSize: 28, fontWeight: FontWeight.bold, letterSpacing: 12, color: inputTextColor, ), decoration: InputDecoration( counterText: '', hintText: '------', hintStyle: TextStyle(letterSpacing: 12, color: subtitleColor), filled: true, fillColor: inputFill, border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: inputBorder)), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Color(0xFF42A4EF), width: 2)), ), ), const SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _loading ? null : _verifyOtp, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF42A4EF), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), elevation: 0, ), child: _loading ? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) : const Text('Verificar', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ), ), const SizedBox(height: 16), _resendSeconds > 0 ? Text('Reenviar en $_resendSeconds s', style: TextStyle(color: subtitleColor, fontSize: 13)) : TextButton( onPressed: _sendCode, child: const Text('Reenviar código', style: TextStyle(color: Color(0xFF42A4EF), fontWeight: FontWeight.w600)), ), const SizedBox(height: 8), TextButton( onPressed: () => setState(() { _codeSent = false; _otpController.clear(); }), child: Text('← Cambiar número', style: TextStyle(color: subtitleColor, fontSize: 13)), ), ], ); } }