Checkpoint: Correction du bug d'émargement formateur bloqué sur la saisie d'email

- Ajout de la détection automatique formateur/apprenant dans EmargementScan.tsx
- Nouvelle procédure tRPC getSequenceByToken pour récupérer les infos de séquence
- Interface adaptée selon le type d'utilisateur (apprenant ou formateur)
- Déploiement réussi sur le VPS de production

Le système détecte maintenant automatiquement si l'email correspond à un apprenant ou un formateur, et affiche l'interface appropriée pour chaque cas.
This commit is contained in:
Manus
2026-02-02 14:18:46 -05:00
parent e8410230a9
commit f9983adada
81 changed files with 3734 additions and 27745 deletions

View File

@@ -1,180 +0,0 @@
/**
* Générateur de templates d'emails personnalisés
* Utilise les templates stockés en base de données
*/
import * as db from "./db";
import { EmailTemplate } from "../drizzle/schema";
import { replaceEmailVariables, EmailVariables } from "./emailTemplateUtils";
/**
* Génère le HTML d'un email en utilisant le template personnalisé
* @param templateType - Type de template (à utiliser)
* @param content - Contenu de l'email (legacy, sera remplacé par bodyContent)
* @param variables - Variables à remplacer dans le template
*/
export async function generateEmailFromTemplate(
templateType: string,
content: string,
variables?: EmailVariables
): Promise<string> {
// Récupérer le template depuis la base de données
const template = await db.getEmailTemplateByType(templateType);
// Si pas de template trouvé, utiliser le template par défaut
if (!template) {
const defaultContent = variables ? replaceEmailVariables(content, variables) : content;
return getDefaultEmailTemplate(defaultContent);
}
return buildEmailHTML(template, content, variables);
}
/**
* Construit le HTML de l'email avec le template
*/
function buildEmailHTML(template: EmailTemplate, content: string, variables?: EmailVariables): string {
// Utiliser bodyContent si disponible, sinon utiliser content (legacy)
let emailBody = template.bodyContent || content;
// Remplacer les variables si fournies
if (variables) {
emailBody = replaceEmailVariables(emailBody, variables);
// Remplacer aussi dans le titre et le pied de page
template = {
...template,
headerTitle: replaceEmailVariables(template.headerTitle, variables),
footerText: template.footerText ? replaceEmailVariables(template.footerText, variables) : template.footerText,
};
}
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: white;
}
.header {
background-color: ${template.headerBgColor};
color: ${template.headerTextColor};
padding: 30px 20px;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 24px;
}
${template.logoUrl ? `
.header img {
max-width: 150px;
margin-bottom: 15px;
display: block;
margin-left: auto;
margin-right: auto;
}` : ''}
.content {
background-color: #f9fafb;
padding: 30px 20px;
}
.content h2 {
color: ${template.primaryColor};
margin-top: 0;
}
.footer {
background-color: #f3f4f6;
padding: 20px;
text-align: center;
font-size: 12px;
color: #6b7280;
}
.button {
display: inline-block;
padding: 12px 24px;
background-color: ${template.primaryColor};
color: white;
text-decoration: none;
border-radius: 6px;
margin: 10px 0;
}
.info-box {
background-color: #dbeafe;
border-left: 4px solid ${template.primaryColor};
padding: 15px;
margin: 15px 0;
}
.date-item {
margin: 10px 0;
padding: 10px;
background-color: white;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
${template.logoUrl ? `<img src="${template.logoUrl}" alt="Logo" />` : ''}
<h1>${template.headerTitle}</h1>
</div>
<div class="content">
${emailBody}
</div>
<div class="footer">
<p>${template.footerText || 'Cet email a été envoyé automatiquement par le système de gestion des formations Itinova.'}</p>
</div>
</div>
</body>
</html>
`.trim();
}
/**
* Template par défaut si aucun template personnalisé n'est trouvé
*/
function getDefaultEmailTemplate(content: string): string {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; background-color: #f5f5f5; }
.container { max-width: 600px; margin: 0 auto; background-color: white; }
.header { background-color: #2563eb; color: white; padding: 30px 20px; text-align: center; }
.header h1 { margin: 0; font-size: 24px; }
.content { background-color: #f9fafb; padding: 30px 20px; }
.footer { background-color: #f3f4f6; padding: 20px; text-align: center; font-size: 12px; color: #6b7280; }
.button { display: inline-block; padding: 12px 24px; background-color: #2563eb; color: white; text-decoration: none; border-radius: 6px; margin: 10px 0; }
.info-box { background-color: #dbeafe; border-left: 4px solid #2563eb; padding: 15px; margin: 15px 0; }
.date-item { margin: 10px 0; padding: 10px; background-color: white; border-radius: 4px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Formation Manager Itinova</h1>
</div>
<div class="content">
${content}
</div>
<div class="footer">
<p>Cet email a été envoyé automatiquement par le système de gestion des formations Itinova.</p>
<p>Pour toute question, veuillez contacter le service RH.</p>
</div>
</div>
</body>
</html>
`.trim();
}