import { useMemo, useState } from 'react' import { Alert } from '@/components/ui/Alert' import { Button } from '@/components/ui/Button' import { fieldControlClass } from '@/components/ui/field' import { toast } from '@/components/ui/toast' import { CategoryChips } from '@/components/plants/CategoryChips' import { PlantCard } from '@/components/plants/PlantCard' import { PlantFormModal } from '@/components/plants/PlantFormModal' import { DeletePlantModal } from '@/components/plants/DeletePlantModal' import { SeedLotModal } from '@/components/plants/SeedLotModal' import { DeleteSeedLotModal } from '@/components/plants/DeleteSeedLotModal' import { PlantPicker } from '@/editor/PlantPicker' import { filterPlants, usePlants, type CategoryFilter, type Plant } from '@/lib/plants' import { lotsByPlant, useSeedLots, type SeedLot } from '@/lib/seedLots' import type { UnitPref } from '@/lib/units' import { usePageTitle } from '@/lib/usePageTitle' // Which modal is open, if any. edit/duplicate/delete carry the target plant. type Dialog = | { kind: 'create' } | { kind: 'edit'; plant: Plant } | { kind: 'duplicate'; plant: Plant } | { kind: 'delete'; plant: Plant } | { kind: 'picker' } | { kind: 'addLot'; plant: Plant } | { kind: 'editLot'; plant: Plant; lot: SeedLot } | { kind: 'deleteLot'; lot: SeedLot } | null // There's no per-user unit preference server-side (only per-garden), so the // catalog page keeps its own, persisted locally. const UNIT_KEY = 'pansy:unit-pref' function loadUnit(): UnitPref { try { return localStorage.getItem(UNIT_KEY) === 'imperial' ? 'imperial' : 'metric' } catch { return 'metric' } } export function PlantsPage() { usePageTitle('Plants') const plants = usePlants() const seedLots = useSeedLots() const lots = useMemo(() => lotsByPlant(seedLots.data), [seedLots.data]) const [unit, setUnit] = useState(() => loadUnit()) const [query, setQuery] = useState('') const [category, setCategory] = useState('all') const [dialog, setDialog] = useState(null) const close = () => setDialog(null) function toggleUnit() { setUnit((u) => { const next: UnitPref = u === 'metric' ? 'imperial' : 'metric' try { localStorage.setItem(UNIT_KEY, next) } catch { // Preference is a nicety; ignore storage failures. } return next }) } const all = useMemo(() => plants.data ?? [], [plants.data]) const filtered = useMemo(() => filterPlants(all, query, category), [all, query, category]) return (

Plants

setQuery(e.target.value)} placeholder="Search plants by name…" aria-label="Search plants" className={fieldControlClass} />
{plants.isPending &&

Loading the catalog…

} {plants.isError && Could not load the plant catalog. Please refresh.} {plants.isSuccess && filtered.length === 0 && (

No plants match.

Try a different search or category, or add a custom plant.

)} {filtered.length > 0 && (
{filtered.map((p) => ( setDialog({ kind: 'edit', plant: p })} onDelete={() => setDialog({ kind: 'delete', plant: p })} onDuplicate={() => setDialog({ kind: 'duplicate', plant: p })} onAddLot={() => setDialog({ kind: 'addLot', plant: p })} onEditLot={(lot) => setDialog({ kind: 'editLot', plant: p, lot })} onDeleteLot={(lot) => setDialog({ kind: 'deleteLot', lot })} /> ))}
)}
{dialog?.kind === 'create' && } {dialog?.kind === 'edit' && } {dialog?.kind === 'duplicate' && } {dialog?.kind === 'delete' && } {dialog?.kind === 'addLot' && } {dialog?.kind === 'editLot' && } {dialog?.kind === 'deleteLot' && } {dialog?.kind === 'picker' && ( { toast.info(`Picked ${p.name}`) close() }} /> )}
) }