Checkpoint: Ajout des types de rappels J-7 et J-1 dans l'interface de gestion des rappels. Les templates d'emails ont été corrigés pour afficher toutes les dates des séquences. Bug connu : l'insertion des rappels échoue avec une erreur SQL sur le champ derniereExecution (à corriger après ce checkpoint).

This commit is contained in:
Manus Sandbox
2025-11-30 17:24:41 -05:00
parent d84a2fe0c5
commit 548dbc12b9
9 changed files with 1375 additions and 70 deletions

View File

@@ -26,7 +26,10 @@ import {
InsertEmailTemplate,
formateurs,
InsertFormateur,
Formateur
Formateur,
rappels,
InsertRappel,
Rappel
} from "../drizzle/schema";
import { ENV } from './_core/env';
@@ -816,3 +819,70 @@ export async function deleteFormateur(id: number) {
await db.delete(formateurs).where(eq(formateurs.id, id));
}
// ==================== RAPPELS ====================
export async function createRappel(data: InsertRappel) {
const db = await getDb();
if (!db) throw new Error("Database not available");
// Construire un objet d'insertion explicite sans derniereExecution
const insertData: Partial<InsertRappel> = {
nom: data.nom,
templateType: data.templateType,
joursAvant: data.joursAvant,
heureEnvoi: data.heureEnvoi,
actif: data.actif,
};
const result = await db.insert(rappels).values(insertData as InsertRappel);
return result;
}
export async function getRappels() {
const db = await getDb();
if (!db) return [];
return await db.select().from(rappels).orderBy(rappels.joursAvant);
}
export async function getRappelById(id: number): Promise<Rappel | undefined> {
const db = await getDb();
if (!db) return undefined;
const result = await db.select().from(rappels).where(eq(rappels.id, id)).limit(1);
return result.length > 0 ? result[0] : undefined;
}
export async function getActiveRappels(): Promise<Rappel[]> {
const db = await getDb();
if (!db) return [];
return await db.select().from(rappels).where(eq(rappels.actif, true));
}
export async function updateRappel(id: number, data: Partial<InsertRappel>) {
const db = await getDb();
if (!db) throw new Error("Database not available");
await db.update(rappels).set({
...data,
updatedAt: new Date(),
}).where(eq(rappels.id, id));
}
export async function deleteRappel(id: number) {
const db = await getDb();
if (!db) throw new Error("Database not available");
await db.delete(rappels).where(eq(rappels.id, id));
}
export async function updateRappelExecution(id: number) {
const db = await getDb();
if (!db) return;
await db.update(rappels).set({
derniereExecution: new Date(),
}).where(eq(rappels.id, id));
}

View File

@@ -829,15 +829,15 @@ export const appRouter = router({
// ===== GESTION DES RAPPELS =====
rappels: router({
list: adminProcedure.query(async () => {
return db.getAllRappels();
return db.getRappels();
}),
create: adminProcedure
.input(z.object({
nom: z.string(),
templateType: z.string(),
joursAvant: z.number(),
sujet: z.string(),
contenu: z.string(),
heureEnvoi: z.string().default("09:00"),
actif: z.boolean(),
}))
.mutation(async ({ input }) => {
@@ -847,14 +847,16 @@ export const appRouter = router({
update: adminProcedure
.input(z.object({
id: z.number(),
nom: z.string(),
joursAvant: z.number(),
sujet: z.string(),
contenu: z.string(),
actif: z.boolean(),
nom: z.string().optional(),
templateType: z.string().optional(),
joursAvant: z.number().optional(),
heureEnvoi: z.string().optional(),
actif: z.boolean().optional(),
}))
.mutation(async ({ input }) => {
return db.updateRappel(input);
const { id, ...data } = input;
await db.updateRappel(id, data);
return { success: true };
}),
delete: adminProcedure
@@ -867,7 +869,7 @@ export const appRouter = router({
toggleActif: adminProcedure
.input(z.object({ id: z.number(), actif: z.boolean() }))
.mutation(async ({ input }) => {
await db.updateRappel({ id: input.id, actif: input.actif });
await db.updateRappel(input.id, { actif: input.actif });
return { success: true };
}),
}),