refactor: streamline alias editing and improve category path handling in admin panel
This commit is contained in:
@@ -26,7 +26,6 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
|
||||
|
||||
final TextEditingController _aliasController = TextEditingController();
|
||||
int? _selectedProductId;
|
||||
int? _editingAliasId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -81,31 +80,21 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
|
||||
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<AdminAliasesPanel> {
|
||||
}
|
||||
}
|
||||
|
||||
void _startEditAlias(ReceiptAlias alias) {
|
||||
if (!alias.isGlobal) {
|
||||
Future<void> _editAlias(ReceiptAlias alias) async {
|
||||
String aliasName = alias.receiptName;
|
||||
int selectedProductId = alias.productId;
|
||||
final nameController = TextEditingController(text: alias.receiptName);
|
||||
|
||||
final result = await showDialog<bool>(
|
||||
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<int>(
|
||||
initialValue: selectedProductId,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Produkt',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
items: _products
|
||||
.map(
|
||||
(product) => DropdownMenuItem<int>(
|
||||
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<void> _removeAlias(ReceiptAlias alias) async {
|
||||
@@ -207,7 +264,7 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
|
||||
|
||||
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<AdminAliasesPanel> {
|
||||
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<AdminAliasesPanel> {
|
||||
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<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
|
||||
@@ -341,8 +390,8 @@ class _AdminAliasesPanelState extends ConsumerState<AdminAliasesPanel> {
|
||||
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'),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -76,9 +76,10 @@ List<ProductOption> toProductOptions(List<AdminProduct> 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(
|
||||
|
||||
Reference in New Issue
Block a user