v0.1.1 — Garden: edit and delete plants
This commit is contained in:
@@ -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 && (
|
||||
|
||||
84
src/app/api/plants/[id]/route.ts
Normal file
84
src/app/api/plants/[id]/route.ts
Normal 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 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user