v0.19.0 — Pantry: tag what you used items for

Quick-pick chips (Family dinner, Dinner party, Taking on a trip, Meal
prep, Gave it away) in the Use dialog, alongside the existing freeform
notes field — picking one fills the note, no schema change needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bonna Moon
2026-06-29 17:55:13 -05:00
parent c449b0c2ae
commit 61dc8acacf
3 changed files with 52 additions and 6 deletions

View File

@@ -1,18 +1,33 @@
"use client";
import { useState } from "react";
import { useRef, useState } from "react";
import { Minus } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import type { PantryItem } from "./pantry-client";
const QUICK_REASONS = ["Family dinner", "Dinner party", "Taking on a trip", "Meal prep", "Gave it away"];
export function UseItemDialog({ item, onSuccess }: { item: PantryItem; onSuccess: () => void }) {
const [open, setOpen] = useState(false);
const [amount, setAmount] = useState("1");
const [notes, setNotes] = useState("");
const [saving, setSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
const [selectedReason, setSelectedReason] = useState<string | null>(null);
const notesRef = useRef<HTMLInputElement>(null);
function pickReason(reason: string) {
if (selectedReason === reason) {
setSelectedReason(null);
setNotes("");
} else {
setSelectedReason(reason);
setNotes(reason);
}
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
@@ -28,6 +43,7 @@ export function UseItemDialog({ item, onSuccess }: { item: PantryItem; onSuccess
setOpen(false);
setAmount("1");
setNotes("");
setSelectedReason(null);
onSuccess();
} catch (err) {
setError(String(err).replace("Error: ", ""));
@@ -44,7 +60,7 @@ export function UseItemDialog({ item, onSuccess }: { item: PantryItem; onSuccess
<Minus className="h-3.5 w-3.5" />
</Button>
<Dialog open={open} onOpenChange={setOpen}>
<Dialog open={open} onOpenChange={o => { setOpen(o); if (!o) { setSelectedReason(null); setNotes(""); } }}>
<DialogContent className="max-w-sm">
<DialogHeader>
<DialogTitle>Use {item.name}</DialogTitle>
@@ -66,9 +82,32 @@ export function UseItemDialog({ item, onSuccess }: { item: PantryItem; onSuccess
required
/>
</div>
<div className="space-y-1">
<Label>Notes (optional)</Label>
<input className={inputCls} value={notes} onChange={e => setNotes(e.target.value)} placeholder="e.g. used in chicken soup" />
<div className="space-y-1.5">
<Label>What's it for? (optional)</Label>
<div className="flex flex-wrap gap-1.5">
{QUICK_REASONS.map(reason => (
<button
key={reason}
type="button"
onClick={() => pickReason(reason)}
className={cn(
"rounded-full border px-3 py-1 text-xs",
selectedReason === reason
? "bg-primary text-primary-foreground border-primary"
: "bg-background hover:bg-accent"
)}
>
{reason}
</button>
))}
</div>
<input
ref={notesRef}
className={inputCls}
value={notes}
onChange={e => { setNotes(e.target.value); setSelectedReason(null); }}
placeholder="e.g. used in chicken soup, or pick a tag above"
/>
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
<DialogFooter>

View File

@@ -8,6 +8,13 @@ export type ChangelogEntry = {
};
export const CHANGELOG: ChangelogEntry[] = [
{
version: "0.19.0",
date: "2026-06-29",
changes: [
"Pantry: when you use something, you can now tag why with one tap — Family dinner, Dinner party, Taking on a trip, Meal prep, Gave it away — or type your own note instead.",
],
},
{
version: "0.18.1",
date: "2026-06-29",

View File

@@ -1,2 +1,2 @@
// Bump on every user-visible release. Changelog entries live in `src/lib/changelog.ts`.
export const APP_VERSION = "0.18.1";
export const APP_VERSION = "0.19.0";