Checkpoint: Ajout de la possibilité de joindre un fichier dans l'envoi des rappels par email

Modifications apportées :
- Ajout des colonnes nomFichier, urlFichier, s3Key, typeFichier, tailleFichier dans la table rappels
- Création du composant FileUpload pour l'upload de fichiers vers S3 (max 10 Mo)
- Création de l'endpoint API /api/upload-file pour gérer l'upload
- Intégration du composant FileUpload dans les formulaires de création et modification de rappels
- Mise à jour des procédures tRPC create et update pour gérer les informations de fichier
- Modification des fonctions sendRappelJ7Email et sendRappelJ1Email pour inclure les pièces jointes
- Mise à jour du scheduler de rappels pour passer les informations de fichier lors de l'envoi
- Les fichiers sont téléchargés depuis S3 et convertis en base64 pour être attachés aux emails
This commit is contained in:
Manus
2026-01-08 06:00:27 -05:00
parent 6e25c00865
commit 5308b7921e
16 changed files with 2613 additions and 4 deletions

View File

@@ -938,18 +938,29 @@ export async function deleteFormateur(id: number) {
// ==================== RAPPELS ====================
export async function createRappel(data: InsertRappel) {
export async function createRappel(data: InsertRappel & { fichier?: { nomFichier: string; urlFichier: string; s3Key: string; typeFichier: string; tailleFichier: number; } | null }) {
const db = await getDb();
if (!db) throw new Error("Database not available");
// Construire un objet d'insertion explicite sans derniereExecution
// Construire un objet d'insertion explicite
const insertData: Partial<InsertRappel> = {
nom: data.nom,
templateType: data.templateType,
timing: data.timing,
joursAvant: data.joursAvant,
heureEnvoi: data.heureEnvoi,
actif: data.actif,
};
// Ajouter les champs de fichier si présents
if (data.fichier) {
insertData.nomFichier = data.fichier.nomFichier;
insertData.urlFichier = data.fichier.urlFichier;
insertData.s3Key = data.fichier.s3Key;
insertData.typeFichier = data.fichier.typeFichier;
insertData.tailleFichier = data.fichier.tailleFichier;
}
const result = await db.insert(rappels).values(insertData as InsertRappel);
return result;
}
@@ -976,12 +987,33 @@ export async function getActiveRappels(): Promise<Rappel[]> {
return await db.select().from(rappels).where(eq(rappels.actif, true));
}
export async function updateRappel(id: number, data: Partial<InsertRappel>) {
export async function updateRappel(id: number, data: Partial<InsertRappel> & { fichier?: { nomFichier: string; urlFichier: string; s3Key: string; typeFichier: string; tailleFichier: number; } | null }) {
const db = await getDb();
if (!db) throw new Error("Database not available");
const updateData: any = { ...data };
// Gérer les champs de fichier
if ('fichier' in data) {
delete updateData.fichier;
if (data.fichier) {
updateData.nomFichier = data.fichier.nomFichier;
updateData.urlFichier = data.fichier.urlFichier;
updateData.s3Key = data.fichier.s3Key;
updateData.typeFichier = data.fichier.typeFichier;
updateData.tailleFichier = data.fichier.tailleFichier;
} else {
// Supprimer le fichier
updateData.nomFichier = null;
updateData.urlFichier = null;
updateData.s3Key = null;
updateData.typeFichier = null;
updateData.tailleFichier = null;
}
}
await db.update(rappels).set({
...data,
...updateData,
updatedAt: new Date(),
}).where(eq(rappels.id, id));
}