Checkpoint: Corrections multiples : template reset_password, bugs UI templates d'email, schémas DB, et table logsRappels
**Ajouts :**
- Template "Réinitialisation de mot de passe" (reset_password) ajouté à l'enum et au système
**Corrections de bugs :**
- Bug de mise à jour du type de template (ajout de key={selectedType} pour forcer remontage)
- Erreur SQL configuration SMTP (correction schéma emailConfig avec champs active, domainVerified, apiKey)
- Erreur de type formateurId (conversion string → number dans AdminSequences.tsx)
- Date de blocage non sauvegardée (ajout champ dateBlocage au schéma sequences)
- Table logsRappels incohérente (suppression colonnes obsolètes, correction enum statut)
**Schémas Drizzle mis à jour :**
- emailTemplates : ajout reset_password à l'enum type
- emailConfig : ajout active, domainVerified, correction apiKey
- sequences : ajout dateBlocage (datetime)
- logsRappels : structure nettoyée et conforme
**Déploiement VPS :**
- Toutes les migrations SQL exécutées avec succès
- Application redémarrée et fonctionnelle
- Historique des rappels prêt à fonctionner (table logsRappels corrigée)
This commit is contained in:
@@ -64,7 +64,7 @@ export default function AdminEmailTemplates() {
|
|||||||
],
|
],
|
||||||
content: formData.bodyContent,
|
content: formData.bodyContent,
|
||||||
onUpdate: ({ editor }) => {
|
onUpdate: ({ editor }) => {
|
||||||
setFormData({ ...formData, bodyContent: editor.getHTML() });
|
setFormData((prev) => ({ ...prev, bodyContent: editor.getHTML() }));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,11 +101,18 @@ export default function AdminEmailTemplates() {
|
|||||||
};
|
};
|
||||||
setFormData(newData);
|
setFormData(newData);
|
||||||
// Mettre à jour le contenu de l'éditeur
|
// Mettre à jour le contenu de l'éditeur
|
||||||
if (editor) {
|
if (editor && !editor.isDestroyed) {
|
||||||
editor.commands.setContent(newData.bodyContent);
|
editor.commands.setContent(newData.bodyContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [currentTemplate, editor]);
|
}, [currentTemplate]);
|
||||||
|
|
||||||
|
// Synchroniser l'éditeur avec formData.bodyContent quand l'éditeur est prêt
|
||||||
|
useEffect(() => {
|
||||||
|
if (editor && !editor.isDestroyed && formData.bodyContent !== editor.getHTML()) {
|
||||||
|
editor.commands.setContent(formData.bodyContent);
|
||||||
|
}
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
upsertMutation.mutate({
|
upsertMutation.mutate({
|
||||||
@@ -273,7 +280,7 @@ export default function AdminEmailTemplates() {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Formulaire d'édition */}
|
{/* Formulaire d'édition */}
|
||||||
<Card className="lg:col-span-2">
|
<Card key={selectedType} className="lg:col-span-2">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Éditer le template</CardTitle>
|
<CardTitle>Éditer le template</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export default function AdminSequences() {
|
|||||||
|
|
||||||
// Convertir une date locale (datetime-local) en ISO UTC
|
// Convertir une date locale (datetime-local) en ISO UTC
|
||||||
const convertLocalToUTC = (localDateStr: string): string => {
|
const convertLocalToUTC = (localDateStr: string): string => {
|
||||||
if (!localDateStr) return localDateStr;
|
if (!localDateStr || localDateStr.trim() === '') return '';
|
||||||
// datetime-local retourne "YYYY-MM-DDTHH:mm"
|
// datetime-local retourne "YYYY-MM-DDTHH:mm"
|
||||||
// On doit le traiter comme heure locale et le convertir en UTC
|
// On doit le traiter comme heure locale et le convertir en UTC
|
||||||
const localDate = new Date(localDateStr);
|
const localDate = new Date(localDateStr);
|
||||||
@@ -185,7 +185,7 @@ export default function AdminSequences() {
|
|||||||
capaciteMax: parseInt(formData.capaciteMax),
|
capaciteMax: parseInt(formData.capaciteMax),
|
||||||
dateBlocage: convertLocalToUTC(formData.dateBlocage),
|
dateBlocage: convertLocalToUTC(formData.dateBlocage),
|
||||||
statut: formData.statut,
|
statut: formData.statut,
|
||||||
formateurId: formData.formateur,
|
formateurId: formData.formateur ? parseInt(formData.formateur) : null,
|
||||||
dates: formData.dates.map(d => ({
|
dates: formData.dates.map(d => ({
|
||||||
...d,
|
...d,
|
||||||
dateDebut: convertLocalToUTC(d.dateDebut),
|
dateDebut: convertLocalToUTC(d.dateDebut),
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ export const sequences = mysqlTable("sequences", {
|
|||||||
publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre", "tous"]).default("tous").notNull(),
|
publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre", "tous"]).default("tous").notNull(),
|
||||||
/** ID du formateur assigné à cette séquence */
|
/** ID du formateur assigné à cette séquence */
|
||||||
formateurId: int("formateurId"),
|
formateurId: int("formateurId"),
|
||||||
|
/** Date limite d'inscription (blocage) */
|
||||||
|
dateBlocage: datetime("dateBlocage"),
|
||||||
/** Token unique pour le QR code d'émargement */
|
/** Token unique pour le QR code d'émargement */
|
||||||
qrCodeToken: varchar("qrCodeToken", { length: 100 }).unique(),
|
qrCodeToken: varchar("qrCodeToken", { length: 100 }).unique(),
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
@@ -149,24 +151,28 @@ export const emailConfig = mysqlTable("emailConfig", {
|
|||||||
id: int("id").autoincrement().primaryKey(),
|
id: int("id").autoincrement().primaryKey(),
|
||||||
/** Provider d'envoi d'emails (resend, smtp, simulation) */
|
/** Provider d'envoi d'emails (resend, smtp, simulation) */
|
||||||
provider: mysqlEnum("provider", ["resend", "smtp", "simulation"]).default("simulation").notNull(),
|
provider: mysqlEnum("provider", ["resend", "smtp", "simulation"]).default("simulation").notNull(),
|
||||||
/** Clé API Resend */
|
/** Clé API (pour Resend ou autres) */
|
||||||
resendApiKey: varchar("resendApiKey", { length: 255 }),
|
apiKey: text("apiKey"),
|
||||||
/** Hôte SMTP */
|
/** Hôte SMTP */
|
||||||
smtpHost: varchar("smtpHost", { length: 255 }),
|
smtpHost: varchar("smtpHost", { length: 255 }),
|
||||||
/** Port SMTP */
|
/** Port SMTP */
|
||||||
smtpPort: int("smtpPort"),
|
smtpPort: int("smtpPort"),
|
||||||
/** Sécurité SMTP (TLS, SSL, None) */
|
/** Sécurité SMTP (TLS, SSL, None) */
|
||||||
smtpSecure: mysqlEnum("smtpSecure", ["tls", "ssl", "none"]),
|
smtpSecure: mysqlEnum("smtpSecure", ["none", "tls", "ssl"]),
|
||||||
/** Utilisateur SMTP */
|
/** Utilisateur SMTP */
|
||||||
smtpUser: varchar("smtpUser", { length: 255 }),
|
smtpUser: varchar("smtpUser", { length: 320 }),
|
||||||
/** Mot de passe SMTP */
|
/** Mot de passe SMTP */
|
||||||
smtpPassword: varchar("smtpPassword", { length: 255 }),
|
smtpPassword: text("smtpPassword"),
|
||||||
/** Email expéditeur */
|
/** Email expéditeur */
|
||||||
fromEmail: varchar("fromEmail", { length: 320 }).notNull(),
|
fromEmail: varchar("fromEmail", { length: 320 }).notNull(),
|
||||||
/** Nom de l'expéditeur */
|
/** Nom de l'expéditeur */
|
||||||
fromName: varchar("fromName", { length: 255 }).notNull(),
|
fromName: varchar("fromName", { length: 255 }).default("Formation Manager Itinova").notNull(),
|
||||||
/** Mode de fonctionnement (simulation ou production) */
|
/** Mode de fonctionnement (simulation ou production) */
|
||||||
mode: mysqlEnum("mode", ["simulation", "production"]).default("simulation").notNull(),
|
mode: mysqlEnum("mode", ["simulation", "production"]).default("simulation").notNull(),
|
||||||
|
/** Domaine vérifié */
|
||||||
|
domainVerified: boolean("domainVerified").default(false).notNull(),
|
||||||
|
/** Configuration active */
|
||||||
|
active: boolean("active").default(true).notNull(),
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -398,7 +398,9 @@ export const appRouter = router({
|
|||||||
// Mettre à jour la séquence
|
// Mettre à jour la séquence
|
||||||
const updateData: any = {
|
const updateData: any = {
|
||||||
...sequenceData,
|
...sequenceData,
|
||||||
dateBlocage: parseLocalDateTime(sequenceData.dateBlocage),
|
dateBlocage: sequenceData.dateBlocage && sequenceData.dateBlocage.trim() !== ''
|
||||||
|
? parseLocalDateTime(sequenceData.dateBlocage)
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[UPDATE SEQUENCE] UpdateData:', JSON.stringify(updateData, null, 2));
|
console.log('[UPDATE SEQUENCE] UpdateData:', JSON.stringify(updateData, null, 2));
|
||||||
|
|||||||
6
todo.md
6
todo.md
@@ -801,3 +801,9 @@
|
|||||||
- [ ] Modifier l'enum dans la base de données
|
- [ ] Modifier l'enum dans la base de données
|
||||||
- [ ] Mettre à jour le code frontend
|
- [ ] Mettre à jour le code frontend
|
||||||
- [ ] Créer le template par défaut
|
- [ ] Créer le template par défaut
|
||||||
|
- [x] Corriger le bug de mise à jour du type de template lors du changement de sélection dans AdminEmailTemplates.tsx
|
||||||
|
- [x] Corriger le bug nécessitant deux clics pour mettre à jour le template (ajout de key pour forcer remontage)
|
||||||
|
- [x] Corriger l'erreur SQL dans la modification de configuration SMTP (correction du schéma emailConfig)
|
||||||
|
- [x] Corriger l'erreur de type dans la modification des séquences (formateurId string au lieu de number)
|
||||||
|
- [x] Corriger la conservation de la date de blocage lors de la modification des séquences (ajout du champ dans le schéma Drizzle)
|
||||||
|
- [x] Corriger les rappels envoyés plusieurs fois et l'historique vide (nettoyage de la table logsRappels)
|
||||||
|
|||||||
Reference in New Issue
Block a user