v0.1.1 — Garden: edit and delete plants

This commit is contained in:
Bonna Moon
2026-06-15 16:58:03 -05:00
parent eb43ec37a0
commit 78728963f4
11 changed files with 9650 additions and 3 deletions

View File

@@ -7,6 +7,8 @@ import { MapPin, CalendarDays, ChevronLeft, Sprout, Package } from "lucide-react
import { formatDate } from "@/lib/utils";
import { CATEGORY_LABELS, LOG_TYPE_LABELS, LOG_TYPE_COLORS } from "@/lib/garden/categories";
import { AddLogButton } from "@/components/garden/add-log-button";
import { EditPlantButton } from "@/components/garden/edit-plant-button";
import { DeletePlantButton } from "@/components/garden/delete-plant-button";
export async function generateMetadata({ params }: { params: { id: string } }) {
const plant = await db.plant.findUnique({ where: { id: params.id }, select: { commonName: true } });
@@ -41,6 +43,11 @@ export default async function PlantDetailPage({ params }: { params: { id: string
</Badge>
</div>
<div className="flex items-center gap-2">
<EditPlantButton plant={plant} />
<DeletePlantButton plantId={plant.id} plantName={plant.commonName} />
</div>
<Card>
<CardContent className="pt-4 space-y-2 text-sm">
{plant.zone && (

View File

@@ -0,0 +1,84 @@
import { NextResponse } from "next/server";
import { z } from "zod";
import { db } from "@/lib/db";
import { requireAuth, isAdmin } from "@/lib/auth";
import { PlantCategory } from "@prisma/client";
const updateSchema = z.object({
commonName: z.string().min(1),
species: z.string().optional(),
variety: z.string().optional(),
category: z.nativeEnum(PlantCategory),
zone: z.string().optional(),
plantedAt: z.string().optional(),
source: z.string().optional(),
notes: z.string().optional(),
});
export async function PATCH(req: Request, { params }: { params: { id: string } }) {
try {
const session = await requireAuth();
const plant = await db.plant.findUnique({ where: { id: params.id } });
if (!plant || !plant.active) return NextResponse.json({ error: "Not found" }, { status: 404 });
const body = await req.json();
const data = updateSchema.parse(body);
const updated = await db.plant.update({
where: { id: params.id },
data: {
commonName: data.commonName.trim(),
species: data.species?.trim() || null,
variety: data.variety?.trim() || null,
category: data.category,
zone: data.zone?.trim() || null,
plantedAt: data.plantedAt ? new Date(data.plantedAt) : null,
source: data.source?.trim() || null,
notes: data.notes?.trim() || null,
},
});
await db.auditEvent.create({
data: {
action: "plant.update",
entityId: params.id,
actorId: session.user.id,
payload: { commonName: updated.commonName },
},
});
return NextResponse.json(updated);
} catch (err) {
if (err instanceof z.ZodError) return NextResponse.json({ error: err.issues }, { status: 400 });
if (err instanceof Error && err.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
console.error(err);
return NextResponse.json({ error: "Server error" }, { status: 500 });
}
}
export async function DELETE(_req: Request, { params }: { params: { id: string } }) {
try {
const session = await requireAuth();
if (!isAdmin(session.user.role)) return NextResponse.json({ error: "Forbidden" }, { status: 403 });
const plant = await db.plant.findUnique({ where: { id: params.id } });
if (!plant || !plant.active) return NextResponse.json({ error: "Not found" }, { status: 404 });
await db.plant.update({ where: { id: params.id }, data: { active: false } });
await db.auditEvent.create({
data: {
action: "plant.delete",
entityId: params.id,
actorId: session.user.id,
payload: { commonName: plant.commonName },
},
});
return NextResponse.json({ ok: true });
} catch (err) {
if (err instanceof Error && err.message === "Unauthorized") return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
console.error(err);
return NextResponse.json({ error: "Server error" }, { status: 500 });
}
}