feat: implement full CRUD functionality for projects with image upload support and admin dashboard management

This commit is contained in:
Yolando
2026-03-28 21:11:36 +07:00
parent 0549f12a97
commit 01ecca4b28
17 changed files with 2399 additions and 6 deletions

View File

@@ -0,0 +1,68 @@
import { NextResponse } from "next/server";
import { prisma } from "@/core/db/prisma";
import { uploadFileLocally } from "@/core/storage/local";
import { verifySession } from "@/core/security/session";
import { projectSchema } from "@/features/projects/project-schema";
import { revalidatePath } from "next/cache";
export async function POST(req: Request) {
const session = await verifySession();
if (!session) {
return NextResponse.json({ success: false, message: "Unauthorized" }, { status: 401 });
}
try {
const formData = await req.formData();
const data = {
title: formData.get("title") as string,
slug: formData.get("slug") as string,
description: formData.get("description") as string,
category: formData.get("category") as string,
repoUrl: formData.get("repoUrl") as string,
liveUrl: formData.get("liveUrl") as string,
isPublished: formData.get("isPublished") === "true" || formData.get("isPublished") === "on",
image: formData.get("image") as File | null,
};
const validation = projectSchema.safeParse(data);
if (!validation.success) {
return NextResponse.json({ success: false, message: validation.error.issues[0].message }, { status: 400 });
}
let imageUrl: string | undefined = undefined;
if (data.image && data.image.size > 0 && data.image.name) {
try {
imageUrl = await uploadFileLocally(data.image);
} catch (e: any) {
console.error("Local upload error:", e);
return NextResponse.json({ success: false, message: "Failed to upload image locally." }, { status: 500 });
}
}
const project = await prisma.project.create({
data: {
title: validation.data.title,
slug: validation.data.slug,
description: validation.data.description,
category: validation.data.category,
repoUrl: validation.data.repoUrl || null,
liveUrl: validation.data.liveUrl || null,
isPublished: validation.data.isPublished,
imageUrl: imageUrl,
},
});
revalidatePath("/admin/dashboard/projects");
revalidatePath("/admin/dashboard");
revalidatePath("/");
return NextResponse.json({ success: true, project });
} catch (error: any) {
console.error("API Error (Create Project):", error);
if (error?.code === "P2002") {
return NextResponse.json({ success: false, message: "Project slug already exists" }, { status: 400 });
}
return NextResponse.json({ success: false, message: "Failed to create project" }, { status: 500 });
}
}