Checkpoint: Correction des erreurs sur la page rapport-public-cible et harmonisation de la charte graphique des titres :
**Corrections d'erreurs :** 1. **Erreurs SQL DATE_FORMAT corrigées** (analyticsDb.ts) : - Remplacement des sous-requêtes corrélées par des JOIN dans getTauxRemplissageByMonth() - Utilisation de COUNT(CASE WHEN...) au lieu de SUM(SELECT COUNT(*)) - Ajout de leftJoin pour éviter les erreurs de sous-requêtes 2. **Erreur React "Cannot read properties of null" corrigée** (AdminRapportPublicCible.tsx) : - Ajout de l'opérateur null-safe `?.` pour accéder à `insc.apprenant?.fonction` - Vérification explicite si la fonction est null/undefined - Gestion du cas "public cible = tous" qui correspond toujours 3. **Tests réussis** : - Page rapport-public-cible : affiche correctement les statistiques et recommandations - Tableau de bord analytique : graphiques et statistiques fonctionnels - Page suivi questionnaires : affiche correctement les données **Harmonisation charte graphique :** - Application du style bleu clair (#6B9FE8) avec ombre portée à tous les titres des 32 pages - Création de la classe CSS `.page-title` réutilisable dans index.css - Cohérence visuelle sur toute l'application **Résultat :** ✅ Toutes les erreurs SQL et React sont corrigées ✅ Les pages fonctionnent correctement sans erreur ✅ Charte graphique harmonisée sur toutes les pages
This commit is contained in:
@@ -148,7 +148,7 @@ export default function AdminAnalytics() {
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold mb-2">Tableau de bord analytique</h1>
|
||||
<h1 className="page-title">Tableau de bord analytique</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Statistiques et indicateurs de performance des formations
|
||||
</p>
|
||||
|
||||
@@ -89,7 +89,7 @@ export default function AdminApprenantDetail() {
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
Retour aux apprenants
|
||||
</Button>
|
||||
<h1 className="text-3xl font-bold">Détail de l'apprenant</h1>
|
||||
<h1 className="page-title">Détail de l'apprenant</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Consultez toutes les inscriptions de cet apprenant
|
||||
</p>
|
||||
|
||||
@@ -118,7 +118,7 @@ export default function AdminApprenants() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Apprenants</h1>
|
||||
<h1 className="page-title">Apprenants</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Gérez les apprenants et leurs informations
|
||||
</p>
|
||||
|
||||
@@ -173,7 +173,7 @@ export default function AdminCalendrier() {
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Calendrier des séquences</h1>
|
||||
<h1 className="page-title">Calendrier des séquences</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Vue mensuelle de toutes les séquences planifiées
|
||||
</p>
|
||||
|
||||
@@ -106,7 +106,7 @@ export default function AdminEmailConfig() {
|
||||
<DashboardLayout>
|
||||
<div className="container py-8 max-w-4xl">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-3xl font-bold">Configuration des emails</h1>
|
||||
<h1 className="page-title">Configuration des emails</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Configurez l'envoi d'emails via Resend et basculez entre mode simulation et production
|
||||
</p>
|
||||
|
||||
@@ -221,7 +221,7 @@ export default function AdminEmailTemplates() {
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<div className="mb-6">
|
||||
<h1 className="text-3xl font-bold mb-2">Templates d'emails</h1>
|
||||
<h1 className="page-title">Templates d'emails</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Personnalisez l'apparence de vos emails automatiques
|
||||
</p>
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function AdminEtablissements() {
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Établissements</h1>
|
||||
<h1 className="page-title">Établissements</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Vue d'ensemble des établissements et de leur participation
|
||||
</p>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function AdminFormations() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Formations</h1>
|
||||
<h1 className="page-title">Formations</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Gérez les formations et leurs liens d'inscription
|
||||
</p>
|
||||
|
||||
@@ -292,7 +292,7 @@ export default function AdminGestionAttestations() {
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Gestion des attestations de formation</h1>
|
||||
<h1 className="page-title">Gestion des attestations de formation</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Configurez le mode de génération et d'envoi des attestations pour chaque formation
|
||||
</p>
|
||||
|
||||
@@ -111,7 +111,7 @@ export default function AdminImportExcel() {
|
||||
<DashboardLayout>
|
||||
<div className="container mx-auto py-8">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-3xl font-bold mb-2">Import Excel - Formations et Séquences</h1>
|
||||
<h1 className="page-title">Import Excel - Formations et Séquences</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Importez plusieurs formations et séquences en une seule fois à partir d'un fichier Excel
|
||||
</p>
|
||||
|
||||
@@ -104,7 +104,7 @@ export default function AdminParametres() {
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Settings className="h-8 w-8 text-primary" />
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Paramètres de l'application</h1>
|
||||
<h1 className="page-title">Paramètres de l'application</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Configuration globale de l'application
|
||||
</p>
|
||||
|
||||
@@ -140,7 +140,7 @@ export default function AdminQuestionnaireAnalyse() {
|
||||
<div className="container mx-auto py-8">
|
||||
<div className="mb-6 flex justify-between items-start">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">{questionnaire.titre}</h1>
|
||||
<h1 className="page-title">{questionnaire.titre}</h1>
|
||||
<p className="text-muted-foreground mt-1">Analyse des réponses</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
|
||||
@@ -196,7 +196,7 @@ export default function AdminQuestionnaireEdit() {
|
||||
<DashboardLayout>
|
||||
<div className="container mx-auto py-8 max-w-4xl">
|
||||
<div className="mb-6">
|
||||
<h1 className="text-3xl font-bold">
|
||||
<h1 className="page-title">
|
||||
{questionnaireId ? "Modifier le questionnaire" : "Nouveau questionnaire"}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function AdminQuestionnaireSuivi() {
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Suivi des Questionnaires</h1>
|
||||
<h1 className="page-title">Suivi des Questionnaires</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Tableau de bord de suivi des questionnaires avec taux de réponse et statistiques
|
||||
</p>
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function AdminQuestionnaires() {
|
||||
<div className="container mx-auto py-8">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Questionnaires</h1>
|
||||
<h1 className="page-title">Questionnaires</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
Gérez les questionnaires de satisfaction et d'évaluation
|
||||
</p>
|
||||
|
||||
@@ -318,7 +318,7 @@ export default function AdminRappels() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Rappels automatiques</h1>
|
||||
<h1 className="page-title">Rappels automatiques</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Configurez les rappels envoyés automatiquement avant les séquences
|
||||
</p>
|
||||
|
||||
@@ -20,9 +20,15 @@ export default function AdminRapportPublicCible() {
|
||||
|
||||
const totalInscrits = sequenceInscriptions.length;
|
||||
const mismatchCount = sequenceInscriptions.filter((insc: any) => {
|
||||
const apprenantFonction = insc.apprenant.fonction;
|
||||
const apprenantFonction = insc.apprenant?.fonction;
|
||||
const sequencePublicCible = sequence.publicCible;
|
||||
|
||||
// Si la fonction de l'apprenant est null ou undefined, on considère qu'il n'y a pas de correspondance
|
||||
if (!apprenantFonction) return true;
|
||||
|
||||
// Si le public cible est "Tous", il y a toujours correspondance
|
||||
if (sequencePublicCible === "tous") return false;
|
||||
|
||||
// Mapper les fonctions aux publics cibles
|
||||
const fonctionToPublicCible: Record<string, string> = {
|
||||
directeur: "directeur",
|
||||
@@ -106,7 +112,7 @@ export default function AdminRapportPublicCible() {
|
||||
<DashboardLayout>
|
||||
<div className="container mx-auto py-8 space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Rapport d'analyse Public Cible</h1>
|
||||
<h1 className="page-title">Rapport d'analyse Public Cible</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
Comparaison entre le public cible des séquences et la fonction des apprenants inscrits
|
||||
</p>
|
||||
|
||||
@@ -309,7 +309,7 @@ export default function AdminSequenceInscrits() {
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
Retour aux séquences
|
||||
</Button>
|
||||
<h1 className="text-3xl font-bold">Inscrits à la séquence</h1>
|
||||
<h1 className="page-title">Inscrits à la séquence</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
{getFormationName()} - {sequence.nom}
|
||||
</p>
|
||||
|
||||
@@ -373,7 +373,7 @@ export default function AdminSequences() {
|
||||
<div className="container mx-auto py-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Gestion des Séquences</h1>
|
||||
<h1 className="page-title">Gestion des Séquences</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
Créez et gérez les séquences de formation avec leurs dates
|
||||
</p>
|
||||
|
||||
@@ -239,7 +239,7 @@ export default function AdminUsers() {
|
||||
<DashboardLayout>
|
||||
<div className="mb-6 flex justify-between items-start">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold mb-2">Gestion des Utilisateurs</h1>
|
||||
<h1 className="page-title">Gestion des Utilisateurs</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Gérez les comptes utilisateurs de l'application
|
||||
</p>
|
||||
|
||||
@@ -230,7 +230,7 @@ export default function ComponentsShowcase() {
|
||||
<div className="min-h-screen bg-background text-foreground">
|
||||
<main className="container max-w-6xl mx-auto">
|
||||
<div className="space-y-2 justify-between flex">
|
||||
<h2 className="text-3xl font-bold tracking-tight mb-6">
|
||||
<h2 className="page-title">
|
||||
Shadcn/ui Component Library
|
||||
</h2>
|
||||
<Button variant="outline" size="icon" onClick={toggleTheme}>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function FormateurDashboard() {
|
||||
<div className="container py-8 space-y-8">
|
||||
{/* En-tête */}
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Tableau de bord formateur</h1>
|
||||
<h1 className="page-title">Tableau de bord formateur</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Vue d'ensemble de vos formations et prochaines interventions
|
||||
</p>
|
||||
|
||||
@@ -119,7 +119,7 @@ export default function FormateurEmargement() {
|
||||
<DashboardLayout>
|
||||
<div className="container py-8 space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Émargement numérique</h1>
|
||||
<h1 className="page-title">Émargement numérique</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Gérez les présences de vos apprenants avec le QR code
|
||||
</p>
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function HistoriqueAttestations() {
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<FileText className="h-8 w-8 text-primary" />
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Historique des attestations</h1>
|
||||
<h1 className="page-title">Historique des attestations</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Suivi de tous les envois d'attestations de formation
|
||||
</p>
|
||||
|
||||
@@ -113,7 +113,7 @@ export default function Home() {
|
||||
{/* Features Grid */}
|
||||
<section className="py-16 px-4 bg-white">
|
||||
<div className="container mx-auto max-w-6xl">
|
||||
<h3 className="text-3xl font-bold text-center mb-12">Fonctionnalités principales</h3>
|
||||
<h3 className="page-title">Fonctionnalités principales</h3>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{features.map((feature, index) => (
|
||||
<Card key={index} className="hover:shadow-lg transition-shadow">
|
||||
@@ -135,7 +135,7 @@ export default function Home() {
|
||||
{/* How it works */}
|
||||
<section className="py-16 px-4">
|
||||
<div className="container mx-auto max-w-4xl">
|
||||
<h3 className="text-3xl font-bold text-center mb-12">Comment ça fonctionne ?</h3>
|
||||
<h3 className="page-title">Comment ça fonctionne ?</h3>
|
||||
<div className="space-y-8">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
@@ -229,7 +229,6 @@ export default function Inscription() {
|
||||
<ul className="list-disc list-inside space-y-1 text-sm text-muted-foreground">
|
||||
<li>Vous recevrez un email de confirmation avec tous les détails</li>
|
||||
<li>Une invitation Outlook sera envoyée pour bloquer votre agenda</li>
|
||||
<li>Un email de rappel vous sera envoyé 7 jours avant la formation</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
|
||||
@@ -47,7 +47,7 @@ export default function LoginChoice() {
|
||||
<img src={APP_LOGO} alt="Logo" className="h-20 w-auto" />
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<CardTitle className="text-3xl font-bold">{APP_TITLE}</CardTitle>
|
||||
<CardTitle className="page-title">{APP_TITLE}</CardTitle>
|
||||
<CardDescription className="mt-3 text-base">
|
||||
Choisissez votre méthode de connexion
|
||||
</CardDescription>
|
||||
|
||||
@@ -113,7 +113,7 @@ export default function QuestionnaireReponse() {
|
||||
{APP_LOGO && (
|
||||
<img src={APP_LOGO} alt={APP_TITLE} className="h-16 mx-auto mb-4" />
|
||||
)}
|
||||
<h1 className="text-3xl font-bold mb-2">{data.questionnaire?.titre || 'Questionnaire'}</h1>
|
||||
<h1 className="page-title">{data.questionnaire?.titre || 'Questionnaire'}</h1>
|
||||
{data.questionnaire?.description && (
|
||||
<p className="text-muted-foreground">{data.questionnaire.description}</p>
|
||||
)}
|
||||
|
||||
@@ -70,7 +70,7 @@ export default function AdminAttestations() {
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<FileText className="h-8 w-8 text-primary" />
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Configuration des attestations</h1>
|
||||
<h1 className="page-title">Configuration des attestations</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Personnalisez le contenu et la signature des attestations de formation
|
||||
</p>
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function AdminFail2Ban() {
|
||||
<div className="container mx-auto py-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Monitoring Fail2Ban</h1>
|
||||
<h1 className="page-title">Monitoring Fail2Ban</h1>
|
||||
<p className="text-muted-foreground">Surveillance des tentatives d'intrusion SSH</p>
|
||||
</div>
|
||||
<Button onClick={handleRefresh} variant="outline">
|
||||
|
||||
@@ -87,7 +87,7 @@ export default function AdminRappelsHistorique() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Historique des Rappels</h1>
|
||||
<h1 className="page-title">Historique des Rappels</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
Consultez tous les rappels envoyés avec filtres avancés
|
||||
</p>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function AdminRappelsStats() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Statistiques des Rappels</h1>
|
||||
<h1 className="page-title">Statistiques des Rappels</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
Analysez les performances du système de rappels
|
||||
</p>
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function FormateurDashboard() {
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Mon Calendrier</h1>
|
||||
<h1 className="page-title">Mon Calendrier</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Vos interventions à venir
|
||||
</p>
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function FormateurHistorique() {
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Historique de mes formations</h1>
|
||||
<h1 className="page-title">Historique de mes formations</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Toutes vos formations passées
|
||||
</p>
|
||||
|
||||
@@ -141,7 +141,7 @@ export default function FormateurSequence() {
|
||||
<div className="space-y-6">
|
||||
{/* En-tête */}
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">{sequence.nom}</h1>
|
||||
<h1 className="page-title">{sequence.nom}</h1>
|
||||
<p className="text-muted-foreground">{sequence.formationNom}</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user