feat: pantry drag-to-recategorize, always-show categories, auto-categorize; fix category label + merge quantity mismatch (v0.84.0)

Pantry items can now be dragged between category sections (dnd-kit, cross-category drop only — no sortOrder column to persist within-category reorder). All 9 categories always render as sections, even empty ones, instead of only ones with items. Added an "Auto-categorize" action mirroring the shopping list's guessAisle heuristic.

Fixed: the edit dialog's category dropdown displayed the raw stored slug/"__other__" instead of its translated label (SelectValue needs a value->label render function, same pattern shopping-list-view.tsx already used elsewhere). Fixed: merge-duplicates now merges by ingredient identity alone, not identity+unit — two rows merge even with mismatched, missing, or different-unit quantities, only summing when safe to do so.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-24 15:51:05 +02:00
parent 93936eae10
commit ebe3216c04
11 changed files with 218 additions and 69 deletions
@@ -35,6 +35,10 @@ export type PantryItem = {
const OTHER_VALUE = "__other__";
function categoryLabel(value: string, tShopping: (key: string) => string): string {
return value === OTHER_VALUE ? tShopping("aisleOther") : tShopping(`categories.${value}`);
}
export function PantryItemDialog({
item,
open,
@@ -115,7 +119,7 @@ export function PantryItemDialog({
<Label>{t("categoryLabel")}</Label>
<Select value={aisle} onValueChange={(v) => setAisle(v ?? OTHER_VALUE)}>
<SelectTrigger>
<SelectValue />
<SelectValue>{(v: string) => categoryLabel(v, tShopping)}</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem value={OTHER_VALUE}>{tShopping("aisleOther")}</SelectItem>