diff --git a/lib/models/usuario.dart b/lib/models/usuario.dart index 0852c58..126f2fc 100644 --- a/lib/models/usuario.dart +++ b/lib/models/usuario.dart @@ -11,6 +11,7 @@ class Usuario { final String? birthday; final String? gender; final ProState proState; + final DateTime? proRejectedAt; final String? token; final bool isPhoneVerified; @@ -26,6 +27,7 @@ class Usuario { required this.gender, required this.proState, required this.token, + this.proRejectedAt, this.isPhoneVerified = false, }); @@ -57,11 +59,24 @@ class Usuario { birthday: doc['birthday'], gender: doc['gender'], proState: intToEnum((doc['professional_state'] as int?) ?? 0), + proRejectedAt: _parseRejectedAt(doc), token: doc['token'], isPhoneVerified: doc['is_phone_verified'] as bool? ?? false, ); } + static DateTime? _parseRejectedAt(Map doc) { + // /auth/me returns professionals nested; if pro_state==3 use professionals.updated_at + final state = (doc['professional_state'] as int?) ?? 0; + if (state != 3) return null; + final pros = doc['professionals']; + if (pros is Map) { + final raw = pros['updated_at']; + if (raw is String) return DateTime.tryParse(raw); + } + return null; + } + @override String toString() { return 'User(id: $id, email: $email, phone: $phone, name: $name, nickname: $nickname, city: $city, picture: $picture, birthday: $birthday, gender: $gender, proState: $proState, token: $token)'; diff --git a/lib/ui/views/request_professional_view.dart b/lib/ui/views/request_professional_view.dart index fe406a0..5af1e56 100644 --- a/lib/ui/views/request_professional_view.dart +++ b/lib/ui/views/request_professional_view.dart @@ -611,7 +611,7 @@ class _UploadTile extends StatelessWidget { } } -class _StatusCard extends StatelessWidget { +class _StatusCard extends StatefulWidget { final Color cardBg; final Color border; final Color textPrimary; @@ -626,26 +626,62 @@ class _StatusCard extends StatelessWidget { required this.isPending, }); + @override + State<_StatusCard> createState() => _StatusCardState(); +} + +class _StatusCardState extends State<_StatusCard> { + int _waitDays = 7; + bool _loadingSettings = true; + + @override + void initState() { + super.initState(); + if (!widget.isPending) _loadWaitDays(); + } + + Future _loadWaitDays() async { + try { + final data = await ApiService.instance.get('/settings') as Map; + final v = data['rejection_wait_days']; + if (v != null) setState(() => _waitDays = (v as num).toInt()); + } catch (_) {} + if (mounted) setState(() => _loadingSettings = false); + } + + Future _retry() async { + try { + await ApiService.instance.delete('/professionals/me'); + } catch (_) {} + if (mounted) await context.read().isAuthenticated(); + } + @override Widget build(BuildContext context) { - final accent = isPending + final accent = widget.isPending ? const Color(0xFFF59E0B) : const Color(0xFFEF4444); + final user = context.watch().user; + final rejectedAt = user?.proRejectedAt; + final daysSince = rejectedAt != null + ? DateTime.now().difference(rejectedAt).inDays + : _waitDays; + final daysLeft = (_waitDays - daysSince).clamp(0, _waitDays); + final canRetry = !widget.isPending && daysLeft == 0; + return Container( margin: const EdgeInsets.only(top: 24), padding: const EdgeInsets.all(32), decoration: BoxDecoration( - color: cardBg, + color: widget.cardBg, borderRadius: BorderRadius.circular(16), - border: Border.all(color: border), + border: Border.all(color: widget.border), ), child: Column( children: [ - if (isPending) - const Image( - image: AssetImage('assets/checklist.gif'), - width: 160) + if (widget.isPending) + const Image(image: AssetImage('assets/checklist.gif'), width: 160) else Container( padding: const EdgeInsets.all(20), @@ -653,63 +689,70 @@ class _StatusCard extends StatelessWidget { color: accent.withOpacity(0.1), shape: BoxShape.circle, ), - child: Icon( - isPending - ? Icons.hourglass_empty_rounded - : Icons.sentiment_dissatisfied_outlined, - size: 52, - color: accent), + child: Icon(Icons.sentiment_dissatisfied_outlined, size: 52, color: accent), ), const SizedBox(height: 18), Text( - isPending - ? 'Solicitud en revisión' - : 'Solicitud no aprobada', - style: TextStyle( - fontSize: 19, - fontWeight: FontWeight.bold, - color: textPrimary), + widget.isPending ? 'Solicitud en revisión' : 'Solicitud no aprobada', + style: TextStyle(fontSize: 19, fontWeight: FontWeight.bold, color: widget.textPrimary), ), const SizedBox(height: 10), Text( - isPending + widget.isPending ? 'Estamos revisando tus datos. Te notificaremos cuando tu cuenta esté aprobada.' - : 'Tu solicitud no fue aprobada. Revisa tus documentos y vuelve a intentarlo.', + : canRetry + ? 'Puedes volver a enviar tu solicitud con los documentos corregidos.' + : 'Tu solicitud no fue aprobada. Podrás reintentar en $daysLeft día${daysLeft == 1 ? '' : 's'}.', textAlign: TextAlign.center, - style: - TextStyle(color: textSec, fontSize: 13, height: 1.5), + style: TextStyle(color: widget.textSec, fontSize: 13, height: 1.5), ), const SizedBox(height: 16), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 14, vertical: 8), - decoration: BoxDecoration( - color: accent.withOpacity(0.12), - borderRadius: BorderRadius.circular(10), - border: - Border.all(color: accent.withOpacity(0.4)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - isPending - ? Icons.hourglass_empty_rounded - : Icons.cancel_outlined, - color: accent, - size: 16, + if (!widget.isPending && !_loadingSettings) ...[ + if (canRetry) + FilledButton.icon( + onPressed: _retry, + icon: const Icon(Icons.refresh, size: 18), + label: const Text('Volver a solicitar'), + style: FilledButton.styleFrom(backgroundColor: const Color(0xFF42A4EF)), + ) + else + Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), + decoration: BoxDecoration( + color: accent.withOpacity(0.12), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: accent.withOpacity(0.4)), ), - const SizedBox(width: 6), - Text( - isPending ? 'Revisión en proceso' : 'No aprobado', - style: TextStyle( - color: accent, - fontWeight: FontWeight.w600, - fontSize: 13), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.timer_outlined, color: accent, size: 16), + const SizedBox(width: 6), + Text( + 'Disponible en $daysLeft día${daysLeft == 1 ? '' : 's'}', + style: TextStyle(color: accent, fontWeight: FontWeight.w600, fontSize: 13), + ), + ], ), - ], + ), + ] else if (widget.isPending) + Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), + decoration: BoxDecoration( + color: accent.withOpacity(0.12), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: accent.withOpacity(0.4)), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.hourglass_empty_rounded, color: accent, size: 16), + const SizedBox(width: 6), + Text('Revisión en proceso', + style: TextStyle(color: accent, fontWeight: FontWeight.w600, fontSize: 13)), + ], + ), ), - ), ], ), );