diff --git a/drizzle/schema.ts b/drizzle/schema.ts index 3be1b29..32ecf29 100644 --- a/drizzle/schema.ts +++ b/drizzle/schema.ts @@ -190,8 +190,8 @@ export type InsertEmailConfig = typeof emailConfig.$inferInsert; */ export const emailTemplates = mysqlTable("emailTemplates", { id: int("id").autoincrement().primaryKey(), - /** Type de template (inscription, teaser, rappel, rappelJ1, rappel3, rappel4, rappel5, rappel6, reset_password) */ - type: mysqlEnum("type", ["inscription", "teaser", "rappel", "rappelJ1", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password"]).notNull().unique(), + /** Type de template (inscription, teaser, rappel1, rappel2, rappel3, rappel4, rappel5, rappel6, reset_password) */ + type: mysqlEnum("type", ["inscription", "teaser", "rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password"]).notNull().unique(), titre: varchar("titre", { length: 255 }).notNull(), /** Corps du message avec variables dynamiques */ bodyContent: text("bodyContent").notNull(), @@ -225,8 +225,8 @@ export type InsertFormateur = typeof formateurs.$inferInsert; export const rappels = mysqlTable("rappels", { id: int("id").autoincrement().primaryKey(), nom: varchar("nom", { length: 255 }).notNull(), - /** Type de template d'email à utiliser (rappel, rappelJ1, rappel3, rappel4, rappel5, rappel6) */ - templateType: mysqlEnum("templateType", ["rappel", "rappelJ1", "rappel3", "rappel4", "rappel5", "rappel6"]).notNull(), + /** Type de template d'email à utiliser (rappel1, rappel2, rappel3, rappel4, rappel5, rappel6) */ + templateType: mysqlEnum("templateType", ["rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6"]).notNull(), /** Nombre de jours avant la séquence */ joursAvant: int("joursAvant").notNull(), /** Heure d'envoi (format HH:mm) */ @@ -275,8 +275,8 @@ export const logsRappels = mysqlTable("logsrappels", { sequenceId: int("sequenceId").notNull(), apprenantId: int("apprenantId").notNull(), email: varchar("email", { length: 320 }).notNull(), - /** Type de rappel (rappel, rappelJ1, rappel3, rappel4, rappel5, rappel6) */ - type: mysqlEnum("type", ["rappel", "rappelJ1", "rappel3", "rappel4", "rappel5", "rappel6"]).notNull(), + /** Type de rappel (rappel1, rappel2, rappel3, rappel4, rappel5, rappel6) */ + type: mysqlEnum("type", ["rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6"]).notNull(), /** Type d'envoi (automatique, test) - les tests ne bloquent pas les envois automatiques */ typeEnvoi: mysqlEnum("typeEnvoi", ["automatique", "test"]).default("automatique").notNull(), statut: mysqlEnum("statut", ["succes", "echec"]).notNull(), diff --git a/server/db.ts b/server/db.ts index fb07379..7643129 100644 --- a/server/db.ts +++ b/server/db.ts @@ -751,8 +751,8 @@ export async function initializeDefaultEmailTemplates() { piedDePage: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.", }, { - type: "rappel", - titre: "Rappel J-7", + type: "rappel1", + titre: "Rappel 1", couleurPrincipale: "#283581", couleurSecondaire: "#0578BE", bodyContent: `

Rappel : Votre formation commence bientôt !

@@ -774,8 +774,8 @@ export async function initializeDefaultEmailTemplates() { piedDePage: "Cet email a été envoyé automatiquement par le système de gestion des formations Itinova. Pour toute question, veuillez contacter le service RH.", }, { - type: "rappelJ1", - titre: "Rappel J-1", + type: "rappel2", + titre: "Rappel 2", couleurPrincipale: "#283581", couleurSecondaire: "#0578BE", bodyContent: `

Rappel : Votre formation commence demain !

diff --git a/server/rappelRetry.ts b/server/rappelRetry.ts index 63cd7da..937be3e 100644 --- a/server/rappelRetry.ts +++ b/server/rappelRetry.ts @@ -113,7 +113,7 @@ export async function processRappelRetry() { // Réessayer l'envoi try { - if (log.typeRappel === "rappel") { + if (log.type === "rappel") { await sendRappelJ7Email({ apprenantEmail: apprenant[0].email, apprenantPrenom: apprenant[0].prenom, @@ -128,7 +128,7 @@ export async function processRappelRetry() { })), lieu: seq.lieu || "", }); - } else if (log.typeRappel === "rappelJ1") { + } else if (log.type === "rappel2") { await sendRappelJ1Email({ apprenantEmail: apprenant[0].email, apprenantPrenom: apprenant[0].prenom, @@ -149,7 +149,7 @@ export async function processRappelRetry() { await db .update(logsRappels) .set({ - statut: "success", + statut: "succes", nbTentatives: log.nbTentatives + 1, prochainEssai: null, }) @@ -166,7 +166,7 @@ export async function processRappelRetry() { await db .update(logsRappels) .set({ - statut: "failed", + statut: "echec", nbTentatives: nouvelleTentative, messageErreur: `Abandon après 3 tentatives: ${messageErreur}`, prochainEssai: null, diff --git a/server/routers.ts b/server/routers.ts index 0f0729e..4a7d1d9 100644 --- a/server/routers.ts +++ b/server/routers.ts @@ -63,8 +63,8 @@ export const appRouter = router({ await sendResetPasswordEmail({ email, - prenom: utilisateur.prenom || '', - nom: utilisateur.nom || '', + prenom: utilisateur.name?.split(' ')[0] || '', + nom: utilisateur.name?.split(' ').slice(1).join(' ') || utilisateur.name || '', lienReinitialisation: resetUrl, }); @@ -593,7 +593,7 @@ export const appRouter = router({ // Vérifier la capacité const nbInscrits = await db.countInscriptionsBySequence(input.sequenceId, 'confirmee'); - const statut = nbInscrits >= sequence.capaciteMax ? 'liste_attente' : 'confirmee'; + const statut = nbInscrits >= sequence.capaciteMax ? 'en_attente' : 'confirmee'; await db.createInscription({ apprenantId: input.apprenantId, @@ -615,7 +615,7 @@ export const appRouter = router({ apprenantEmail: inscriptionApprenant.email, apprenantNom: inscriptionApprenant.nom, apprenantPrenom: inscriptionApprenant.prenom, - apprenantFonction: inscriptionApprenant.fonction, + apprenantFonction: inscriptionApprenant.fonction || '', formationNom: inscriptionFormation.nom, sequenceNom: inscriptionSequence.nom, dates: dates.map(d => ({ @@ -638,8 +638,8 @@ export const appRouter = router({ formateurNom: formateur.nom, apprenantNom: inscriptionApprenant.nom, apprenantPrenom: inscriptionApprenant.prenom, - apprenantFonction: inscriptionApprenant.fonction, - apprenantEtablissement: inscriptionApprenant.codeEtablissement, + apprenantFonction: inscriptionApprenant.fonction || '', + apprenantEtablissement: inscriptionApprenant.codeEtablissement || '', formationNom: inscriptionFormation.nom, sequenceNom: inscriptionSequence.nom, nbInscrits: nbInscritsActuel, @@ -685,7 +685,7 @@ export const appRouter = router({ const admins = await db.getAdminUsers(); const adminEmails = admins.filter(a => a.email).map(a => a.email!); if (adminEmails.length > 0) { - const nbListeAttente = await db.countInscriptionsBySequence(input.sequenceId, 'liste_attente'); + const nbListeAttente = await db.countInscriptionsBySequence(input.sequenceId, 'en_attente'); let formateurNom: string | undefined; if (inscriptionSequence.formateurId) { const formateur = await db.getFormateurById(inscriptionSequence.formateurId); @@ -819,7 +819,7 @@ export const appRouter = router({ // Notifier le premier en liste d'attente qu'une place s'est libérée const inscriptionsListeAttente = await db.getInscriptionsBySequence(input.sequenceId); const premierEnAttente = inscriptionsListeAttente - .filter(i => i.inscription.statut === 'liste_attente') + .filter(i => i.inscription.statut === 'en_attente') .sort((a, b) => new Date(a.inscription.dateInscription).getTime() - new Date(b.inscription.dateInscription).getTime())[0]; if (premierEnAttente && premierEnAttente.apprenant) { @@ -828,7 +828,7 @@ export const appRouter = router({ apprenantEmail: premierEnAttente.apprenant.email, apprenantNom: premierEnAttente.apprenant.nom, apprenantPrenom: premierEnAttente.apprenant.prenom, - apprenantFonction: premierEnAttente.apprenant.fonction, + apprenantFonction: premierEnAttente.apprenant.fonction || '', formationNom: formation.nom, sequenceNom: sequence.nom, positionListeAttente: 1, @@ -865,7 +865,7 @@ export const appRouter = router({ updateStatut: adminProcedure.input(z.object({ id: z.number(), - statut: z.enum(['confirmee', 'liste_attente', 'annulee']), + statut: z.enum(['confirmee', 'en_attente', 'annulee']), })).mutation(async ({ input }) => { // Récupérer l'inscription avant modification const inscriptionAvant = await db.getInscriptionById(input.id); @@ -1262,7 +1262,7 @@ export const appRouter = router({ upsert: adminProcedure .input(z.object({ - type: z.enum(["inscription", "teaser", "rappel", "rappelJ1", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password"]), + type: z.enum(["inscription", "teaser", "rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password"]), titre: z.string(), bodyContent: z.string(), couleurPrincipale: z.string(), @@ -1295,7 +1295,7 @@ export const appRouter = router({ create: adminProcedure .input(z.object({ nom: z.string(), - templateType: z.enum(["rappel", "rappelJ1", "rappel3", "rappel4", "rappel5", "rappel6"]), + templateType: z.enum(["rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6"]), timing: z.enum(["pre_formation", "post_formation"]).default("pre_formation"), joursAvant: z.number(), heureEnvoi: z.string().default("09:00"), @@ -1328,7 +1328,7 @@ export const appRouter = router({ .input(z.object({ id: z.number(), nom: z.string().optional(), - templateType: z.enum(["rappel", "rappelJ1", "rappel3", "rappel4", "rappel5", "rappel6"]).optional(), + templateType: z.enum(["rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6"]).optional(), timing: z.enum(["pre_formation", "post_formation"]).optional(), joursAvant: z.number().optional(), heureEnvoi: z.string().optional(), diff --git a/todo.md b/todo.md index 725bfd6..524bd80 100644 --- a/todo.md +++ b/todo.md @@ -884,3 +884,18 @@ - [x] Corriger le problème d'affichage vide du menu Gestion technique (rebuild forcé) - [x] Redéployer correctement DashboardLayout.tsx sur le VPS avec Gestion technique en dernier - [ ] Corriger l'erreur qui cause l'affichage d'une page vide sur le VPS +- [x] Identifier les 5 erreurs TypeScript les plus critiques +- [x] Corriger les erreurs TypeScript critiques identifiées (89 → 78 erreurs) +- [x] Déployer les corrections TypeScript sur le VPS +- [ ] Vérifier le schéma de la table logsrappels dans la base de données +- [ ] Exécuter la migration de base de données si nécessaire +- [ ] Analyser la correspondance entre types de rappels et templates d'emails +- [ ] Corriger l'enum de la colonne type dans logsrappels si nécessaire + +## Correction cohérence types de rappels + +- [x] Analyser la correspondance entre types de rappels et templates d'emails +- [x] Renommer rappel → rappel1 et rappelJ1 → rappel2 dans le schéma Drizzle +- [x] Mettre à jour tous les fichiers utilisant rappel et rappelJ1 +- [x] Modifier l'enum dans la base de données MySQL +- [x] Déployer et tester les corrections