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,
|
||||
onUpdate: ({ editor }) => {
|
||||
setFormData({ ...formData, bodyContent: editor.getHTML() });
|
||||
setFormData((prev) => ({ ...prev, bodyContent: editor.getHTML() }));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -101,11 +101,18 @@ export default function AdminEmailTemplates() {
|
||||
};
|
||||
setFormData(newData);
|
||||
// Mettre à jour le contenu de l'éditeur
|
||||
if (editor) {
|
||||
if (editor && !editor.isDestroyed) {
|
||||
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 = () => {
|
||||
upsertMutation.mutate({
|
||||
@@ -273,7 +280,7 @@ export default function AdminEmailTemplates() {
|
||||
</Card>
|
||||
|
||||
{/* Formulaire d'édition */}
|
||||
<Card className="lg:col-span-2">
|
||||
<Card key={selectedType} className="lg:col-span-2">
|
||||
<CardHeader>
|
||||
<CardTitle>Éditer le template</CardTitle>
|
||||
<CardDescription>
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function AdminSequences() {
|
||||
|
||||
// Convertir une date locale (datetime-local) en ISO UTC
|
||||
const convertLocalToUTC = (localDateStr: string): string => {
|
||||
if (!localDateStr) return localDateStr;
|
||||
if (!localDateStr || localDateStr.trim() === '') return '';
|
||||
// datetime-local retourne "YYYY-MM-DDTHH:mm"
|
||||
// On doit le traiter comme heure locale et le convertir en UTC
|
||||
const localDate = new Date(localDateStr);
|
||||
@@ -185,7 +185,7 @@ export default function AdminSequences() {
|
||||
capaciteMax: parseInt(formData.capaciteMax),
|
||||
dateBlocage: convertLocalToUTC(formData.dateBlocage),
|
||||
statut: formData.statut,
|
||||
formateurId: formData.formateur,
|
||||
formateurId: formData.formateur ? parseInt(formData.formateur) : null,
|
||||
dates: formData.dates.map(d => ({
|
||||
...d,
|
||||
dateDebut: convertLocalToUTC(d.dateDebut),
|
||||
|
||||
@@ -83,6 +83,8 @@ export const sequences = mysqlTable("sequences", {
|
||||
publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre", "tous"]).default("tous").notNull(),
|
||||
/** ID du formateur assigné à cette séquence */
|
||||
formateurId: int("formateurId"),
|
||||
/** Date limite d'inscription (blocage) */
|
||||
dateBlocage: datetime("dateBlocage"),
|
||||
/** Token unique pour le QR code d'émargement */
|
||||
qrCodeToken: varchar("qrCodeToken", { length: 100 }).unique(),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
@@ -149,24 +151,28 @@ export const emailConfig = mysqlTable("emailConfig", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
/** Provider d'envoi d'emails (resend, smtp, simulation) */
|
||||
provider: mysqlEnum("provider", ["resend", "smtp", "simulation"]).default("simulation").notNull(),
|
||||
/** Clé API Resend */
|
||||
resendApiKey: varchar("resendApiKey", { length: 255 }),
|
||||
/** Clé API (pour Resend ou autres) */
|
||||
apiKey: text("apiKey"),
|
||||
/** Hôte SMTP */
|
||||
smtpHost: varchar("smtpHost", { length: 255 }),
|
||||
/** Port SMTP */
|
||||
smtpPort: int("smtpPort"),
|
||||
/** Sécurité SMTP (TLS, SSL, None) */
|
||||
smtpSecure: mysqlEnum("smtpSecure", ["tls", "ssl", "none"]),
|
||||
smtpSecure: mysqlEnum("smtpSecure", ["none", "tls", "ssl"]),
|
||||
/** Utilisateur SMTP */
|
||||
smtpUser: varchar("smtpUser", { length: 255 }),
|
||||
smtpUser: varchar("smtpUser", { length: 320 }),
|
||||
/** Mot de passe SMTP */
|
||||
smtpPassword: varchar("smtpPassword", { length: 255 }),
|
||||
smtpPassword: text("smtpPassword"),
|
||||
/** Email expéditeur */
|
||||
fromEmail: varchar("fromEmail", { length: 320 }).notNull(),
|
||||
/** 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: 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(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
@@ -398,7 +398,9 @@ export const appRouter = router({
|
||||
// Mettre à jour la séquence
|
||||
const updateData: any = {
|
||||
...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));
|
||||
|
||||
6
todo.md
6
todo.md
@@ -801,3 +801,9 @@
|
||||
- [ ] Modifier l'enum dans la base de données
|
||||
- [ ] Mettre à jour le code frontend
|
||||
- [ ] 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