diff --git a/flutter/lib/features/admin/presentation/admin_aliases_panel.dart b/flutter/lib/features/admin/presentation/admin_aliases_panel.dart index c7a7dfad..65ac00df 100644 --- a/flutter/lib/features/admin/presentation/admin_aliases_panel.dart +++ b/flutter/lib/features/admin/presentation/admin_aliases_panel.dart @@ -26,7 +26,6 @@ class _AdminAliasesPanelState extends ConsumerState { final TextEditingController _aliasController = TextEditingController(); int? _selectedProductId; - int? _editingAliasId; @override void initState() { @@ -81,31 +80,21 @@ class _AdminAliasesPanelState extends ConsumerState { setState(() => _isSaving = true); try { final repo = ref.read(adminRepositoryProvider); - final isEditing = _editingAliasId != null; - if (isEditing) { - await repo.updateReceiptAlias( - _editingAliasId!, - receiptName: rawAlias, - productId: productId, - ); - } else { - await repo.upsertReceiptAlias( - receiptName: rawAlias, - productId: productId, - isGlobal: true, - ); - } + await repo.upsertReceiptAlias( + receiptName: rawAlias, + productId: productId, + isGlobal: true, + ); if (!mounted) return; _aliasController.clear(); setState(() { _selectedProductId = null; - _editingAliasId = null; }); await _load(); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(isEditing ? 'Alias uppdaterat.' : 'Alias sparad.')), + const SnackBar(content: Text('Alias sparad.')), ); } catch (e) { if (!mounted) return; @@ -117,27 +106,95 @@ class _AdminAliasesPanelState extends ConsumerState { } } - void _startEditAlias(ReceiptAlias alias) { - if (!alias.isGlobal) { + Future _editAlias(ReceiptAlias alias) async { + String aliasName = alias.receiptName; + int selectedProductId = alias.productId; + final nameController = TextEditingController(text: alias.receiptName); + + final result = await showDialog( + context: context, + builder: (dialogContext) => StatefulBuilder( + builder: (dialogContext, setDialogState) => AlertDialog( + title: const Text('Redigera alias'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: nameController, + decoration: const InputDecoration( + labelText: 'Kvittonamn (alias)', + border: OutlineInputBorder(), + ), + onChanged: (value) => aliasName = value, + ), + const SizedBox(height: 12), + DropdownButtonFormField( + initialValue: selectedProductId, + decoration: const InputDecoration( + labelText: 'Produkt', + border: OutlineInputBorder(), + ), + items: _products + .map( + (product) => DropdownMenuItem( + value: product.id, + child: Text(product.displayName), + ), + ) + .toList(), + onChanged: (value) { + if (value == null) return; + setDialogState(() => selectedProductId = value); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(dialogContext, false), + child: const Text('Avbryt'), + ), + FilledButton( + onPressed: () => Navigator.pop(dialogContext, true), + child: const Text('Spara'), + ), + ], + ), + ), + ); + + nameController.dispose(); + if (result != true || !mounted) return; + + final trimmedAlias = aliasName.trim(); + if (trimmedAlias.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Privata alias redigeras av respektive användare.')), + const SnackBar(content: Text('Aliasnamn kan inte vara tomt.')), ); return; } - setState(() { - _editingAliasId = alias.id; - _aliasController.text = alias.receiptName; - _selectedProductId = alias.productId; - }); - } - - void _cancelEditAlias() { - setState(() { - _editingAliasId = null; - _aliasController.clear(); - _selectedProductId = null; - }); + setState(() => _isSaving = true); + try { + await ref.read(adminRepositoryProvider).updateReceiptAlias( + alias.id, + receiptName: trimmedAlias, + productId: selectedProductId, + ); + if (!mounted) return; + await _load(); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Alias uppdaterat.')), + ); + } catch (e) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + buildCopyableErrorSnackBar(context, mapErrorToUserMessage(e, context)), + ); + } finally { + if (mounted) setState(() => _isSaving = false); + } } Future _removeAlias(ReceiptAlias alias) async { @@ -207,7 +264,7 @@ class _AdminAliasesPanelState extends ConsumerState { Widget buildAliasCard(ReceiptAlias alias) { final product = productById[alias.productId]; - final categoryPath = product?.categoryPath ?? 'okänd'; + final categoryPath = product?.categoryPath?.trim(); return Card( child: ListTile( @@ -215,7 +272,8 @@ class _AdminAliasesPanelState extends ConsumerState { title: Row( children: [ Expanded(child: Text(alias.receiptName, style: const TextStyle(fontWeight: FontWeight.w500))), - buildCategoryPathChip(categoryPath), + if (categoryPath != null && categoryPath.isNotEmpty) + buildCategoryPathChip(categoryPath), ], ), subtitle: Column( @@ -244,11 +302,9 @@ class _AdminAliasesPanelState extends ConsumerState { mainAxisSize: MainAxisSize.min, children: [ IconButton( - onPressed: () => _startEditAlias(alias), + onPressed: _isSaving ? null : () => _editAlias(alias), icon: const Icon(Icons.edit_outlined), - tooltip: alias.isGlobal - ? 'Redigera alias' - : 'Privata alias redigeras av användaren', + tooltip: 'Redigera alias', ), IconButton( onPressed: () => _removeAlias(alias), @@ -326,13 +382,6 @@ class _AdminAliasesPanelState extends ConsumerState { ), ), const SizedBox(width: 8), - if (_editingAliasId != null) ...[ - OutlinedButton( - onPressed: _isSaving ? null : _cancelEditAlias, - child: const Text('Avbryt'), - ), - const SizedBox(width: 8), - ], FilledButton.icon( onPressed: _isSaving ? null : _upsertAlias, icon: _isSaving @@ -341,8 +390,8 @@ class _AdminAliasesPanelState extends ConsumerState { height: 14, child: CircularProgressIndicator(strokeWidth: 2), ) - : Icon(_editingAliasId != null ? Icons.edit_outlined : Icons.save_outlined), - label: Text(_editingAliasId != null ? 'Uppdatera' : 'Spara'), + : const Icon(Icons.save_outlined), + label: const Text('Spara'), ), ], ), diff --git a/flutter/lib/features/admin/presentation/admin_form_shared.dart b/flutter/lib/features/admin/presentation/admin_form_shared.dart index 2df954a2..b3d3eae1 100644 --- a/flutter/lib/features/admin/presentation/admin_form_shared.dart +++ b/flutter/lib/features/admin/presentation/admin_form_shared.dart @@ -76,9 +76,10 @@ List toProductOptions(List products) { } Widget buildCategoryPathChip(String? categoryPath, {double maxWidth = 220}) { - final value = (categoryPath == null || categoryPath.trim().isEmpty) - ? 'okänd' - : categoryPath.trim(); + if (categoryPath == null || categoryPath.trim().isEmpty) { + return const SizedBox.shrink(); + } + final value = categoryPath.trim(); return Tooltip( message: value, child: Chip(