"use client"; import { useState, useTransition, useRef } from "react"; import { useRouter } from "next/navigation"; import { createPlant, updatePlant } from "../server/actions"; import { SpeciesSearch } from "./species-search"; import type { PlantDetailDto, ContainerDto } from "../server/queries"; import type { SpeciesSuggestion } from "../server/species-lookup"; const CATEGORIES = [ { value: "vegetable", label: "Vegetable" }, { value: "fruit", label: "Fruit" }, { value: "herb", label: "Herb" }, { value: "flower", label: "Flower" }, { value: "succulent", label: "Succulent" }, { value: "cactus", label: "Cactus" }, { value: "tropical", label: "Tropical" }, { value: "tree", label: "Tree" }, { value: "shrub", label: "Shrub" }, { value: "other", label: "Other" }, ]; const HEALTH_STATUSES = [ { value: "healthy", label: "Healthy" }, { value: "needs-attention", label: "Needs attention" }, { value: "sick", label: "Sick" }, { value: "dormant", label: "Dormant" }, ]; const GROWTH_STAGES = [ { value: "", label: "Unknown" }, { value: "seedling", label: "Seedling" }, { value: "sprout", label: "Sprout" }, { value: "vegetative", label: "Vegetative" }, { value: "budding", label: "Budding" }, { value: "flowering", label: "Flowering" }, { value: "ripening", label: "Ripening" }, { value: "dormant", label: "Dormant" }, ]; type Props = { existingPlant?: PlantDetailDto; defaultContainerId?: string | null; containers: ContainerDto[]; }; export function PlantForm({ existingPlant, defaultContainerId, containers }: Props) { const router = useRouter(); const [error, setError] = useState(null); const [isPending, startTransition] = useTransition(); const [images, setImages] = useState(existingPlant?.images ?? []); const [uploading, setUploading] = useState(false); const [selectedSpeciesId, setSelectedSpeciesId] = useState(existingPlant?.speciesId ?? ""); const scientificNameRef = useRef(null); const sunlightRef = useRef(null); const wateringNotesRef = useRef(null); function handleSpeciesSelect(species: SpeciesSuggestion) { setSelectedSpeciesId(species.id); if (scientificNameRef.current) scientificNameRef.current.value = species.scientific_name; if (sunlightRef.current) sunlightRef.current.value = species.sunlight.join(", "); if (wateringNotesRef.current) wateringNotesRef.current.value = species.watering; } async function handleImageSelect(e: React.ChangeEvent) { const files = Array.from(e.target.files ?? []); if (images.length >= 10) { setError("Maximum 10 images allowed."); return; } setUploading(true); setError(null); try { const urls: string[] = []; for (const file of files) { if (images.length + urls.length >= 10) break; const fd = new FormData(); fd.append("file", file); const res = await fetch("/api/uploads", { method: "POST", body: fd }); if (!res.ok) throw new Error("Upload failed"); const data = (await res.json()) as { url: string }; urls.push(data.url); } setImages((prev) => [...prev, ...urls]); } catch { setError("Image upload failed. Please try again."); } finally { setUploading(false); e.target.value = ""; } } function handleRemoveImage(url: string) { setImages((prev) => prev.filter((u) => u !== url)); } function handleSubmit(e: React.FormEvent) { e.preventDefault(); const fd = new FormData(e.currentTarget); const input = { name: fd.get("name") as string, category: (fd.get("category") as string) || "other", containerId: (fd.get("containerId") as string) || null, healthStatus: (fd.get("healthStatus") as string) || "healthy", growthStage: (fd.get("growthStage") as string) || null, scientificName: scientificNameRef.current?.value || null, speciesId: selectedSpeciesId || null, sunlight: sunlightRef.current?.value || null, wateringNotes: wateringNotesRef.current?.value || null, fertilizingNotes: (fd.get("fertilizingNotes") as string) || null, notes: (fd.get("notes") as string) || null, acquisitionDate: (fd.get("acquisitionDate") as string) || null, images, primaryImageUrl: existingPlant?.primaryImageUrl ?? images[0] ?? null, }; setError(null); startTransition(async () => { try { if (existingPlant) { await updatePlant({ id: existingPlant.id, ...input }); router.push(`/garden/plants/${existingPlant.id}`); router.refresh(); } else { const plant = await createPlant(input); router.push(`/garden/plants/${plant.id}`); } } catch { setError("Something went wrong. Please try again."); } }); } return (

Search OpenPlantBook to auto-fill scientific name and care notes.