Checkpoint: Ajout de 3 améliorations pour le système de notifications :
1. Interface de gestion des emails formateurs (Configuration > Formateurs) - permet de gérer les adresses email des formateurs pour activer/désactiver les notifications 2. Tableau de bord des notifications (Configuration > Notifications) - historique complet des emails envoyés avec filtres et statistiques 3. Lien vers questionnaire de satisfaction automatiquement inclus dans l'email de remerciement post-formation
This commit is contained in:
@@ -1,7 +1,82 @@
|
||||
import { getDb } from "./db";
|
||||
import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs } from "../drizzle/schema";
|
||||
import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs, questionnaires, envoisQuestionnaires } from "../drizzle/schema";
|
||||
import { eq, and, lte, sql } from "drizzle-orm";
|
||||
import { sendRemerciementPostFormation } from "./emailService";
|
||||
import { logNotification } from "./notificationLogsDb";
|
||||
import crypto from "crypto";
|
||||
|
||||
/**
|
||||
* Génère un token unique pour accéder au questionnaire
|
||||
*/
|
||||
function generateToken(): string {
|
||||
return crypto.randomBytes(32).toString("hex");
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère ou crée un lien questionnaire pour un apprenant
|
||||
*/
|
||||
async function getOrCreateQuestionnaireLink(
|
||||
apprenantId: number,
|
||||
sequenceId: number
|
||||
): Promise<string | null> {
|
||||
const db = await getDb();
|
||||
if (!db) return null;
|
||||
|
||||
try {
|
||||
// Chercher un questionnaire de satisfaction actif
|
||||
const [questionnaire] = await db
|
||||
.select()
|
||||
.from(questionnaires)
|
||||
.where(
|
||||
and(
|
||||
eq(questionnaires.type, "satisfaction"),
|
||||
eq(questionnaires.actif, true)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (!questionnaire) {
|
||||
console.log("[Remerciements] Aucun questionnaire de satisfaction actif trouvé");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Vérifier si un envoi existe déjà
|
||||
const [envoiExistant] = await db
|
||||
.select()
|
||||
.from(envoisQuestionnaires)
|
||||
.where(
|
||||
and(
|
||||
eq(envoisQuestionnaires.questionnaireId, questionnaire.id),
|
||||
eq(envoisQuestionnaires.apprenantId, apprenantId),
|
||||
eq(envoisQuestionnaires.sequenceId, sequenceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (envoiExistant) {
|
||||
// Retourner le lien existant
|
||||
const baseUrl = process.env.VITE_FRONTEND_URL || "http://localhost:3000";
|
||||
return `${baseUrl}/questionnaire/${envoiExistant.token}`;
|
||||
}
|
||||
|
||||
// Créer un nouvel envoi
|
||||
const token = generateToken();
|
||||
await db.insert(envoisQuestionnaires).values({
|
||||
questionnaireId: questionnaire.id,
|
||||
apprenantId,
|
||||
sequenceId,
|
||||
token,
|
||||
dateEnvoi: new Date(),
|
||||
dateReponse: null,
|
||||
});
|
||||
|
||||
const baseUrl = process.env.VITE_FRONTEND_URL || "http://localhost:3000";
|
||||
return `${baseUrl}/questionnaire/${token}`;
|
||||
} catch (error) {
|
||||
console.error("[Remerciements] Erreur lors de la création du lien questionnaire:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Table pour suivre les remerciements déjà envoyés
|
||||
@@ -111,6 +186,9 @@ async function processRemerciementSequence(
|
||||
}
|
||||
|
||||
try {
|
||||
// Générer le lien questionnaire
|
||||
const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequence.id);
|
||||
|
||||
await sendRemerciementPostFormation({
|
||||
apprenantEmail: apprenant.email,
|
||||
apprenantNom: apprenant.nom,
|
||||
@@ -119,12 +197,35 @@ async function processRemerciementSequence(
|
||||
formationNom: formation.nom,
|
||||
sequenceNom: sequence.nom,
|
||||
formateurNom: formateur?.nom,
|
||||
lienQuestionnaire: lienQuestionnaire || undefined,
|
||||
});
|
||||
|
||||
// Logger la notification
|
||||
await logNotification({
|
||||
type: "remerciement",
|
||||
sequenceId: sequence.id,
|
||||
apprenantId: apprenant.id,
|
||||
emailDestinataire: apprenant.email,
|
||||
sujet: `Merci pour votre participation - ${formation.nom}`,
|
||||
statut: "success",
|
||||
metadata: { lienQuestionnaire },
|
||||
});
|
||||
|
||||
marquerRemerciementEnvoye(inscription.id, sequence.id);
|
||||
envoyesCount++;
|
||||
console.log(`[Remerciements] Email envoyé à ${apprenant.email}`);
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
// Logger l'échec
|
||||
await logNotification({
|
||||
type: "remerciement",
|
||||
sequenceId: sequence.id,
|
||||
apprenantId: apprenant.id,
|
||||
emailDestinataire: apprenant.email,
|
||||
sujet: `Merci pour votre participation - ${formation.nom}`,
|
||||
statut: "failed",
|
||||
messageErreur: error.message,
|
||||
});
|
||||
|
||||
errorsCount++;
|
||||
console.error(`[Remerciements] Erreur envoi à ${apprenant.email}:`, error);
|
||||
}
|
||||
@@ -189,6 +290,9 @@ export async function envoyerRemerciementsSequence(sequenceId: number): Promise<
|
||||
|
||||
for (const { inscription, apprenant } of inscriptionsConfirmees) {
|
||||
try {
|
||||
// Générer le lien questionnaire
|
||||
const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequenceId);
|
||||
|
||||
await sendRemerciementPostFormation({
|
||||
apprenantEmail: apprenant.email,
|
||||
apprenantNom: apprenant.nom,
|
||||
@@ -197,9 +301,33 @@ export async function envoyerRemerciementsSequence(sequenceId: number): Promise<
|
||||
formationNom: formation.nom,
|
||||
sequenceNom: sequence.nom,
|
||||
formateurNom: formateur?.nom,
|
||||
lienQuestionnaire: lienQuestionnaire || undefined,
|
||||
});
|
||||
|
||||
// Logger la notification
|
||||
await logNotification({
|
||||
type: "remerciement",
|
||||
sequenceId,
|
||||
apprenantId: apprenant.id,
|
||||
emailDestinataire: apprenant.email,
|
||||
sujet: `Merci pour votre participation - ${formation.nom}`,
|
||||
statut: "success",
|
||||
metadata: { lienQuestionnaire },
|
||||
});
|
||||
|
||||
sent++;
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
// Logger l'échec
|
||||
await logNotification({
|
||||
type: "remerciement",
|
||||
sequenceId,
|
||||
apprenantId: apprenant.id,
|
||||
emailDestinataire: apprenant.email,
|
||||
sujet: `Merci pour votre participation - ${formation.nom}`,
|
||||
statut: "failed",
|
||||
messageErreur: error.message,
|
||||
});
|
||||
|
||||
console.error(`[Remerciements] Erreur envoi à ${apprenant.email}:`, error);
|
||||
failed++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user