Refactor evaluation and admin pages to use server actions for data fetching, enhancing performance and simplifying state management. Update README to reflect API route changes and remove deprecated API endpoints for users and evaluations.
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m7s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m7s
This commit is contained in:
190
src/actions/evaluations.ts
Normal file
190
src/actions/evaluations.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
"use server";
|
||||
|
||||
import { auth } from "@/auth";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { canAccessEvaluation } from "@/lib/evaluation-access";
|
||||
import { getEvaluation } from "@/lib/server-data";
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
export type ActionResult<T = void> = { success: true; data?: T } | { success: false; error: string };
|
||||
|
||||
export async function fetchEvaluation(id: string): Promise<ActionResult<Awaited<ReturnType<typeof getEvaluation>>>> {
|
||||
const session = await auth();
|
||||
if (!session?.user) return { success: false, error: "Non authentifié" };
|
||||
|
||||
const evaluation = await getEvaluation(id);
|
||||
if (!evaluation) return { success: false, error: "Évaluation introuvable" };
|
||||
|
||||
return { success: true, data: evaluation };
|
||||
}
|
||||
|
||||
export async function deleteEvaluation(id: string): Promise<ActionResult> {
|
||||
const session = await auth();
|
||||
if (!session?.user) return { success: false, error: "Non authentifié" };
|
||||
|
||||
const hasAccess = await canAccessEvaluation(id, session.user.id, session.user.role === "admin");
|
||||
if (!hasAccess) return { success: false, error: "Accès refusé" };
|
||||
|
||||
try {
|
||||
await prisma.evaluation.delete({ where: { id } });
|
||||
revalidatePath("/dashboard");
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { success: false, error: "Erreur lors de la suppression" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function createEvaluation(data: {
|
||||
candidateName: string;
|
||||
candidateRole: string;
|
||||
candidateTeam?: string;
|
||||
evaluationDate: string;
|
||||
templateId: string;
|
||||
}): Promise<ActionResult<{ id: string }>> {
|
||||
const session = await auth();
|
||||
if (!session?.user) return { success: false, error: "Non authentifié" };
|
||||
|
||||
const { candidateName, candidateRole, candidateTeam, evaluationDate, templateId } = data;
|
||||
if (!candidateName || !candidateRole || !evaluationDate || !templateId) {
|
||||
return { success: false, error: "Champs requis manquants" };
|
||||
}
|
||||
|
||||
try {
|
||||
const evaluatorName = session.user.name || session.user.email || "Évaluateur";
|
||||
|
||||
const template = await prisma.template.findUnique({
|
||||
where: { id: templateId },
|
||||
include: { dimensions: { orderBy: { orderIndex: "asc" } } },
|
||||
});
|
||||
if (!template) return { success: false, error: "Template introuvable" };
|
||||
|
||||
const evaluation = await prisma.evaluation.create({
|
||||
data: {
|
||||
candidateName,
|
||||
candidateRole,
|
||||
candidateTeam: candidateTeam || null,
|
||||
evaluatorName,
|
||||
evaluatorId: session.user.id,
|
||||
evaluationDate: new Date(evaluationDate),
|
||||
templateId,
|
||||
status: "draft",
|
||||
},
|
||||
});
|
||||
|
||||
for (const dim of template.dimensions) {
|
||||
await prisma.dimensionScore.create({
|
||||
data: { evaluationId: evaluation.id, dimensionId: dim.id },
|
||||
});
|
||||
}
|
||||
|
||||
revalidatePath("/dashboard");
|
||||
return { success: true, data: { id: evaluation.id } };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { success: false, error: "Erreur lors de la création" };
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateEvaluationInput {
|
||||
candidateName?: string;
|
||||
candidateRole?: string;
|
||||
candidateTeam?: string | null;
|
||||
evaluatorName?: string;
|
||||
evaluationDate?: string;
|
||||
status?: string;
|
||||
findings?: string | null;
|
||||
recommendations?: string | null;
|
||||
isPublic?: boolean;
|
||||
dimensionScores?: {
|
||||
dimensionId: string;
|
||||
evaluationId: string;
|
||||
score: number | null;
|
||||
justification?: string | null;
|
||||
examplesObserved?: string | null;
|
||||
confidence?: string | null;
|
||||
candidateNotes?: string | null;
|
||||
}[];
|
||||
}
|
||||
|
||||
export async function updateEvaluation(id: string, data: UpdateEvaluationInput): Promise<ActionResult> {
|
||||
const session = await auth();
|
||||
if (!session?.user) return { success: false, error: "Non authentifié" };
|
||||
|
||||
const hasAccess = await canAccessEvaluation(id, session.user.id, session.user.role === "admin");
|
||||
if (!hasAccess) return { success: false, error: "Accès refusé" };
|
||||
|
||||
const existing = await prisma.evaluation.findUnique({ where: { id } });
|
||||
if (!existing) return { success: false, error: "Évaluation introuvable" };
|
||||
|
||||
try {
|
||||
const {
|
||||
candidateName,
|
||||
candidateRole,
|
||||
candidateTeam,
|
||||
evaluatorName,
|
||||
evaluationDate,
|
||||
status,
|
||||
findings,
|
||||
recommendations,
|
||||
isPublic,
|
||||
dimensionScores,
|
||||
} = data;
|
||||
|
||||
const updateData: Record<string, unknown> = {};
|
||||
if (candidateName != null) updateData.candidateName = candidateName;
|
||||
if (candidateRole != null) updateData.candidateRole = candidateRole;
|
||||
if (candidateTeam !== undefined) updateData.candidateTeam = candidateTeam;
|
||||
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 (typeof isPublic === "boolean") updateData.isPublic = isPublic;
|
||||
|
||||
if (Object.keys(updateData).length > 0) {
|
||||
await prisma.auditLog.create({
|
||||
data: { evaluationId: id, action: "updated", newValue: JSON.stringify(updateData) },
|
||||
});
|
||||
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,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
revalidatePath(`/evaluations/${id}`);
|
||||
revalidatePath("/dashboard");
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { success: false, error: e instanceof Error ? e.message : "Erreur lors de la sauvegarde" };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user