180 lines
5.8 KiB
TypeScript
180 lines
5.8 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { Prisma } from "@prisma/client";
|
|
import { prisma } from "@/lib/db";
|
|
|
|
export async function GET(
|
|
_req: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
try {
|
|
const { id } = await params;
|
|
const evaluation = await prisma.evaluation.findUnique({
|
|
where: { id },
|
|
include: {
|
|
template: {
|
|
include: {
|
|
dimensions: { orderBy: { orderIndex: "asc" } },
|
|
},
|
|
},
|
|
dimensionScores: { include: { dimension: true } },
|
|
},
|
|
});
|
|
|
|
if (!evaluation) {
|
|
return NextResponse.json({ error: "Evaluation not found" }, { status: 404 });
|
|
}
|
|
|
|
// Prisma ORM omits suggestedQuestions in some contexts — fetch via raw
|
|
const templateId = evaluation.templateId;
|
|
const dimsRaw = evaluation.template
|
|
? ((await prisma.$queryRaw(
|
|
Prisma.sql`SELECT id, slug, title, rubric, "orderIndex", "suggestedQuestions" FROM "TemplateDimension" WHERE "templateId" = ${templateId} ORDER BY "orderIndex" ASC`
|
|
)) as { id: string; slug: string; title: string; rubric: string; orderIndex: number; suggestedQuestions: string | null }[])
|
|
: [];
|
|
|
|
const dimMap = new Map(dimsRaw.map((d) => [d.id, d]));
|
|
|
|
const out = {
|
|
...evaluation,
|
|
template: evaluation.template
|
|
? {
|
|
...evaluation.template,
|
|
dimensions: evaluation.template.dimensions.map((d) => {
|
|
const raw = dimMap.get(d.id);
|
|
return {
|
|
id: d.id,
|
|
slug: d.slug,
|
|
title: d.title,
|
|
rubric: d.rubric,
|
|
orderIndex: d.orderIndex,
|
|
suggestedQuestions: raw?.suggestedQuestions ?? d.suggestedQuestions,
|
|
};
|
|
}),
|
|
}
|
|
: null,
|
|
dimensionScores: evaluation.dimensionScores.map((ds) => ({
|
|
...ds,
|
|
dimension: ds.dimension
|
|
? {
|
|
id: ds.dimension.id,
|
|
slug: ds.dimension.slug,
|
|
title: ds.dimension.title,
|
|
rubric: ds.dimension.rubric,
|
|
suggestedQuestions: dimMap.get(ds.dimension.id)?.suggestedQuestions ?? ds.dimension.suggestedQuestions,
|
|
}
|
|
: null,
|
|
})),
|
|
};
|
|
return NextResponse.json(out);
|
|
} catch (e) {
|
|
console.error(e);
|
|
return NextResponse.json({ error: "Failed to fetch evaluation" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export async function PUT(
|
|
req: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
try {
|
|
const { id } = await params;
|
|
const body = await req.json();
|
|
|
|
const { candidateName, candidateRole, candidateTeam, evaluatorName, evaluationDate, status, findings, recommendations, dimensionScores } = body;
|
|
|
|
const existing = await prisma.evaluation.findUnique({ where: { id } });
|
|
if (!existing) {
|
|
return NextResponse.json({ error: "Evaluation not found" }, { status: 404 });
|
|
}
|
|
|
|
const updateData: Record<string, unknown> = {};
|
|
if (candidateName != null) updateData.candidateName = candidateName;
|
|
if (candidateRole != null) updateData.candidateRole = candidateRole;
|
|
if (candidateTeam !== undefined) updateData.candidateTeam = candidateTeam || null;
|
|
if (evaluatorName != null) updateData.evaluatorName = evaluatorName;
|
|
if (evaluationDate != null) {
|
|
const d = new Date(evaluationDate);
|
|
if (!isNaN(d.getTime())) updateData.evaluationDate = d;
|
|
}
|
|
if (status != null) updateData.status = status;
|
|
if (findings != null) updateData.findings = findings;
|
|
if (recommendations != null) updateData.recommendations = recommendations;
|
|
|
|
if (Object.keys(updateData).length > 0) {
|
|
await prisma.auditLog.create({
|
|
data: {
|
|
evaluationId: id,
|
|
action: "updated",
|
|
newValue: JSON.stringify(updateData),
|
|
},
|
|
});
|
|
}
|
|
|
|
if (Object.keys(updateData).length > 0) {
|
|
await prisma.evaluation.update({
|
|
where: { id },
|
|
data: updateData as Record<string, unknown>,
|
|
});
|
|
}
|
|
|
|
if (dimensionScores && Array.isArray(dimensionScores)) {
|
|
for (const ds of dimensionScores) {
|
|
if (ds.dimensionId) {
|
|
await prisma.dimensionScore.upsert({
|
|
where: {
|
|
evaluationId_dimensionId: {
|
|
evaluationId: id,
|
|
dimensionId: ds.dimensionId,
|
|
},
|
|
},
|
|
update: {
|
|
score: ds.score,
|
|
justification: ds.justification,
|
|
examplesObserved: ds.examplesObserved,
|
|
confidence: ds.confidence,
|
|
candidateNotes: ds.candidateNotes,
|
|
},
|
|
create: {
|
|
evaluationId: id,
|
|
dimensionId: ds.dimensionId,
|
|
score: ds.score,
|
|
justification: ds.justification,
|
|
examplesObserved: ds.examplesObserved,
|
|
confidence: ds.confidence,
|
|
candidateNotes: ds.candidateNotes,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
const updated = await prisma.evaluation.findUnique({
|
|
where: { id },
|
|
include: {
|
|
template: { include: { dimensions: { orderBy: { orderIndex: "asc" } } } },
|
|
dimensionScores: { include: { dimension: true } },
|
|
},
|
|
});
|
|
|
|
return NextResponse.json(updated);
|
|
} catch (e) {
|
|
console.error(e);
|
|
const msg = e instanceof Error ? e.message : "Failed to update evaluation";
|
|
return NextResponse.json({ error: msg }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export async function DELETE(
|
|
_req: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
try {
|
|
const { id } = await params;
|
|
await prisma.evaluation.delete({ where: { id } });
|
|
return NextResponse.json({ ok: true });
|
|
} catch (e) {
|
|
console.error(e);
|
|
return NextResponse.json({ error: "Failed to delete evaluation" }, { status: 500 });
|
|
}
|
|
}
|