import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import '../../providers/admin_provider.dart'; import '../../providers/auth_provider.dart'; import '../../providers/time_provider.dart'; import '../../models/deviation.dart'; class DeviationListScreen extends ConsumerStatefulWidget { const DeviationListScreen({super.key}); @override ConsumerState createState() => _DeviationListScreenState(); } class _DeviationListScreenState extends ConsumerState { bool _onlyUnacknowledged = true; @override Widget build(BuildContext context) { final deviationsAsync = ref.watch(organizationDeviationsProvider(_onlyUnacknowledged)); return Scaffold( appBar: AppBar( title: const Text('Avvikshåndtering'), actions: [ IconButton( icon: Icon(_onlyUnacknowledged ? Icons.filter_alt : Icons.filter_alt_off), onPressed: () { setState(() { _onlyUnacknowledged = !_onlyUnacknowledged; }); }, tooltip: _onlyUnacknowledged ? 'Vis alle' : 'Vis kun åpne', ), ], ), body: deviationsAsync.when( data: (deviations) { if (deviations.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.check_circle_outline, size: 64, color: Colors.green), const SizedBox(height: 16), Text( _onlyUnacknowledged ? 'Ingen åpne avvik!' : 'Ingen avvik funnet', style: Theme.of(context).textTheme.titleMedium, ), ], ), ); } return ListView.builder( itemCount: deviations.length, itemBuilder: (context, index) { final deviation = deviations[index]; return Card( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: ExpansionTile( leading: Icon( Icons.warning, color: _getSeverityColor(deviation.severity), ), title: Text( deviation.description, style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text( DateFormat('dd.MM.yyyy HH:mm').format(deviation.detectedAt), ), trailing: deviation.acknowledgedAt != null ? const Icon(Icons.check_circle, color: Colors.green) : null, children: [ Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _DetailRow(label: 'Type', value: _getTypeDisplayName(deviation.type)), if (deviation.metadata.actualValue != null) _DetailRow( label: 'Faktisk verdi', value: '${deviation.metadata.actualValue}', ), if (deviation.metadata.limitValue != null) _DetailRow( label: 'Grenseverdi', value: '${deviation.metadata.limitValue}', ), const SizedBox(height: 16), if (deviation.acknowledgedAt == null) FilledButton( onPressed: () => _showAcknowledgeDialog(context, deviation), child: const Text('Kvitter ut avvik'), ) else Text( 'Kvittert ut av ${deviation.acknowledgedBy ?? "ukjent"} den ${DateFormat('dd.MM.yyyy HH:mm').format(deviation.acknowledgedAt!)}', style: const TextStyle(fontStyle: FontStyle.italic, color: Colors.grey), ), ], ), ), ], ), ); }, ); }, loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => Center(child: Text('Feil: $error')), ), ); } Future _showAcknowledgeDialog(BuildContext context, Deviation deviation) async { final commentController = TextEditingController(); final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Kvitter ut avvik'), content: Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Er du sikker på at du vil kvittere ut dette avviket?'), const SizedBox(height: 16), TextField( controller: commentController, decoration: const InputDecoration( labelText: 'Kommentar (valgfritt)', border: OutlineInputBorder(), ), maxLines: 3, ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Avbryt'), ), FilledButton( onPressed: () => Navigator.pop(context, true), child: const Text('Kvitter ut'), ), ], ), ); if (confirmed == true) { try { final user = ref.read(currentUserProvider); if (user == null) return; final timeService = ref.read(timeServiceProvider); await timeService.acknowledgeDeviation( deviationId: deviation.id, userId: user.uid, comment: commentController.text.isNotEmpty ? commentController.text : null, ); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Avvik kvittert ut')), ); // Refresh list ref.invalidate(organizationDeviationsProvider); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Feil: $e')), ); } } } } Color _getSeverityColor(DeviationSeverity severity) { switch (severity) { case DeviationSeverity.warning: return Colors.orange; case DeviationSeverity.violation: return Colors.red; } } String _getTypeDisplayName(DeviationType type) { switch (type) { case DeviationType.dailyMax: return 'Daglig maksgrense'; case DeviationType.weeklyMax: return 'Ukentlig maksgrense'; case DeviationType.dailyRest: return 'Daglig hviletid'; case DeviationType.weeklyRest: return 'Ukentlig hviletid'; case DeviationType.averageExceeded: return 'Gjennomsnittsberegning overskredet'; case DeviationType.nightWork: return 'Nattarbeid'; } } } class _DetailRow extends StatelessWidget { final String label; final String value; const _DetailRow({required this.label, required this.value}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: const TextStyle(color: Colors.grey)), Text(value, style: const TextStyle(fontWeight: FontWeight.bold)), ], ), ); } }