feat: implement update functionality for receipt aliases and add corresponding tests
Test Suite / backend-pr-quick (24.15.0) (push) Has been skipped
Test Suite / quick-import-pr-quick (24.15.0) (push) Has been skipped
Test Suite / backend-full (24.15.0) (push) Failing after 22s
Test Suite / flutter-quality (push) Failing after 4s

This commit is contained in:
Nils-Johan Gynther
2026-05-12 21:25:48 +02:00
parent fb6b371fb7
commit 46b9be4791
10 changed files with 403 additions and 21 deletions
@@ -420,6 +420,19 @@ class AdminRepository {
'isGlobal': isGlobal,
});
Future<void> updateReceiptAlias(
int id, {
String? receiptName,
int? productId,
}) {
final body = <String, dynamic>{
if (receiptName != null) 'receiptName': receiptName,
if (productId != null) 'productId': productId,
};
return _patchVoid(ReceiptAliasApiPaths.update(id), body);
}
Future<void> removeReceiptAlias(int id) =>
_deleteVoid(ReceiptAliasApiPaths.remove(id));
@@ -26,6 +26,7 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
final TextEditingController _aliasController = TextEditingController();
int? _selectedProductId;
int? _editingAliasId;
@override
void initState() {
@@ -79,18 +80,32 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
setState(() => _isSaving = true);
try {
await ref.read(adminRepositoryProvider).upsertReceiptAlias(
receiptName: rawAlias,
productId: productId,
isGlobal: true,
);
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,
);
}
if (!mounted) return;
_aliasController.clear();
setState(() => _selectedProductId = null);
setState(() {
_selectedProductId = null;
_editingAliasId = null;
});
await _load();
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Alias sparad.')),
SnackBar(content: Text(isEditing ? 'Alias uppdaterat.' : 'Alias sparad.')),
);
} catch (e) {
if (!mounted) return;
@@ -102,6 +117,29 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
}
}
void _startEditAlias(ReceiptAlias alias) {
if (!alias.isGlobal) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Privata alias redigeras av respektive användare.')),
);
return;
}
setState(() {
_editingAliasId = alias.id;
_aliasController.text = alias.receiptName;
_selectedProductId = alias.productId;
});
}
void _cancelEditAlias() {
setState(() {
_editingAliasId = null;
_aliasController.clear();
_selectedProductId = null;
});
}
Future<void> _removeAlias(ReceiptAlias alias) async {
final confirmed = await showDialog<bool>(
context: context,
@@ -202,11 +240,23 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
),
],
),
trailing: IconButton(
onPressed: () => _removeAlias(alias),
icon: const Icon(Icons.delete_outline),
tooltip: 'Ta bort alias',
color: Theme.of(context).colorScheme.error,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () => _startEditAlias(alias),
icon: const Icon(Icons.edit_outlined),
tooltip: alias.isGlobal
? 'Redigera alias'
: 'Privata alias redigeras av användaren',
),
IconButton(
onPressed: () => _removeAlias(alias),
icon: const Icon(Icons.delete_outline),
tooltip: 'Ta bort alias',
color: Theme.of(context).colorScheme.error,
),
],
),
),
);
@@ -256,6 +306,7 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
const SizedBox(width: 8),
Expanded(
child: DropdownButtonFormField<int>(
key: ValueKey<int?>(_selectedProductId),
initialValue: _selectedProductId,
decoration: const InputDecoration(
labelText: 'Produkt',
@@ -275,6 +326,13 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
),
),
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
@@ -283,8 +341,8 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
height: 14,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.save_outlined),
label: const Text('Spara'),
: Icon(_editingAliasId != null ? Icons.edit_outlined : Icons.save_outlined),
label: Text(_editingAliasId != null ? 'Uppdatera' : 'Spara'),
),
],
),