import { useState, type FormEvent } from 'react' import { Alert } from '@/components/ui/Alert' import { Button } from '@/components/ui/Button' import { Dialog } from '@/components/ui/Dialog' import { SelectField, TextAreaField, TextField } from '@/components/ui/Field' import { errorMessage } from '@/lib/api' import type { Plant } from '@/lib/plants' import { conflictSeedLot, LOT_UNITS, safeExternalUrl, useCreateSeedLot, useUpdateSeedLot, type LotUnit, type SeedLot, } from '@/lib/seedLots' const unitOptions = LOT_UNITS.map((u) => ({ value: u.value, label: u.label })) /** * Record a purchase, or correct one. Everything except quantity and unit is * optional — the point is to make writing it down cheap enough to bother with. */ export function SeedLotDialog({ plant, lot, onClose }: { plant: Plant; lot?: SeedLot; onClose: () => void }) { const isEdit = !!lot const create = useCreateSeedLot() const update = useUpdateSeedLot() const pending = create.isPending || update.isPending const [vendor, setVendor] = useState(lot?.vendor ?? plant.vendor ?? '') const [sourceUrl, setSourceUrl] = useState(lot?.sourceUrl ?? plant.sourceUrl ?? '') const [quantity, setQuantity] = useState(lot ? String(lot.quantity) : '') const [unit, setUnit] = useState(lot?.unit ?? 'seeds') const [purchasedAt, setPurchasedAt] = useState(lot?.purchasedAt ?? '') const [packedForYear, setPackedForYear] = useState(lot?.packedForYear != null ? String(lot.packedForYear) : '') const [cost, setCost] = useState(lot?.costCents != null ? (lot.costCents / 100).toFixed(2) : '') const [germination, setGermination] = useState(lot?.germinationPct != null ? String(lot.germinationPct) : '') const [sku, setSku] = useState(lot?.sku ?? '') const [lotCode, setLotCode] = useState(lot?.lotCode ?? '') const [notes, setNotes] = useState(lot?.notes ?? '') const [version, setVersion] = useState(lot?.version ?? 0) const [conflict, setConflict] = useState(null) const [error, setError] = useState(null) async function onSubmit(e: FormEvent) { e.preventDefault() setError(null) setConflict(null) const qty = quantity.trim() === '' ? 0 : Number(quantity) if (!Number.isFinite(qty) || qty < 0) return setError('Quantity must be a number, or blank.') if (sourceUrl.trim() && !safeExternalUrl(sourceUrl.trim())) return setError('The source link needs to be a full http:// or https:// address.') let year: number | null = null if (packedForYear.trim()) { const y = Number(packedForYear) if (!Number.isInteger(y) || y < 1900 || y > 2200) return setError('Packed-for should be a four-digit year.') year = y } let costCents: number | null = null if (cost.trim()) { const c = Number(cost) if (!Number.isFinite(c) || c < 0) return setError('Cost must be an amount, or blank.') costCents = Math.round(c * 100) } let germinationPct: number | null = null if (germination.trim()) { const g = Number(germination) if (!Number.isFinite(g) || g < 0 || g > 100) return setError('Germination is a percentage between 0 and 100.') germinationPct = g } const input = { plantId: plant.id, vendor: vendor.trim(), sourceUrl: sourceUrl.trim(), sku: sku.trim(), lotCode: lotCode.trim(), purchasedAt: purchasedAt.trim() === '' ? null : purchasedAt.trim(), packedForYear: year, quantity: qty, unit, costCents, germinationPct, notes: notes.trim(), } try { if (isEdit) await update.mutateAsync({ id: lot.id, version, ...input }) else await create.mutateAsync(input) onClose() } catch (err) { const current = conflictSeedLot(err) if (current) { setVersion(current.version) setVendor(current.vendor) setSourceUrl(current.sourceUrl) setQuantity(String(current.quantity)) setUnit(current.unit) setPurchasedAt(current.purchasedAt ?? '') setPackedForYear(current.packedForYear != null ? String(current.packedForYear) : '') setCost(current.costCents != null ? (current.costCents / 100).toFixed(2) : '') setGermination(current.germinationPct != null ? String(current.germinationPct) : '') setSku(current.sku) setLotCode(current.lotCode) setNotes(current.notes) setConflict('This lot changed elsewhere. The latest values are shown — look them over and save again.') return } setError(errorMessage(err, isEdit ? 'Could not save the lot.' : 'Could not record the lot.')) } } return (
{conflict && {conflict}}
setQuantity(e.target.value)} /> setUnit(e.target.value as LotUnit)} options={unitOptions} /> setVendor(e.target.value)} /> setPackedForYear(e.target.value)} /> setPurchasedAt(e.target.value)} /> setCost(e.target.value)} /> setGermination(e.target.value)} /> setSourceUrl(e.target.value)} /> setSku(e.target.value)} /> setLotCode(e.target.value)} />
setNotes(e.target.value)} /> {error && {error}}
) }