"use client"; import { useState, useTransition } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { deletePlant, addPlantImage, removePlantImage, setPrimaryImage } from "../server/actions"; import type { CalendarDto } from "../server/calendar-bridge"; import type { CareLogDto, CareScheduleDto, PlantDetailDto } from "../server/queries"; import { ShareButton } from "@/components/share-button"; import { ShareLinkList } from "@/components/share-link-list"; import type { EntityShareLink } from "@/modules/_core/share"; import { CareHistoryList } from "./care-history-list"; import { CareLogForm } from "./care-log-form"; import { CareScheduleEditor } from "./care-schedule-editor"; type Tab = "info" | "gallery" | "care"; type Props = { plant: PlantDetailDto; careLogs: CareLogDto[]; careSchedules: CareScheduleDto[]; calendars: CalendarDto[]; shareLinks: EntityShareLink[]; }; function InfoRow({ label, value, children, }: { label: string; value?: string | null; children?: React.ReactNode; }) { if (!value && !children) return null; return (
{label} {children ?? value}
); } function healthBadgeClass(status: string): string { if (status === "healthy") return "badge-success"; if (status === "sick") return "badge-danger"; return "badge-warning"; } export function PlantDetail({ plant, careLogs, careSchedules, calendars, shareLinks }: Props) { const [tab, setTab] = useState("info"); const [confirming, setConfirming] = useState(false); const [isPending, startTransition] = useTransition(); const [galleryError, setGalleryError] = useState(null); const [uploadingImage, setUploadingImage] = useState(false); const router = useRouter(); function handleDelete() { startTransition(async () => { await deletePlant({ id: plant.id }); router.push("/garden"); router.refresh(); }); } async function handleImageUpload(e: React.ChangeEvent) { const file = e.target.files?.[0]; if (!file) return; setGalleryError(null); setUploadingImage(true); try { 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 }; await addPlantImage({ id: plant.id, url: data.url }); router.refresh(); } catch { setGalleryError("Image upload failed."); } finally { setUploadingImage(false); e.target.value = ""; } } function handleRemoveImage(url: string) { startTransition(async () => { await removePlantImage({ id: plant.id, url }); router.refresh(); }); } function handleSetPrimary(url: string) { startTransition(async () => { await setPrimaryImage({ id: plant.id, url }); router.refresh(); }); } return (
{/* Header */}
{plant.primaryImageUrl && ( )}

{plant.name}

{plant.scientificName && (

{plant.scientificName}

)}
{plant.healthStatus} {plant.growthStage && ( {plant.growthStage} )}
Edit {confirming ? (
) : ( )}
{/* Tabs */}
{(["info", "gallery", "care"] as Tab[]).map((t) => ( ))}
{/* Info */} {tab === "info" && (
{plant.containerName && ( {plant.containerName} )} {plant.recentCareLogs.length > 0 && (

Recent care

    {plant.recentCareLogs.map((log) => (
  • {log.careType} {new Date(log.performedAt).toLocaleDateString()} {log.notes && — {log.notes}}
  • ))}
)}
)} {/* Gallery */} {tab === "gallery" && (
{plant.images.length === 0 ? (

No photos yet.

) : (
{plant.images.map((url) => (
{url === plant.primaryImageUrl && ( Primary )}
))}
)} {galleryError &&

{galleryError}

}
{plant.images.length < 10 && ( )} {plant.images.length}/10 photos
)} {/* Care */} {tab === "care" && (

Log care

router.refresh()} />

History

)}
); }