import { useState } from 'react' import { Button } from '@/components/ui/Button' import { Icon } from '@/components/ui/Icon' import { Tag } from '@/components/ui/Tag' import { cn } from '@/lib/cn' import { CATEGORY_LABELS, isBuiltin, type Plant } from '@/lib/plants' import { formatCost, formatQuantity, lotState, safeExternalUrl, type SeedLot } from '@/lib/seedLots' import { formatSpacing, type UnitPref } from '@/lib/units' import { Monogram } from './Monogram' /** * One catalog plant as a card: monogram, name, "Category · spacing · days", a * built-in tag for seeded plants, and a seed-lot summary. Clicking expands it * (accent border) to the lot cards — vendor, packed-for year, what's left — and * the plant's own actions. Built-ins are read-only: duplicate to customize. */ export function PlantCard({ plant, letters, unit, lots, onEdit, onDelete, onDuplicate, onAddLot, onEditLot, onDeleteLot, }: { plant: Plant letters: string unit: UnitPref lots: SeedLot[] onEdit: () => void onDelete: () => void onDuplicate: () => void onAddLot: () => void onEditLot: (lot: SeedLot) => void onDeleteLot: (lot: SeedLot) => void }) { const builtin = isBuiltin(plant) const [open, setOpen] = useState(false) const sub = [CATEGORY_LABELS[plant.category], `${formatSpacing(plant.spacingCm, unit)} spacing`] if (plant.daysToMaturity != null) sub.push(`${plant.daysToMaturity} days`) const lotText = lots.length === 0 ? `No seed lots · click to ${open ? 'close' : 'expand'}` : `${lots.length} seed ${lots.length === 1 ? 'lot' : 'lots'} · click to ${open ? 'close' : 'see'}` const source = safeExternalUrl(plant.sourceUrl) return (
{/* The whole face is the toggle; the expanded area below has its own controls. */} {open && (
{lots.map((lot) => ( onEditLot(lot)} onDelete={() => onDeleteLot(lot)} /> ))} {lots.length === 0 && (
No seed lots yet — scan a packet, or record one by hand.
)} {(plant.vendor || source || plant.notes) && (
{plant.vendor && {plant.vendor}} {plant.vendor && source && · } {source && ( source )} {plant.notes &&

{plant.notes}

}
)}
{!builtin && ( )} {!builtin && ( )}
)}
) } /** What's left of a lot, said plainly: "50 cloves · 14 left" — or how far over * it was planted, which is a real situation worth showing rather than clamping. */ export function describeLot(lot: SeedLot): string { const parts = [`${formatQuantity(lot.quantity)} ${lot.unit}`] const state = lotState(lot) if (state === 'over') parts.push(`${formatQuantity(-lot.remaining)} over what was bought`) else if (state === 'empty') parts.push('none left') else if (state !== 'unknown') parts.push(`${formatQuantity(lot.remaining)} left`) if (lot.germinationPct != null) parts.push(`${lot.germinationPct}% germination`) const cost = formatCost(lot.costCents) if (cost) parts.push(cost) return parts.join(' · ') } function LotCard({ lot, onEdit, onDelete }: { lot: SeedLot; onEdit: () => void; onDelete: () => void }) { const state = lotState(lot) return (
{lot.vendor || 'Unnamed lot'} {state === 'low' && low} {state === 'empty' && empty} {state === 'over' && over-planted} {lot.packedForYear != null ? `packed for ${lot.packedForYear}` : lot.purchasedAt ? `bought ${lot.purchasedAt}` : ''}
{describeLot(lot)}
{lot.notes &&
{lot.notes}
}
) }