import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/api/api_error_mapper.dart'; import '../../../core/ui/async_state_views.dart'; import '../../auth/data/auth_providers.dart'; import '../data/inventory_providers.dart'; import '../domain/inventory_item.dart'; class InventoryScreen extends ConsumerWidget { const InventoryScreen({super.key}); static const _locationOptions = ['', 'Kyl', 'Frys', 'Skafferi']; static const _sortOptions = <({String value, String label})>[ (value: '', label: 'Senast tillagda'), (value: 'nameAsc', label: 'Namn A-O'), (value: 'bestBeforeAsc', label: 'Bast fore stigande'), (value: 'bestBeforeDesc', label: 'Bast fore fallande'), ]; @override Widget build(BuildContext context, WidgetRef ref) { final location = ref.watch(inventoryLocationFilterProvider); final sort = ref.watch(inventorySortFilterProvider); final inventoryAsync = ref.watch(inventoryProvider); return inventoryAsync.when( loading: () => const LoadingStateView(label: 'Laddar inventarie...'), error: (e, _) => ErrorStateView( message: mapErrorToUserMessage(e), onRetry: () => ref.invalidate(inventoryProvider), ), data: (items) { final filterSection = Padding( padding: const EdgeInsets.fromLTRB(12, 12, 12, 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Filter och sortering', style: TextStyle(fontWeight: FontWeight.w600), ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: _locationOptions .map( (option) => ChoiceChip( label: Text(option.isEmpty ? 'Alla' : option), selected: location == option, onSelected: (_) => ref .read(inventoryLocationFilterProvider.notifier) .state = option, ), ) .toList(), ), const SizedBox(height: 8), DropdownButtonFormField( value: sort, isExpanded: true, decoration: const InputDecoration( labelText: 'Sortering', border: OutlineInputBorder(), ), items: _sortOptions .map( (option) => DropdownMenuItem( value: option.value, child: Text(option.label), ), ) .toList(), onChanged: (value) { ref.read(inventorySortFilterProvider.notifier).state = value ?? ''; }, ), ], ), ); if (items.isEmpty) { return Stack( children: [ ListView( padding: const EdgeInsets.only(bottom: 88), children: [ filterSection, const EmptyStateView(title: 'Inventariet ar tomt.'), ], ), Positioned( right: 16, bottom: 16, child: FloatingActionButton.extended( onPressed: () => context.push('/inventory/create'), icon: const Icon(Icons.add), label: const Text('Lägg till'), ), ), ], ); } return Stack( children: [ ListView.separated( padding: const EdgeInsets.only(bottom: 88), itemCount: items.length + 1, separatorBuilder: (_, __) => const Divider(height: 1), itemBuilder: (context, index) { if (index == 0) return filterSection; final item = items[index - 1]; return _InventoryTile(item: item); }, ), Positioned( right: 16, bottom: 16, child: FloatingActionButton.extended( onPressed: () => context.push('/inventory/create'), icon: const Icon(Icons.add), label: const Text('Lägg till'), ), ), ], ); }, ); } } class _InventoryTile extends StatelessWidget { final InventoryItem item; const _InventoryTile({required this.item}); @override Widget build(BuildContext context) { final subtitle = [ '${item.quantity} ${item.unit}', if (item.location != null && item.location!.isNotEmpty) item.location!, if (item.bestBeforeDate != null) 'Bäst före: ${_formatDate(item.bestBeforeDate!)}', ].join(' · '); return ListTile( title: Text(item.productName), subtitle: Text(subtitle), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (item.opened) const Padding( padding: EdgeInsets.only(right: 4), child: Chip( label: Text('Oppnad'), padding: EdgeInsets.zero, visualDensity: VisualDensity.compact, ), ), Tooltip( message: 'Konsumera', child: IconButton( icon: const Icon(Icons.remove_circle_outline), onPressed: () => context.push('/inventory/${item.id}/consume'), ), ), Tooltip( message: 'Redigera', child: IconButton( icon: const Icon(Icons.edit_outlined), onPressed: () => context.push('/inventory/${item.id}/edit'), ), ), _DeleteInventoryButton(item: item), ], ), onTap: () => context.push('/inventory/${item.id}'), ); } String _formatDate(String iso) { try { final dt = DateTime.parse(iso); return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')}'; } catch (_) { return iso; } } } class _DeleteInventoryButton extends ConsumerWidget { final InventoryItem item; const _DeleteInventoryButton({required this.item}); @override Widget build(BuildContext context, WidgetRef ref) { return Tooltip( message: 'Ta bort', child: IconButton( icon: const Icon(Icons.delete_outline, color: Colors.red), onPressed: () async { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Ta bort inventariepost?'), content: Text('Vill du ta bort "${item.productName}"?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('Avbryt'), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), child: const Text('Ta bort'), ), ], ), ); if (confirmed != true) return; try { final token = await ref.read(authStateProvider.future); await ref .read(inventoryRepositoryProvider) .deleteInventoryItem(item.id, token: token); ref.invalidate(inventoryProvider); } catch (error) { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(mapErrorToUserMessage(error))), ); } }, ), ); } }