Checkpoint: Ajout de la page de gestion des attestations de formation

Nouvelle fonctionnalité complète pour gérer les attestations :

- Schéma de base de données : colonnes modeAttestation et modeEnvoi dans formations, colonnes documentUrl, documentS3Key, uploadedBy, uploadedAt dans attestations
- Backend : fichier gestionAttestationsDb.ts, procédures tRPC, fonction sendAttestationEmail
- Interface : page AdminGestionAttestations avec sélection de formation, configuration des modes, tableau des apprenants, boutons upload/prévisualisation/envoi/suppression
- Navigation : lien dans menu Gestion, route /admin/gestion-attestations
This commit is contained in:
Manus
2026-01-12 14:57:30 -05:00
parent ce64c72f00
commit a7602e6740
9 changed files with 760 additions and 0 deletions

View File

@@ -2281,6 +2281,95 @@ export const appRouter = router({
return checkAllPresencesValidated(input.inscriptionId);
}),
}),
// ===== GESTION DES ATTESTATIONS =====
gestionAttestations: router({
// Récupérer la configuration d'une formation
getFormationConfig: adminProcedure
.input(z.object({ formationId: z.number() }))
.query(async ({ input }) => {
const { getFormationConfig } = await import("./gestionAttestationsDb");
return getFormationConfig(input.formationId);
}),
// Mettre à jour la configuration d'une formation
updateFormationConfig: adminProcedure
.input(z.object({
formationId: z.number(),
modeAttestation: z.enum(["auto", "manuel"]),
modeEnvoi: z.enum(["auto", "manuel"]),
}))
.mutation(async ({ input }) => {
const { updateFormationConfig } = await import("./gestionAttestationsDb");
return updateFormationConfig(
input.formationId,
input.modeAttestation,
input.modeEnvoi
);
}),
// Récupérer les apprenants avec leur statut d'attestation
getApprenantsWithStatus: adminProcedure
.input(z.object({ formationId: z.number() }))
.query(async ({ input }) => {
const { getApprenantsWithAttestationStatus } = await import("./gestionAttestationsDb");
return getApprenantsWithAttestationStatus(input.formationId);
}),
// Uploader un document d'attestation
uploadDocument: adminProcedure
.input(z.object({
inscriptionId: z.number(),
documentUrl: z.string(),
documentS3Key: z.string(),
}))
.mutation(async ({ input, ctx }) => {
const { uploadAttestationDocument } = await import("./gestionAttestationsDb");
return uploadAttestationDocument(
input.inscriptionId,
input.documentUrl,
input.documentS3Key,
ctx.user.id
);
}),
// Supprimer un document d'attestation
deleteDocument: adminProcedure
.input(z.object({ attestationId: z.number() }))
.mutation(async ({ input }) => {
const { deleteAttestationDocument } = await import("./gestionAttestationsDb");
return deleteAttestationDocument(input.attestationId);
}),
// Envoyer une attestation par email
sendAttestation: adminProcedure
.input(z.object({
attestationId: z.number(),
apprenantEmail: z.string(),
apprenantNom: z.string(),
apprenantPrenom: z.string(),
formationNom: z.string(),
pdfUrl: z.string(),
}))
.mutation(async ({ input }) => {
const { sendAttestationEmail } = await import("./emailService");
const { markAttestationAsSent } = await import("./gestionAttestationsDb");
// Envoyer l'email
await sendAttestationEmail({
to: input.apprenantEmail,
apprenantNom: input.apprenantNom,
apprenantPrenom: input.apprenantPrenom,
formationNom: input.formationNom,
pdfUrl: input.pdfUrl,
});
// Marquer comme envoyé
await markAttestationAsSent(input.attestationId);
return { success: true };
}),
}),
});
export type AppRouter = typeof appRouter;