import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/api/api_error_mapper.dart'; import '../../../core/forms/form_options.dart'; import '../../../core/l10n/l10n.dart'; import '../data/admin_repository.dart'; import '../domain/admin_pantry_item.dart'; import '../domain/user_admin.dart'; class AdminPantryPanel extends ConsumerStatefulWidget { final bool embedded; const AdminPantryPanel({super.key, this.embedded = false}); @override ConsumerState createState() => _AdminPantryPanelState(); } class _AdminPantryPanelState extends ConsumerState { bool _isLoading = true; String? _error; int? _selectedUserId; List _items = []; List _users = []; @override void initState() { super.initState(); _load(); } Future _load() async { setState(() { _isLoading = true; _error = null; }); try { final results = await Future.wait([ ref.read(adminRepositoryProvider).listAdminPantry(userId: _selectedUserId), ref.read(adminRepositoryProvider).listUsers(), ]); if (!mounted) return; setState(() { _items = results[0] as List; _users = results[1] as List; }); } catch (e) { if (!mounted) return; setState(() => _error = mapErrorToUserMessage(e, context)); } finally { if (mounted) setState(() => _isLoading = false); } } Future _moveToInventory(AdminPantryItem item) async { final quantityController = TextEditingController(text: '1'); String selectedUnit = 'st'; String? selectedLocation; String? formError; final payload = await showDialog>( context: context, builder: (ctx) { return StatefulBuilder( builder: (ctx, setDialogState) { return AlertDialog( title: Text(context.l10n.pantryAddToInventoryTitle(item.displayName)), content: SizedBox( width: 380, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: quantityController, keyboardType: const TextInputType.numberWithOptions(decimal: true), decoration: InputDecoration( labelText: context.l10n.inventoryQuantityDisplayLabel, border: const OutlineInputBorder(), ), ), const SizedBox(height: 12), DropdownButtonFormField( initialValue: selectedUnit, isExpanded: true, decoration: InputDecoration( labelText: context.l10n.unitLabel, border: const OutlineInputBorder(), ), items: unitOptions .map((option) => DropdownMenuItem( value: option.value, child: Text(option.label), )) .toList(), onChanged: (value) { if (value == null) return; setDialogState(() => selectedUnit = value); }, ), const SizedBox(height: 12), DropdownButtonFormField( initialValue: selectedLocation, isExpanded: true, decoration: InputDecoration( labelText: context.l10n.locationOptionalLabel, border: const OutlineInputBorder(), ), items: [ DropdownMenuItem( value: null, child: Text(context.l10n.pantryNoLocation), ), ...inventoryLocationOptions.map( (location) => DropdownMenuItem( value: location, child: Text(location), ), ), ], onChanged: (value) { setDialogState(() => selectedLocation = value); }, ), if (formError != null) ...[ const SizedBox(height: 8), Text( formError!, style: TextStyle(color: Theme.of(ctx).colorScheme.error), ), ], ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text(context.l10n.cancelAction), ), FilledButton( onPressed: () { final quantity = double.tryParse( quantityController.text.trim().replaceAll(',', '.'), ); if (quantity == null || quantity <= 0) { setDialogState(() { formError = context.l10n.pantryInvalidQuantity; }); return; } Navigator.pop(ctx, { 'quantity': quantity, 'unit': selectedUnit, 'location': selectedLocation, }); }, child: Text(context.l10n.addAction), ), ], ); }, ); }, ); quantityController.dispose(); if (payload == null) return; try { await ref.read(adminRepositoryProvider).moveAdminPantryToInventory( item.id, { 'productId': item.productId, 'quantity': payload['quantity'] as double, 'unit': payload['unit'] as String, if (payload['location'] != null) 'location': payload['location'] as String, }, ); if (!mounted) return; await _load(); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Flyttade "${item.displayName}" till inventarie.')), ); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( buildCopyableErrorSnackBar(context, mapErrorToUserMessage(e, context)), ); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); if (_isLoading) return const Center(child: CircularProgressIndicator()); if (_error != null) { return buildCopyableErrorPanel( context: context, message: _error!, onRetry: _load, title: 'Kunde inte läsa admin pantry', ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Baslager', style: theme.textTheme.titleMedium), const SizedBox(height: 8), Text( 'Här ser du användarnas pantryposter. Flytta dem tillbaka till inventarie eller ta bort poster som inte längre ska ligga kvar.', style: theme.textTheme.bodyMedium, ), const SizedBox(height: 8), const Wrap( spacing: 8, runSpacing: 8, children: [ Chip(label: Text('User-scope')), Chip(label: Text('Flytta till inventarie')), Chip(label: Text('Ta bort')), ], ), ], ), ), ), const SizedBox(height: 12), Card( child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Expanded( child: DropdownButtonFormField( initialValue: _selectedUserId, decoration: const InputDecoration(labelText: 'Filtrera användare'), items: [ const DropdownMenuItem( value: null, child: Text('Alla användare'), ), ..._users.map( (user) => DropdownMenuItem( value: user.id, child: Text('${user.displayName} (${user.username})'), ), ), ], onChanged: (value) { setState(() => _selectedUserId = value); _load(); }, ), ), const SizedBox(width: 8), OutlinedButton.icon( onPressed: _load, icon: const Icon(Icons.refresh), label: const Text('Uppdatera'), ), ], ), ), ), const SizedBox(height: 12), Expanded( child: _items.isEmpty ? Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Baslager', style: theme.textTheme.titleMedium), const SizedBox(height: 8), Text( 'Här ser du användarnas pantryposter. Flytta dem tillbaka till inventarie eller ta bort poster som inte längre ska ligga kvar.', style: theme.textTheme.bodyMedium, ), const SizedBox(height: 8), Text( 'Inga pantry-poster hittades.', style: theme.textTheme.bodyMedium, ), ], ), ), ) : ListView.separated( itemCount: _items.length, separatorBuilder: (_, __) => const Divider(height: 1), itemBuilder: (context, index) { final item = _items[index]; return ListTile( title: Text(item.displayName), subtitle: Text( '${item.username} (${item.userEmail})${item.location == null || item.location!.trim().isEmpty ? '' : ' · ${item.location}'}', ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( tooltip: 'Flytta till inventarie', icon: const Icon(Icons.inventory_2_outlined), onPressed: () => _moveToInventory(item), ), IconButton( tooltip: 'Ta bort', icon: const Icon(Icons.delete_outline, color: Colors.red), onPressed: () async { try { await ref.read(adminRepositoryProvider).removeAdminPantryItem(item.id); if (!mounted) return; await _load(); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( buildCopyableErrorSnackBar(context, mapErrorToUserMessage(e, context)), ); } }, ), ], ), ); }, ), ), ], ); } }