v0.6.2 — Pantry: searchable category/subcategory comboboxes
This commit is contained in:
@@ -5,6 +5,8 @@ import { Plus, Pencil, Sparkles, X } 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 { Combobox } from "@/components/ui/combobox";
|
||||
import { CATEGORY_OPTIONS, getSubcategoryOptions } from "@/lib/pantry/categories";
|
||||
import type { PantryItem, LocationOption, PlantOption } from "./pantry-client";
|
||||
|
||||
const SOURCES = [
|
||||
@@ -19,15 +21,6 @@ const SOURCES = [
|
||||
const COMMON_UNITS = ["lbs", "oz", "g", "kg", "bags", "jars", "quart jars", "pint jars", "gallon bags", "quart bags", "containers", "cans", "bottles", "bunches", "loaves", "portions", "each"];
|
||||
const PRICE_UNITS = ["package", "lb", "oz", "kg", "each", "dozen", "bunch"];
|
||||
|
||||
const DEFAULT_CATEGORIES = ["Meat", "Produce", "Dairy & Eggs", "Baked Goods", "Soups & Broths", "Sauces & Condiments", "Grains & Legumes", "Herbs & Spices", "Prepared Meals", "Fruit", "Seafood", "Other"];
|
||||
const DEFAULT_SUBCATEGORIES: Record<string, string[]> = {
|
||||
"Meat": ["Beef", "Poultry", "Pork", "Lamb", "Game", "Sausage", "Other"],
|
||||
"Produce": ["Berries", "Vegetables", "Leafy Greens", "Root Vegetables", "Corn", "Peppers", "Tomatoes", "Other"],
|
||||
"Dairy & Eggs": ["Butter", "Cheese", "Milk", "Cream", "Eggs", "Other"],
|
||||
"Baked Goods": ["Bread", "Muffins", "Cookies", "Cake", "Pie", "Crackers", "Other"],
|
||||
"Fruit": ["Berries", "Stone Fruit", "Apples & Pears", "Citrus", "Tropical", "Other"],
|
||||
"Seafood": ["Fish", "Shrimp", "Shellfish", "Other"],
|
||||
};
|
||||
|
||||
type Suggestion = {
|
||||
name: string;
|
||||
@@ -107,7 +100,7 @@ export function PantryItemDialog({ item, locations, plants, onSuccess }: Props)
|
||||
setForm(f => ({ ...f, [key]: val }));
|
||||
}
|
||||
|
||||
// Load catalog on open (for category/subcategory autocomplete)
|
||||
// Load catalog on open (for name autocomplete suggestions)
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
fetch("/api/pantry/catalog")
|
||||
@@ -155,13 +148,7 @@ export function PantryItemDialog({ item, locations, plants, onSuccess }: Props)
|
||||
set("name", s.name);
|
||||
}
|
||||
|
||||
// Subcategory options: merge defaults + previously used
|
||||
const allCategories = Array.from(new Set([...DEFAULT_CATEGORIES, ...(catalog?.categories ?? [])])).sort();
|
||||
const subcatDefaults = DEFAULT_SUBCATEGORIES[form.pantryCategory] ?? [];
|
||||
const subcatFromCatalog = (catalog?.subcategories ?? [])
|
||||
.filter(s => s.category === form.pantryCategory)
|
||||
.map(s => s.subcategory);
|
||||
const allSubcategories = Array.from(new Set([...subcatDefaults, ...subcatFromCatalog])).sort();
|
||||
const subcategoryOptions = getSubcategoryOptions(form.pantryCategory);
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
@@ -274,30 +261,23 @@ export function PantryItemDialog({ item, locations, plants, onSuccess }: Props)
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<Label>Category</Label>
|
||||
<input
|
||||
className={inputCls}
|
||||
list="cat-list"
|
||||
<Combobox
|
||||
options={CATEGORY_OPTIONS}
|
||||
value={form.pantryCategory}
|
||||
onChange={e => { set("pantryCategory", e.target.value); set("pantrySubcategory", ""); }}
|
||||
placeholder="e.g. Meat"
|
||||
onChange={v => { set("pantryCategory", v); set("pantrySubcategory", ""); }}
|
||||
placeholder="Select category…"
|
||||
/>
|
||||
<datalist id="cat-list">
|
||||
{allCategories.map(c => <option key={c} value={c} />)}
|
||||
</datalist>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label>Subcategory</Label>
|
||||
<input
|
||||
className={inputCls}
|
||||
list="subcat-list"
|
||||
<Combobox
|
||||
options={subcategoryOptions}
|
||||
value={form.pantrySubcategory}
|
||||
onChange={e => set("pantrySubcategory", e.target.value)}
|
||||
placeholder="e.g. Beef"
|
||||
onChange={v => set("pantrySubcategory", v)}
|
||||
placeholder="Select subcategory…"
|
||||
disabled={!form.pantryCategory}
|
||||
emptyText="No subcategories"
|
||||
/>
|
||||
<datalist id="subcat-list">
|
||||
{allSubcategories.map(c => <option key={c} value={c} />)}
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user