// lib/features/feedback/feedback_screen.dart // Buzón de retroalimentación. Expone "Unidad 101", nunca el nombre del chofer. import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'feedback_model.dart'; import 'feedback_provider.dart'; import '../eta/eta_provider.dart'; // activeAddressIdProvider // El unitId activo se obtiene del ETA response o de la sesión del chofer. // Por simplidad se provee aquí; en producción viene del provider de sesión. final activeUnitIdProvider = StateProvider((ref) => '101'); class FeedbackScreen extends ConsumerStatefulWidget { const FeedbackScreen({super.key}); @override ConsumerState createState() => _FeedbackScreenState(); } class _FeedbackScreenState extends ConsumerState { final _messageController = TextEditingController(); @override void dispose() { _messageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final formState = ref.watch(feedbackProvider); if (formState.status == FeedbackFormStatus.success) { return _SuccessView(onReset: () { ref.read(feedbackProvider.notifier).reset(); _messageController.clear(); }); } return Scaffold( appBar: AppBar(title: const Text('Buzón de retroalimentación')), body: ListView( padding: const EdgeInsets.all(16), children: [ // Tipo de reporte const _SectionLabel('Tipo de reporte'), const SizedBox(height: 8), _TypeChips( selected: formState.selectedType, onSelect: (t) => ref.read(feedbackProvider.notifier).setType(t), ), const SizedBox(height: 20), // Rating const _SectionLabel('Calificación del servicio'), const SizedBox(height: 8), _StarRating( rating: formState.rating, onRate: (r) => ref.read(feedbackProvider.notifier).setRating(r), ), const SizedBox(height: 20), // Unidad (sin exponer chofer) const _SectionLabel('Unidad involucrada'), const SizedBox(height: 8), const _UnitBadge(), const SizedBox(height: 20), // Mensaje libre const _SectionLabel('Descripción (opcional)'), const SizedBox(height: 8), TextField( controller: _messageController, maxLines: 4, maxLength: 300, onChanged: (v) => ref.read(feedbackProvider.notifier).setMessage(v), decoration: InputDecoration( hintText: 'Cuéntanos qué pasó...', border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), ), ), const SizedBox(height: 8), // Error if (formState.status == FeedbackFormStatus.error) _ErrorBanner(message: formState.errorMessage ?? 'Error'), const SizedBox(height: 8), // Submit SizedBox( width: double.infinity, child: FilledButton( onPressed: formState.status == FeedbackFormStatus.loading ? null : () { final addressId = ref.read(activeAddressIdProvider); final unitId = ref.read(activeUnitIdProvider); if (addressId == null) return; ref.read(feedbackProvider.notifier).submit( addressId: addressId, unitId: unitId, ); }, child: formState.status == FeedbackFormStatus.loading ? const SizedBox( height: 18, width: 18, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : const Text('Enviar reporte'), ), ), const SizedBox(height: 24), ], ), ); } } // ────────────────────────────────────────── // Chips de tipo // ────────────────────────────────────────── class _TypeChips extends StatelessWidget { final FeedbackType selected; final ValueChanged onSelect; const _TypeChips({required this.selected, required this.onSelect}); @override Widget build(BuildContext context) { return Wrap( spacing: 8, runSpacing: 8, children: FeedbackType.values.map((t) { final isSelected = t == selected; return ChoiceChip( label: Text(t.label), selected: isSelected, onSelected: (_) => onSelect(t), selectedColor: const Color(0xFFE1F5EE), side: BorderSide( color: isSelected ? const Color(0xFF5DCAA5) : Theme.of(context).colorScheme.outlineVariant, ), labelStyle: TextStyle( color: isSelected ? const Color(0xFF085041) : Theme.of(context).colorScheme.onSurface, fontSize: 13, ), ); }).toList(), ); } } // ────────────────────────────────────────── // Stars // ────────────────────────────────────────── class _StarRating extends StatelessWidget { final int rating; final ValueChanged onRate; const _StarRating({required this.rating, required this.onRate}); @override Widget build(BuildContext context) { return Row( children: List.generate(5, (i) { final filled = i < rating; return GestureDetector( onTap: () => onRate(i + 1), child: Padding( padding: const EdgeInsets.only(right: 4), child: Icon( filled ? Icons.star_rounded : Icons.star_outline_rounded, size: 32, color: filled ? const Color(0xFFEF9F27) : Theme.of(context).colorScheme.outlineVariant, ), ), ); }), ); } } // ────────────────────────────────────────── // Badge de unidad (sin exponer chofer) // ────────────────────────────────────────── class _UnitBadge extends ConsumerWidget { const _UnitBadge(); @override Widget build(BuildContext context, WidgetRef ref) { final unitId = ref.watch(activeUnitIdProvider); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(8), border: Border.all( color: Theme.of(context).colorScheme.outlineVariant, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.local_shipping_outlined, size: 16), const SizedBox(width: 8), Text( 'Unidad $unitId', style: const TextStyle(fontSize: 13), ), ], ), ), const SizedBox(height: 6), Row( children: [ Icon( Icons.shield_outlined, size: 13, color: Theme.of(context).colorScheme.onSurfaceVariant, ), const SizedBox(width: 4), Text( 'Solo se registra el número de unidad. El operador no es identificado.', style: TextStyle( fontSize: 11, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ], ); } } // ────────────────────────────────────────── // Error banner // ────────────────────────────────────────── class _ErrorBanner extends StatelessWidget { final String message; const _ErrorBanner({required this.message}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).colorScheme.errorContainer, borderRadius: BorderRadius.circular(8), ), child: Row( children: [ const Icon(Icons.error_outline, size: 16), const SizedBox(width: 8), Expanded(child: Text(message, style: const TextStyle(fontSize: 12))), ], ), ); } } // ────────────────────────────────────────── // Success view // ────────────────────────────────────────── class _SuccessView extends StatelessWidget { final VoidCallback onReset; const _SuccessView({required this.onReset}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Buzón de retroalimentación')), body: Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 64, height: 64, decoration: const BoxDecoration( color: Color(0xFFE1F5EE), shape: BoxShape.circle, ), child: const Icon( Icons.check_circle_outline_rounded, size: 36, color: Color(0xFF1D9E75), ), ), const SizedBox(height: 16), const Text( 'Reporte enviado', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), ), const SizedBox(height: 8), Text( 'Gracias. Tu retroalimentación ayuda a mejorar el servicio. El reporte fue registrado de forma anónima.', textAlign: TextAlign.center, style: TextStyle( fontSize: 14, color: Theme.of(context).colorScheme.onSurfaceVariant, height: 1.5, ), ), const SizedBox(height: 24), OutlinedButton( onPressed: onReset, child: const Text('Enviar otro reporte'), ), ], ), ), ), ); } } // ────────────────────────────────────────── // Helpers // ────────────────────────────────────────── class _SectionLabel extends StatelessWidget { final String text; const _SectionLabel(this.text); @override Widget build(BuildContext context) { return Text( text, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ); } }