import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import '../../../events/domain/event.dart'; import '../../application/admin_events_notifier.dart'; class AdminEventsScreen extends ConsumerWidget { const AdminEventsScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final eventsAsync = ref.watch(adminEventsStreamProvider); final theme = Theme.of(context); return Scaffold( body: eventsAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (err, _) => _ErrorState( message: '$err', onRetry: () => ref.invalidate(adminEventsStreamProvider), ), data: (events) { if (events.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.event_busy_outlined, size: 64, color: theme.colorScheme.onSurfaceVariant, ), const SizedBox(height: 16), Text( 'No events yet', style: theme.textTheme.titleMedium, ), const SizedBox(height: 8), Text( 'Tap the + button to create your first event.', style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), ), ); } return ListView.builder( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), itemCount: events.length, itemBuilder: (context, index) => _EventRow(event: events[index]), ); }, ), floatingActionButton: FloatingActionButton.extended( onPressed: () => context.go('/admin/events/new'), icon: const Icon(Icons.add), label: const Text('NEW EVENT'), ), ); } } class _EventRow extends ConsumerWidget { const _EventRow({required this.event}); final Event event; Future _confirmDelete(BuildContext context, WidgetRef ref) async { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Delete event?'), content: Text( '"${event.title}" will be permanently removed. This cannot be undone.', ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: const Text('Cancel'), ), FilledButton.tonal( onPressed: () => Navigator.of(ctx).pop(true), child: const Text('Delete'), ), ], ), ); if (confirmed != true) return; if (!context.mounted) return; try { await ref.read(adminEventsNotifierProvider.notifier).delete(event.id); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Deleted "${event.title}"')), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Delete failed: $e')), ); } } } @override Widget build(BuildContext context, WidgetRef ref) { final theme = Theme.of(context); final dateLabel = DateFormat.yMMMd().add_jm().format(event.date); return Card( margin: const EdgeInsets.symmetric(vertical: 6), child: Padding( padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( event.title, style: theme.textTheme.titleMedium, maxLines: 2, overflow: TextOverflow.ellipsis, ), ), if (event.isCancelled) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: theme.colorScheme.errorContainer, borderRadius: BorderRadius.circular(2), ), child: Text( 'CANCELLED', style: theme.textTheme.labelSmall?.copyWith( color: theme.colorScheme.onErrorContainer, fontWeight: FontWeight.w700, ), ), ), ], ), const SizedBox(height: 8), Row( children: [ Icon( Icons.schedule, size: 14, color: theme.colorScheme.onSurfaceVariant, ), const SizedBox(width: 4), Expanded( child: Text( dateLabel, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ), Text( '${event.teamsRegistered}/${event.maxTeams} teams', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), const SizedBox(height: 4), Row( children: [ Icon( Icons.location_on_outlined, size: 14, color: theme.colorScheme.onSurfaceVariant, ), const SizedBox(width: 4), Expanded( child: Text( event.location, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton.icon( onPressed: () => _confirmDelete(context, ref), icon: const Icon(Icons.delete_outline, size: 18), label: const Text('Delete'), ), const SizedBox(width: 8), OutlinedButton.icon( onPressed: () => context.go('/admin/events/${event.id}/edit'), icon: const Icon(Icons.edit_outlined, size: 18), label: const Text('Edit'), ), ], ), ], ), ), ); } } class _ErrorState extends StatelessWidget { const _ErrorState({required this.message, required this.onRetry}); final String message; final VoidCallback onRetry; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.error_outline, size: 48, color: theme.colorScheme.error, ), const SizedBox(height: 12), Text( 'Could not load events', style: theme.textTheme.titleMedium, ), const SizedBox(height: 6), Text( message, textAlign: TextAlign.center, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 16), FilledButton.tonalIcon( onPressed: onRetry, icon: const Icon(Icons.refresh), label: const Text('Try again'), ), ], ), ), ); } }