feat: Add functionality to move inventory items to pantry and enhance pantry management
Test Suite / test (24.15.0) (push) Has been cancelled

- Implemented moveInventoryItemToPantry method in InventoryRepository to facilitate moving items from inventory to pantry.
- Enhanced InventoryScreen with a new header section providing context about the inventory.
- Added a button in SwipeableInventoryTile to move items to pantry with appropriate error handling.
- Introduced movePantryItemToInventory method in PantryRepository to support moving items back to inventory.
- Refactored PantryScreen to rename _addToInventory to _moveToInventory for clarity and updated UI to reflect changes.
- Added AdminPantryItem model to represent pantry items in the admin panel.
- Created AdminPantryPanel for managing pantry items, including moving items to inventory and listing users.
- Developed AdminPrivateProductsPanel for managing private products, allowing promotion to global products.
This commit is contained in:
Nils-Johan Gynther
2026-05-11 09:06:30 +02:00
parent edf9c74e75
commit 84ccabe2fe
27 changed files with 1851 additions and 376 deletions
@@ -95,6 +95,36 @@ class InventoryScreen extends ConsumerWidget {
),
);
final headerSection = Padding(
padding: const EdgeInsets.fromLTRB(12, 12, 12, 4),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(context.l10n.profileInventoryTab, style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
Text(
'Din personliga inventarie. Här ser du sådant du faktiskt äger, kan sortera på plats och bäst före, och flytta vidare till recept eller baslager.',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 8),
const Wrap(
spacing: 8,
runSpacing: 8,
children: [
Chip(label: Text('User-scope')),
Chip(label: Text('Bäst före')),
Chip(label: Text('Swipa för +/-')),
],
),
],
),
),
),
);
if (visibleItems.isEmpty) {
return Stack(
children: [
@@ -102,6 +132,7 @@ class InventoryScreen extends ConsumerWidget {
key: const PageStorageKey<String>('inventory-empty-list'),
padding: const EdgeInsets.only(bottom: 88),
children: [
headerSection,
filterSection,
EmptyStateView(title: context.l10n.inventoryEmpty),
],
@@ -124,11 +155,12 @@ class InventoryScreen extends ConsumerWidget {
ListView.separated(
key: const PageStorageKey<String>('inventory-main-list'),
padding: const EdgeInsets.only(bottom: 88),
itemCount: visibleItems.length + 1,
itemCount: visibleItems.length + 2,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (context, index) {
if (index == 0) return filterSection;
final item = visibleItems[index - 1];
if (index == 1) return headerSection;
final item = visibleItems[index - 2];
return SwipeableInventoryTile(item: item);
},
),
@@ -328,6 +328,26 @@ class _TrailingActions extends ConsumerWidget {
onPressed: () => context.push('/inventory/${item.id}/edit'),
),
),
Tooltip(
message: 'Flytta till baslager',
child: IconButton(
icon: const Icon(Icons.storefront_outlined),
onPressed: () async {
try {
final token = await ref.read(authStateProvider.future);
await ref.read(inventoryRepositoryProvider).moveInventoryItemToPantry(
item.id,
token: token,
);
ref.invalidate(inventoryProvider);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
buildCopyableErrorSnackBar(context, mapErrorToUserMessage(e, context)),
);
}
},
),
),
_DeleteButton(item: item),
],
);