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. */}
setOpen((v) => !v)}
className="block w-full cursor-pointer rounded-[inherit] px-[18px] py-4 text-left"
>
{plant.name}
{sub.join(' · ')}
{builtin && built-in }
{lotText}
{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}
}
)}
Record a lot
Duplicate
{!builtin && (
Edit
)}
{!builtin && (
Delete
)}
)}
)
}
/** 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}
}
Edit
Retire
)
}