Checkpoint: Trois améliorations majeures pour la gestion des séquences :

 **1. Indicateur visuel de remplissage**
- Composant CapacityProgressBar avec barre de progression colorée
- Affichage "X / Y" avec pourcentage
- Couleurs automatiques : vert (<70%), orange (70-90%), rouge (>90%)
- Intégré dans la colonne capacité du tableau des séquences

 **2. Vue calendrier mensuel**
- Nouvelle page AdminCalendrier accessible depuis le menu
- Calendrier mensuel avec navigation (mois précédent/suivant, aujourd'hui)
- Affichage des séquences sur leurs dates respectives
- Dialog de détails au clic sur une séquence
- Vue complète avec toutes les informations (lieu, formateur, capacité, dates)

 **3. Système de rappels automatiques personnalisables**
- Tables rappels et rappelsEnvoyes créées
- Procédures tRPC complètes (list, create, update, delete)
- Page AdminRappels avec interface de gestion
- Configuration de rappels multiples (J-15, J-7, J-1, etc.)
- Templates d'emails personnalisables avec variables dynamiques
- Activation/désactivation des rappels
- Infrastructure prête pour l'envoi automatique (nécessite service de planification externe)

Ces améliorations facilitent grandement la planification et le suivi des formations.
This commit is contained in:
Manus Sandbox
2025-11-19 09:59:37 -05:00
parent 16351ea3d5
commit 4bf589dde3
15 changed files with 1778 additions and 4 deletions

View File

@@ -690,6 +690,40 @@ export const appRouter = router({
}),
}),
// ===== RAPPELS =====
rappels: router({
list: adminProcedure.query(async () => {
return db.getRappels();
}),
create: adminProcedure.input(z.object({
nom: z.string().min(1),
joursAvant: z.number().min(1),
emailTemplate: z.string().min(1),
actif: z.boolean().default(true),
})).mutation(async ({ input }) => {
await db.createRappel(input);
return { success: true };
}),
update: adminProcedure.input(z.object({
id: z.number(),
nom: z.string().min(1).optional(),
joursAvant: z.number().min(1).optional(),
emailTemplate: z.string().min(1).optional(),
actif: z.boolean().optional(),
})).mutation(async ({ input }) => {
const { id, ...data } = input;
await db.updateRappel(id, data);
return { success: true };
}),
delete: adminProcedure.input(z.object({ id: z.number() })).mutation(async ({ input }) => {
await db.deleteRappel(input.id);
return { success: true };
}),
}),
emailConfig: router({
get: adminProcedure.query(async () => {
return db.getActiveEmailConfig();