1. Bug décalage horaire dans le formulaire d'édition des séquences
- Correction de la fonction safeFormatDate pour utiliser les méthodes locales (getHours, getMinutes) au lieu des méthodes UTC
- Les heures saisies (ex: 9h00) s'affichent maintenant correctement dans le formulaire d'édition
2. Ajout du menu de navigation sur la page Import Excel
- Intégration du DashboardLayout wrapper dans AdminImportExcel.tsx
- Le menu latéral s'affiche maintenant correctement sur cette page
3. Déplacement du menu "Import Excel"
- Déplacé du bloc GESTION vers le bloc CONFIGURATION dans le menu de navigation
- Positionné après "Utilisateurs" et avant "Rappels" pour une meilleure organisation
- Ajout de la valeur "tous" dans l'enum publicCible du schéma drizzle/schema.ts
- Mise à jour des validations Zod dans server/routers.ts
- Modification directe de la colonne publicCible en base de données via SQL
- Test réussi : création d'une séquence avec public cible "Tous" fonctionne parfaitement
Corrections apportées:
- Utilisation de clés stables (format yyyy-MM-dd) au lieu de day.toISOString() pour éviter l'erreur React #31
- Gestion correcte des objets Date vs strings pour dateBloquage dans le modal
- Gestion correcte du champ formateur qui peut être un objet ou une string
- Ajout de clés uniques pour les dates de formation dans le modal
Le calendrier fonctionne maintenant sans erreur lors du survol et de l'ouverture des modals de détails.
Modification apportée :
- Le champ email est maintenant modifiable pour l'utilisateur adminServFormation
- Mise à jour du message dans le formulaire d'édition : "Seuls l'email et le mot de passe peuvent être modifiés pour cet utilisateur"
- Les champs nom et identifiant restent en lecture seule (grisés et désactivés)
- Les champs email, mot de passe et rôle sont modifiables pour cet utilisateur spécial
Modifications apportées :
- Création de l'utilisateur "Administrateur" avec identifiant "adminServFormation" et mot de passe "Itinova69!" (hashé avec bcrypt)
- Modification de l'interface pour désactiver le bouton de suppression pour cet utilisateur (grisé avec tooltip explicatif)
- Modification du formulaire d'édition pour rendre les champs nom, email et identifiant en lecture seule (grisés et désactivés)
- Ajout d'un message explicatif dans le formulaire : "Seul le mot de passe peut être modifié pour cet utilisateur"
- Seuls les champs "Nouveau mot de passe" et "Rôle" restent modifiables pour cet utilisateur
- L'utilisateur est identifié par son username "adminServFormation" pour appliquer les restrictions
- Cet utilisateur ne peut pas être supprimé et ses informations de base ne peuvent pas être modifiées, garantissant un accès administrateur permanent au système
Modifications apportées :
- Ajout du champ username (identifiant de connexion) dans le schéma de la base de données avec contrainte UNIQUE
- Mise à jour des procédures tRPC create et update pour gérer username et password
- Implémentation du hashage du mot de passe avec bcryptjs dans createUser et updateUser
- Ajout de la colonne "Identifiant" dans le tableau de la page de gestion des utilisateurs
- Ajout des champs "Identifiant de connexion" et "Mot de passe" dans le formulaire de création
- Ajout des champs "Identifiant de connexion" et "Nouveau mot de passe" dans le formulaire d'édition avec notes explicatives
- Les mots de passe sont hashés avant d'être stockés en base de données pour la sécurité
- Dans le formulaire d'édition, les champs username et password sont optionnels (laissez vide pour ne pas modifier)
Problème identifié :
- La contrainte UNIQUE sur la colonne openId n'existait pas dans la base de données
- Tous les utilisateurs partageaient le même openId
- Chaque connexion créait un nouvel utilisateur au lieu de mettre à jour l'existant
- 344 utilisateurs en double ont été créés
Solution appliquée :
- Nettoyé 343 utilisateurs en double (gardé le plus récent pour chaque openId)
- Ajouté la contrainte UNIQUE sur la colonne openId via ALTER TABLE
- Maintenant onDuplicateKeyUpdate fonctionne correctement
Résultat :
- Plus aucun utilisateur en double ne sera créé
- À chaque connexion, l'utilisateur existant est mis à jour
- Table users propre avec seulement les utilisateurs uniques
✅ Nouvelle procédure tRPC `apprenants.getInscriptions` pour récupérer toutes les inscriptions d'un apprenant avec les détails de formation et séquence
✅ Nouvelle page AdminApprenantDetail (/admin/apprenants/:id) affichant :
- Informations personnelles de l'apprenant (nom, prénom, email, code établissement, fonction)
- Tableau complet de toutes ses inscriptions avec :
* Nom de la formation
* Nom de la séquence
* Toutes les dates de la séquence
* Lieu
* Public cible
* Date d'inscription
* Statut (avec badge coloré : vert pour confirmée, gris pour en attente, rouge pour annulée)
✅ Bouton "Détail" (icône œil) ajouté dans la colonne Actions de la page AdminApprenants
✅ Route /admin/apprenants/:id configurée dans App.tsx
✅ Bouton "Retour aux apprenants" pour navigation facile
Correction appliquée : La procédure getInscriptions extrait maintenant correctement l'objet inscription du résultat retourné par getInscriptionsByApprenant.
Tests réussis : Affichage correct des inscriptions pour l'apprenant "Nouveau Apprenant" (1 inscription à la séquence "Groupe A" avec statut confirmée).
✅ Champ de signature du formateur ajouté en bas de chaque page de feuille de présence
✅ Comprend :
- Label "Signature du formateur :" en gras
- Ligne pour la signature manuscrite (60mm de largeur)
- Champ "Date : _______________" pour dater la validation
Le formateur peut maintenant valider officiellement chaque journée de formation en signant et en datant la feuille de présence.
Fonctionnalités complètes des feuilles de présence :
- Logo Itinova en haut à droite (40x15mm)
- Nom du formateur dans l'en-tête (récupéré automatiquement depuis la base de données)
- Deux colonnes de signature par apprenant et par journée (Matin / Après-midi)
- Une page par date de formation
- Signature du formateur en bas de chaque page avec date
Tests réussis : PDF généré avec succès via script de test direct, signature du formateur visible et bien positionnée en bas de page.
✅ Logo Itinova ajouté en haut à droite de chaque page (40x15mm)
✅ Nom du formateur affiché dans l'en-tête (récupéré automatiquement depuis la base de données)
✅ Deux colonnes de signature par apprenant et par journée (Signature Matin / Signature Après-midi)
✅ Une page générée pour chaque date de formation
✅ Toutes les informations complètes : Formation, Séquence, Lieu, Formateur, Public cible, Date de la journée
✅ Tableau avec 6 colonnes : Nom, Prénom, Code établissement, Fonction, Signature Matin, Signature Après-midi
Corrections techniques :
- Utilisation de path.resolve(process.cwd()) au lieu de __dirname pour éviter l'erreur "ReferenceError: __dirname is not defined"
- Ajout du champ formateur dans l'interface FeuillePresenceInfo
- Récupération automatique du nom du formateur via formateurId dans la procédure exportFeuillePresence
Tests réussis : Génération testée avec la séquence "Groupe A" (formateur George Clooney, 2 dates) - PDF généré avec succès avec toutes les modifications visibles.
Corrections d'affichage du formateur :
- Correction du placeholder "Sélectionner un formateur (optionnel)" en "Sélectionner un formateur" dans le formulaire de modification de séquence
- Ajout d'une colonne "Formateur" dans le tableau de la liste des séquences
- Le formateur s'affiche maintenant dans la liste avec "-" si non assigné
Corrections d'affichage du nom de formation :
- Création de la fonction getSequencesWithFormation() qui récupère les informations de formation via jointure
- Mise à jour de la procédure sequences.list pour utiliser cette nouvelle fonction
- Le nom de la formation s'affiche maintenant correctement dans le calendrier et les détails de séquence
Nettoyage de la base de données :
- Suppression de tous les utilisateurs sauf les 4 spécifiés (IDs: 1110110, 2010001, 2040001, 2070001)
- La table utilisateurs ne contient maintenant que les utilisateurs autorisés
- Correction du placeholder du formateur dans le formulaire de modification de séquence (suppression de "(optionnel)")
- Ajout d'une colonne "Formateur" dans le tableau de la liste des séquences
- Le formateur s'affiche maintenant dans la liste avec "-" si non assigné
- Tests réussis : le placeholder est correct et la colonne formateur est visible
- Création de getSequencesWithFormation() pour récupérer les informations de formation
- Mise à jour de la procédure sequences.list pour utiliser la nouvelle fonction
- Correction de AdminCalendrier.tsx pour utiliser formation.nom au lieu de formation.titre
- Le nom de la formation s'affiche maintenant correctement dans le calendrier et dans le dialog de détails
- Vérification que le placeholder du FormateurCombobox est correct
✅ **1. Champ formateur dans nouvelle séquence**
Ajout du champ formateur avec autocomplétion dans le formulaire de création de séquence, permettant de sélectionner ou ajouter rapidement un formateur.
✅ **2. Placeholder du formateur**
Le placeholder affiche "Sélectionner un formateur" (déjà correct par défaut dans le composant).
✅ **3. Nom séquence + formation dans calendrier**
Le calendrier affiche maintenant le nom de la séquence ET le nom de la formation associée pour une meilleure identification visuelle.