"use client"; import { useState } from "react"; import Link from "next/link"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Leaf, MapPin, CalendarDays, ChevronDown, ChevronRight, Users } from "lucide-react"; import { formatDate } from "@/lib/utils"; import { CATEGORY_LABELS } from "@/lib/garden/categories"; import { GroupLogButton } from "@/components/garden/group-log-button"; import { ZoneLogButton } from "@/components/garden/zone-log-button"; type Plant = { id: string; commonName: string; variety: string | null; species: string | null; category: string; zone: string | null; plantedAt: Date | null; imageUrl: string | null; group: { id: string; name: string } | null; _count: { logs: number }; logs: { date: Date; type: string }[]; }; type Group = { id: string; name: string; _count: { plants: number }; }; type ViewMode = "type" | "location"; // Cluster plants that share the same commonName + variety into one row. function clusterByVariety(plants: Plant[]) { const map = new Map(); for (const p of plants) { const key = `${p.commonName}||${p.variety ?? ""}`; if (!map.has(key)) map.set(key, []); map.get(key)!.push(p); } return Array.from(map.values()); } export function GardenGrid({ plants, groups }: { plants: Plant[]; groups: Group[] }) { const [expanded, setExpanded] = useState>(new Set()); const [view, setView] = useState("type"); function toggle(id: string) { setExpanded((prev) => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; }); } if (plants.length === 0) { return (

No plants yet

Add your first plant to start building your food forest registry.

); } return (
{view === "type" ? ( ) : ( )}
); } function TypeView({ plants, groups, expanded, toggle }: { plants: Plant[]; groups: Group[]; expanded: Set; toggle: (id: string) => void; }) { const ungrouped = plants.filter((p) => !p.group); const grouped = groups.map((g) => ({ ...g, plants: plants.filter((p) => p.group?.id === g.id), })).filter((g) => g.plants.length > 0); return (
{grouped.map((g) => { const isOpen = expanded.has(g.id); const clusters = clusterByVariety(g.plants); return (
{isOpen ? (
{clusters.map((cluster) => ( ))}
) : ( )}
); })} {ungrouped.length > 0 && (
{grouped.length > 0 &&

Other plants

}
{clusterByVariety(ungrouped).map((cluster) => ( ))}
)}
); } // A single variety that may span multiple locations. function VarietyRow({ plants, expanded, toggle }: { plants: Plant[]; expanded: Set; toggle: (id: string) => void; }) { const rep = plants[0]; const key = `variety||${rep.commonName}||${rep.variety ?? ""}`; const isOpen = expanded.has(key); // Collapsible row with location chips. return (
{isOpen && (
{plants.map((p) => )}
)}
); } function LocationView({ plants, expanded, toggle }: { plants: Plant[]; expanded: Set; toggle: (id: string) => void; }) { const zones = Array.from(new Set(plants.filter((p) => p.zone).map((p) => p.zone!))).sort(); const noZone = plants.filter((p) => !p.zone); return (
{zones.map((zone) => { const zonePlants = plants.filter((p) => p.zone === zone); const isOpen = expanded.has(zone); return (
{isOpen ? (
{zonePlants.map((p) => )}
) : ( )}
); })} {noZone.length > 0 && (
{zones.length > 0 &&

No location set

}
{noZone.map((p) => )}
)}
); } function PlantCard({ plant }: { plant: Plant }) { return ( {plant.imageUrl && (
{plant.commonName}
)} {!plant.imageUrl && (
)}

{plant.commonName} {plant.variety && · {plant.variety}}

{plant.species &&

{plant.species}

}
{CATEGORY_LABELS[plant.category as keyof typeof CATEGORY_LABELS]}
{plant.zone && (
{plant.zone}
)} {plant.plantedAt && (
Planted {formatDate(plant.plantedAt)}
)} {plant.logs[0] && (
Last {plant.logs[0].type.toLowerCase()} {formatDate(plant.logs[0].date)}
)}
{plant._count.logs} log {plant._count.logs === 1 ? "entry" : "entries"}
); }