(null);
@@ -46,12 +48,13 @@ export function UseItemDialog({ item, onSuccess }: { item: PantryItem; onSuccess
const res = await fetch(`/api/v1/pantry/${item.id}/use`, {
method: "POST",
headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ amount: parseFloat(amount), notes: notes.trim() || null }),
+ body: JSON.stringify({ amount: parseFloat(amount), notes: notes.trim() || null, reason: disposition }),
});
if (!res.ok) throw new Error((await res.json()).error ?? "Failed");
setOpen(false);
setAmount("1");
setNotes("");
+ setDisposition("consumed");
setSelectedReason(null);
onSuccess();
} catch (err) {
@@ -78,6 +81,26 @@ export function UseItemDialog({ item, onSuccess }: { item: PantryItem; onSuccess
Currently: {item.quantity} {item.unit ?? ""}
+
+
Reason
+
+ {PANTRY_USE_REASONS.map(r => (
+ setDisposition(r.value)}
+ className={cn(
+ "rounded-full border px-3 py-1 text-xs transition-colors",
+ disposition === r.value
+ ? "bg-primary text-primary-foreground border-primary"
+ : "bg-background hover:bg-accent"
+ )}
+ >
+ {r.label}
+
+ ))}
+
+
How much are you using? ({item.unit ?? "units"})
;
diff --git a/src/lib/changelog.ts b/src/lib/changelog.ts
index 07bc880..4a526c7 100644
--- a/src/lib/changelog.ts
+++ b/src/lib/changelog.ts
@@ -8,6 +8,16 @@ export type ChangelogEntry = {
};
export const CHANGELOG: ChangelogEntry[] = [
+ {
+ version: "0.29.0",
+ date: "2026-07-12",
+ changes: [
+ "New Ramble page — a sticky-note board for dumping stray thoughts and ideas that aren't tasks yet. Pin the important ones, archive the ones you're done with.",
+ "Dark mode is back: a sun/moon button in the top bar flips the whole app between light and dark.",
+ "When you pull something from the pantry you can now say why — Immediate use, Preserved, Gave away, or Waste — so we can actually see what's getting eaten vs. thrown out.",
+ "Cleaned up the Suggestions page so it's readable and photo thumbnails show up.",
+ ],
+ },
{
version: "0.28.1",
date: "2026-07-10",
diff --git a/src/lib/pantry/core.ts b/src/lib/pantry/core.ts
index f00549f..47c97d2 100644
--- a/src/lib/pantry/core.ts
+++ b/src/lib/pantry/core.ts
@@ -2,6 +2,23 @@
// planning. No DB access; the service layer (src/lib/services/pantry.ts)
// applies these against Prisma.
+// Disposition for a pantry pull — WHY it left inventory, kept structured so
+// waste vs. use is queryable (don't fold this into freeform notes). Stored as
+// the slug string on ItemLog.reason; null for old rows and API pulls that omit it.
+export const PANTRY_USE_REASONS = [
+ { value: "consumed", label: "Immediate use" },
+ { value: "preserved", label: "Preserved / stored" },
+ { value: "gifted", label: "Gave away" },
+ { value: "waste", label: "Waste / spoiled" },
+] as const;
+
+export type PantryUseReason = (typeof PANTRY_USE_REASONS)[number]["value"];
+
+export const PANTRY_USE_REASON_VALUES = PANTRY_USE_REASONS.map(r => r.value) as [
+ PantryUseReason,
+ ...PantryUseReason[],
+];
+
/** Trim, drop empties, and dedupe a raw tag list (first occurrence wins). */
export function normalizeTags(tags: string[]): string[] {
return Array.from(new Set(tags.map(t => t.trim()).filter(Boolean)));
diff --git a/src/lib/services/pantry.ts b/src/lib/services/pantry.ts
index 10a4b3e..36afc0b 100644
--- a/src/lib/services/pantry.ts
+++ b/src/lib/services/pantry.ts
@@ -166,6 +166,7 @@ export async function usePantryItem(
const result = await bulkUsePantry(ctx, {
pulls: [{ id, amount: input.amount }],
notes: input.notes ?? null,
+ reason: input.reason ?? null,
});
if (result.skipped.length) throw new ApiError(404, "Pantry item not found");
return { remaining: result.results[0].remaining };
@@ -183,6 +184,7 @@ export async function bulkUsePantry(
): Promise {
const ids = input.pulls.map(p => p.id);
const notes = input.notes?.trim() || null;
+ const reason = input.reason ?? null;
return db.$transaction(async tx => {
const items = await tx.item.findMany({
@@ -203,6 +205,7 @@ export async function bulkUsePantry(
type: "USED",
amount: u.amount,
notes,
+ reason,
actorId: ctx.userId,
},
});
@@ -216,6 +219,7 @@ export async function bulkUsePantry(
pulls: plan.updates.map(u => ({ id: u.id, name: u.name, amount: u.amount })),
skipped: plan.skipped,
notes,
+ reason,
via: ctx.via,
},
},
diff --git a/src/lib/version.ts b/src/lib/version.ts
index 8e06f28..4e02442 100644
--- a/src/lib/version.ts
+++ b/src/lib/version.ts
@@ -1,2 +1,2 @@
// Bump on every user-visible release. Changelog entries live in `src/lib/changelog.ts`.
-export const APP_VERSION = "0.28.1";
+export const APP_VERSION = "0.29.0";