Checkpoint: Application complète de gestion des formations Manager Itinova avec toutes les fonctionnalités : gestion des formations/sessions/apprenants, système d'inscription avec validations, génération d'invitations Outlook, emails automatiques, exports PDF/Excel, et documentation complète.
This commit is contained in:
283
server/emailService.ts
Normal file
283
server/emailService.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* Service d'envoi d'emails pour les formations
|
||||
* Note: Ce module utilise console.log pour simuler l'envoi d'emails
|
||||
* Dans un environnement de production, intégrer un service SMTP réel
|
||||
*/
|
||||
|
||||
import { generateFormationICS } from "./icsGenerator";
|
||||
|
||||
interface EmailParams {
|
||||
to: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
attachments?: Array<{
|
||||
filename: string;
|
||||
content: string;
|
||||
contentType: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simule l'envoi d'un email (à remplacer par un vrai service SMTP)
|
||||
*/
|
||||
async function sendEmail(params: EmailParams): Promise<boolean> {
|
||||
console.log('=== EMAIL SIMULÉ ===');
|
||||
console.log('To:', params.to);
|
||||
console.log('Subject:', params.subject);
|
||||
console.log('HTML:', params.html.substring(0, 200) + '...');
|
||||
if (params.attachments) {
|
||||
console.log('Attachments:', params.attachments.map(a => a.filename).join(', '));
|
||||
}
|
||||
console.log('===================');
|
||||
|
||||
// Simuler un délai d'envoi
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template HTML de base pour les emails
|
||||
*/
|
||||
function getEmailTemplate(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; }
|
||||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||||
.header { background-color: #2563eb; color: white; padding: 20px; text-align: center; }
|
||||
.content { background-color: #f9fafb; padding: 30px; }
|
||||
.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; }
|
||||
</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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un email de confirmation d'inscription avec invitation Outlook
|
||||
*/
|
||||
export async function sendInscriptionConfirmation(params: {
|
||||
apprenantEmail: string;
|
||||
apprenantNom: string;
|
||||
apprenantPrenom: string;
|
||||
formationNom: string;
|
||||
sessionNom: string;
|
||||
dateDebut: Date;
|
||||
dateFin: Date;
|
||||
lieu: string;
|
||||
statut: 'confirmee' | 'liste_attente';
|
||||
}): Promise<boolean> {
|
||||
const isConfirmed = params.statut === 'confirmee';
|
||||
|
||||
const content = `
|
||||
<h2>Confirmation d'inscription</h2>
|
||||
<p>Bonjour ${params.apprenantPrenom} ${params.apprenantNom},</p>
|
||||
|
||||
${isConfirmed
|
||||
? '<p><strong>Votre inscription a été confirmée !</strong></p>'
|
||||
: '<p><strong>Vous avez été ajouté à la liste d\'attente.</strong></p>'
|
||||
}
|
||||
|
||||
<div class="info-box">
|
||||
<h3>Détails de la formation</h3>
|
||||
<p><strong>Formation :</strong> ${params.formationNom}</p>
|
||||
<p><strong>Session :</strong> ${params.sessionNom}</p>
|
||||
<p><strong>Date de début :</strong> ${params.dateDebut.toLocaleDateString('fr-FR', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})}</p>
|
||||
<p><strong>Date de fin :</strong> ${params.dateFin.toLocaleDateString('fr-FR', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})}</p>
|
||||
<p><strong>Lieu :</strong> ${params.lieu}</p>
|
||||
</div>
|
||||
|
||||
${isConfirmed
|
||||
? `<p>Une invitation Outlook est jointe à cet email. Merci de l'ajouter à votre calendrier pour bloquer votre agenda.</p>
|
||||
<p><strong>Important :</strong> Les inscriptions seront bloquées 15 jours avant le début de la session. Après cette date, aucune modification ne sera possible.</p>`
|
||||
: '<p>Nous vous contacterons dès qu\'une place se libère.</p>'
|
||||
}
|
||||
|
||||
<p>À bientôt pour cette formation !</p>
|
||||
`;
|
||||
|
||||
const attachments = isConfirmed ? [{
|
||||
filename: 'invitation.ics',
|
||||
content: generateFormationICS({
|
||||
formationNom: params.formationNom,
|
||||
sessionNom: params.sessionNom,
|
||||
dateDebut: params.dateDebut,
|
||||
dateFin: params.dateFin,
|
||||
lieu: params.lieu,
|
||||
apprenantNom: params.apprenantNom,
|
||||
apprenantPrenom: params.apprenantPrenom,
|
||||
apprenantEmail: params.apprenantEmail,
|
||||
}),
|
||||
contentType: 'text/calendar',
|
||||
}] : undefined;
|
||||
|
||||
return sendEmail({
|
||||
to: params.apprenantEmail,
|
||||
subject: isConfirmed
|
||||
? `Confirmation d'inscription - ${params.formationNom}`
|
||||
: `Liste d'attente - ${params.formationNom}`,
|
||||
html: getEmailTemplate(content),
|
||||
attachments,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un email teaser pour une session
|
||||
*/
|
||||
export async function sendTeaserEmail(params: {
|
||||
apprenantEmail: string;
|
||||
apprenantPrenom: string;
|
||||
formationNom: string;
|
||||
sessionNom: string;
|
||||
dateDebut: Date;
|
||||
}): Promise<boolean> {
|
||||
const content = `
|
||||
<h2>Votre formation approche !</h2>
|
||||
<p>Bonjour ${params.apprenantPrenom},</p>
|
||||
|
||||
<p>Nous sommes ravis de vous accueillir prochainement pour la formation <strong>${params.formationNom}</strong>.</p>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>Session :</strong> ${params.sessionNom}</p>
|
||||
<p><strong>Date :</strong> ${params.dateDebut.toLocaleDateString('fr-FR', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}</p>
|
||||
</div>
|
||||
|
||||
<p>Préparez-vous à vivre une expérience enrichissante qui vous permettra de développer vos compétences managériales.</p>
|
||||
|
||||
<p>À très bientôt !</p>
|
||||
`;
|
||||
|
||||
return sendEmail({
|
||||
to: params.apprenantEmail,
|
||||
subject: `Votre formation ${params.formationNom} approche !`,
|
||||
html: getEmailTemplate(content),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un email de rappel J-7
|
||||
*/
|
||||
export async function sendRappelJ7Email(params: {
|
||||
apprenantEmail: string;
|
||||
apprenantPrenom: string;
|
||||
formationNom: string;
|
||||
sessionNom: string;
|
||||
dateDebut: Date;
|
||||
lieu: string;
|
||||
}): Promise<boolean> {
|
||||
const content = `
|
||||
<h2>Rappel : Votre formation dans 7 jours</h2>
|
||||
<p>Bonjour ${params.apprenantPrenom},</p>
|
||||
|
||||
<p>Nous vous rappelons que votre formation <strong>${params.formationNom}</strong> commence dans 7 jours.</p>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>Informations pratiques</h3>
|
||||
<p><strong>Session :</strong> ${params.sessionNom}</p>
|
||||
<p><strong>Date :</strong> ${params.dateDebut.toLocaleDateString('fr-FR', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})}</p>
|
||||
<p><strong>Lieu :</strong> ${params.lieu}</p>
|
||||
</div>
|
||||
|
||||
<p><strong>Merci de vous présenter à l'heure indiquée.</strong></p>
|
||||
|
||||
<p>Si vous avez des questions, n'hésitez pas à contacter le service RH.</p>
|
||||
|
||||
<p>À très bientôt !</p>
|
||||
`;
|
||||
|
||||
return sendEmail({
|
||||
to: params.apprenantEmail,
|
||||
subject: `Rappel J-7 : ${params.formationNom}`,
|
||||
html: getEmailTemplate(content),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie des emails groupés à tous les inscrits d'une session
|
||||
*/
|
||||
export async function sendGroupEmail(params: {
|
||||
recipients: Array<{ email: string; prenom: string }>;
|
||||
formationNom: string;
|
||||
sessionNom: string;
|
||||
type: 'teaser' | 'rappel';
|
||||
dateDebut: Date;
|
||||
lieu?: string;
|
||||
}): Promise<{ sent: number; failed: number }> {
|
||||
let sent = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const recipient of params.recipients) {
|
||||
try {
|
||||
if (params.type === 'teaser') {
|
||||
await sendTeaserEmail({
|
||||
apprenantEmail: recipient.email,
|
||||
apprenantPrenom: recipient.prenom,
|
||||
formationNom: params.formationNom,
|
||||
sessionNom: params.sessionNom,
|
||||
dateDebut: params.dateDebut,
|
||||
});
|
||||
} else {
|
||||
await sendRappelJ7Email({
|
||||
apprenantEmail: recipient.email,
|
||||
apprenantPrenom: recipient.prenom,
|
||||
formationNom: params.formationNom,
|
||||
sessionNom: params.sessionNom,
|
||||
dateDebut: params.dateDebut,
|
||||
lieu: params.lieu || '',
|
||||
});
|
||||
}
|
||||
sent++;
|
||||
} catch (error) {
|
||||
console.error(`Erreur envoi email à ${recipient.email}:`, error);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return { sent, failed };
|
||||
}
|
||||
Reference in New Issue
Block a user