feat: enhance inventory and pantry features with filtering, sorting, and error handling improvements
This commit is contained in:
@@ -4,6 +4,7 @@ class PantryItem {
|
||||
final String productName;
|
||||
final String? canonicalName;
|
||||
final String? category;
|
||||
final int? categoryId;
|
||||
|
||||
const PantryItem({
|
||||
required this.id,
|
||||
@@ -11,6 +12,7 @@ class PantryItem {
|
||||
required this.productName,
|
||||
this.canonicalName,
|
||||
this.category,
|
||||
this.categoryId,
|
||||
});
|
||||
|
||||
String get displayName {
|
||||
@@ -28,6 +30,7 @@ class PantryItem {
|
||||
productName: (product['name'] ?? '').toString(),
|
||||
canonicalName: product['canonicalName']?.toString(),
|
||||
category: product['category']?.toString(),
|
||||
categoryId: (product['categoryId'] as num?)?.toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,16 @@ class PantryProduct {
|
||||
final String name;
|
||||
final String? canonicalName;
|
||||
final String? category;
|
||||
final int? categoryId;
|
||||
final String? categoryPath;
|
||||
|
||||
const PantryProduct({
|
||||
required this.id,
|
||||
required this.name,
|
||||
this.canonicalName,
|
||||
this.category,
|
||||
this.categoryId,
|
||||
this.categoryPath,
|
||||
});
|
||||
|
||||
String get displayName {
|
||||
@@ -19,11 +23,33 @@ class PantryProduct {
|
||||
}
|
||||
|
||||
factory PantryProduct.fromJson(Map<String, dynamic> json) {
|
||||
final categoryRef = json['categoryRef'];
|
||||
final path = _buildCategoryPath(categoryRef);
|
||||
|
||||
return PantryProduct(
|
||||
id: (json['id'] as num).toInt(),
|
||||
name: (json['name'] ?? '').toString(),
|
||||
canonicalName: json['canonicalName']?.toString(),
|
||||
category: json['category']?.toString(),
|
||||
categoryId: (json['categoryId'] as num?)?.toInt(),
|
||||
categoryPath: path,
|
||||
);
|
||||
}
|
||||
|
||||
static String? _buildCategoryPath(dynamic rawCategoryRef) {
|
||||
if (rawCategoryRef is! Map<String, dynamic>) return null;
|
||||
|
||||
final names = <String>[];
|
||||
dynamic current = rawCategoryRef;
|
||||
while (current is Map<String, dynamic>) {
|
||||
final name = current['name']?.toString().trim();
|
||||
if (name != null && name.isNotEmpty) {
|
||||
names.insert(0, name);
|
||||
}
|
||||
current = current['parent'];
|
||||
}
|
||||
|
||||
if (names.isEmpty) return null;
|
||||
return names.join(' > ');
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import '../../auth/data/auth_providers.dart';
|
||||
import '../../../core/ui/async_state_views.dart';
|
||||
import '../data/pantry_providers.dart';
|
||||
import '../domain/pantry_item.dart';
|
||||
import '../domain/pantry_product.dart';
|
||||
|
||||
class PantryScreen extends ConsumerStatefulWidget {
|
||||
const PantryScreen({super.key});
|
||||
@@ -219,6 +220,19 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
String _resolveCategory(PantryItem item, Map<int, PantryProduct> productById) {
|
||||
final fromTree = productById[item.productId]?.categoryPath;
|
||||
if (fromTree != null && fromTree.trim().isNotEmpty) {
|
||||
return fromTree;
|
||||
}
|
||||
|
||||
if (item.category != null && item.category!.trim().isNotEmpty) {
|
||||
return item.category!;
|
||||
}
|
||||
|
||||
return 'Ovrigt';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pantryAsync = ref.watch(pantryProvider);
|
||||
@@ -241,6 +255,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
|
||||
final pantryItems = pantryAsync.valueOrNull ?? const [];
|
||||
final products = productsAsync.valueOrNull ?? const [];
|
||||
final productById = {for (final product in products) product.id: product};
|
||||
final pantryProductIds = pantryItems.map((e) => e.productId).toSet();
|
||||
final availableProducts = products
|
||||
.where((product) => !pantryProductIds.contains(product.id))
|
||||
@@ -252,9 +267,7 @@ class _PantryScreenState extends ConsumerState<PantryScreen> {
|
||||
|
||||
final grouped = <String, List<PantryItem>>{};
|
||||
for (final item in pantryItems) {
|
||||
final category = (item.category == null || item.category!.isEmpty)
|
||||
? 'Ovrigt'
|
||||
: item.category!;
|
||||
final category = _resolveCategory(item, productById);
|
||||
grouped.putIfAbsent(category, () => []).add(item);
|
||||
}
|
||||
final categories = grouped.keys.toList()
|
||||
|
||||
Reference in New Issue
Block a user