# Optimisation de l'affichage des congés ## Résumé des modifications Les congés et activités ont été optimisés pour prendre moins de place et être plus visuels dans le **Calendrier mensuel** et le **Dashboard**. --- ## 🎯 Objectifs ### 1. **Calendrier mensuel** (`MonthlyCalendarScreen`) - **Avant** : Chaque personne en congé prenait une ligne complète - **Après** : Les congés du même type sont regroupés sur une seule ligne avec des pastilles de couleur ### 2. **Dashboard** (`DashboardScreen` + `TimeGridMulti`) - **Avant** : Pas d'indication de congé visible - **Après** : Badge "Congé" ou "Vacances" affiché à côté du nom de la personne dans la colonne --- ## ✅ Modifications effectuées ### 1. Calendrier mensuel - Regroupement des congés #### Fichier modifié : `frontend/src/screens/MonthlyCalendarScreen.js` **Ajout de nouveaux composants styled :** ```javascript const GroupedHolidayMarker = styled.div ` display: flex; align-items: center; gap: 8px; font-size: 0.75rem; color: #b8c0ff; padding: 4px 6px; background: rgba(125, 108, 255, 0.1); border-radius: 4px; font-style: italic; `; const HolidayColorDots = styled.div ` display: flex; gap: 3px; align-items: center; `; const HolidayDot = styled.div ` width: 12px; height: 12px; border-radius: 50%; background: ${({ $color }) => $color}; border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 0 4px ${({ $color }) => `${$color}66`}; `; ``` **Nouvelle logique d'affichage (lignes 489-507) :** ```javascript // Regrouper les congés par type const publicHolidays = dateHolidays.filter(h => h.type === "public"); const schoolHolidays = dateHolidays.filter(h => h.type === "school"); const personalLeaves = dateHolidays.filter(h => h.type === "personal"); // Jours fériés publics (affichés normalement) publicHolidays.map((holiday, idx) => ( 🎉 {holiday.label} )) // Vacances scolaires (regroupées) schoolHolidays.length > 0 && ( Vacances {schoolHolidays.map((holiday, idx) => ( ))} ) // Congés personnels (regroupés) personalLeaves.length > 0 && ( Congé {personalLeaves.map((holiday, idx) => ( ))} ) ``` **Résultat visuel :** ``` ┌─────────────────────────────────┐ │ Mar 15/01 │ ├─────────────────────────────────┤ │ 🎉 Nouvel An │ ← Jour férié (normal) │ Vacances ● ● ● │ ← 3 enfants en vacances (1 ligne) │ Congé ● ● │ ← 2 parents en congé (1 ligne) └─────────────────────────────────┘ ``` --- ### 2. Dashboard - Badge de congé dans les colonnes #### Fichier modifié : `frontend/src/screens/DashboardScreen.js` **Ajout des imports (ligne 8) :** ```javascript import { apiClient, listParents, listGrandParents, getHolidays, getPublicHolidays, getPersonalLeaves } from "../services/api-client"; ``` **Ajout des états (lignes 142-143) :** ```javascript const [holidays, setHolidays] = useState([]); const [personalLeaves, setPersonalLeaves] = useState([]); ``` **Chargement des congés (lignes 264-286) :** ```javascript useEffect(() => { const loadHolidaysAndLeaves = async () => { try { // Charger les vacances scolaires const regions = [...new Set(children.map(c => c.schoolRegion).filter(Boolean))]; const holidayPromises = regions.map(region => getHolidays(region, today.getFullYear()).catch(() => ({ holidays: [] })) ); const holidayResults = await Promise.all(holidayPromises); const allHolidays = holidayResults.flatMap(r => r.holidays); // Charger les jours fériés const publicHolidaysResult = await getPublicHolidays(today.getFullYear()) .catch(() => ({ holidays: [] })); // Combiner et dédupliquer const combinedHolidays = [...allHolidays, ...publicHolidaysResult.holidays]; const uniqueHolidays = Array.from( new Map(combinedHolidays.map(h => [h.id, h])).values() ); setHolidays(uniqueHolidays); // Charger les congés personnels const leavePromises = selectedProfiles.map(profileId => getPersonalLeaves(profileId).catch(() => ({ leaves: [] })) ); const leaveResults = await Promise.all(leavePromises); const allLeaves = leaveResults.flatMap(r => r.leaves); setPersonalLeaves(allLeaves); } catch (error) { console.warn("Erreur lors du chargement des congés", error); } }; void loadHolidaysAndLeaves(); }, [children, selectedProfiles, today]); ``` **Modification de profileColumns pour inclure vacationStatus (lignes 430-497) :** ```javascript const profileColumns = useMemo(() => { const selected = new Set(selectedProfiles); const todayISO = today.toISOString().slice(0, 10); const todayDate = new Date(todayISO); return allProfiles .filter((profile) => selected.has(profile.id)) .map((profile) => { // ... code existant ... // Vérifier si le profil est en congé aujourd'hui let vacationStatus = null; // Vérifier les vacances scolaires pour les enfants if (profile.kind === "child") { const child = children.find(c => c.id === profile.id); if (child?.schoolRegion) { const schoolHoliday = holidays.find(h => { if (h.type !== "school") return false; if (!h.zones || !h.zones.includes(child.schoolRegion)) return false; const start = new Date(h.startDate); const end = new Date(h.endDate); return todayDate >= start && todayDate <= end; }); if (schoolHoliday) { vacationStatus = "Vacances"; } } } // Vérifier les congés personnels pour tous les profils const personalLeave = personalLeaves.find(leave => { if (leave.profileId !== profile.id) return false; const start = new Date(leave.startDate); const end = new Date(leave.endDate); return todayDate >= start && todayDate <= end; }); if (personalLeave) { vacationStatus = "Congé"; } return { // ... autres propriétés ... vacationStatus // ← Nouvelle propriété }; }); }, [allProfiles, selectedProfiles, dayEventsMap, children, holidays, personalLeaves, today]); ``` #### Fichier modifié : `frontend/src/components/TimeGridMulti.js` **Ajout du composant styled VacationBadge (lignes 42-51) :** ```javascript const VacationBadge = styled.span ` padding: 2px 8px; border-radius: 999px; background: ${({ $color }) => `${$color}33`}; border: 1px solid ${({ $color }) => `${$color}66`}; color: #e9ebff; font-size: 0.75rem; font-weight: 600; margin-left: auto; `; ``` **Modification du ColHeader (lignes 32-40) :** ```javascript const ColHeader = styled.div ` padding: 10px 12px; border-bottom: 1px solid rgba(126, 136, 180, 0.22); font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; // ← Ajouté pour permettre le retour à la ligne `; ``` **Affichage du badge dans le header (ligne 136) :** ```javascript {/* Avatar et nom */} {col.avatarUrl ? : ...} {col.link ? {col.title} : {col.title}} {/* Badge de congé */} {col.vacationStatus ? ( {col.vacationStatus} ) : null} ``` **Résultat visuel :** ``` ┌──────────────────────────────────────┐ │ 👤 Robert Hérault [Congé] │ ← Badge à droite du nom ├──────────────────────────────────────┤ │ 08:00 ────────────────────────── │ │ 09:00 ────────────────────────── │ │ ... │ └──────────────────────────────────────┘ ``` --- ## 🎨 Améliorations visuelles ### Calendrier mensuel | Avant | Après | |-------|-------| | 4 lignes pour 4 personnes en congé | 1 ligne avec 4 pastilles de couleur | | Beaucoup d'espace perdu | Plus de place pour les activités | | Difficile de voir d'un coup d'œil | Vue d'ensemble immédiate | **Exemple concret :** **AVANT** (4 lignes) : ``` Timéo Hérault - Vacances Gabriel Hérault - Vacances Robert Hérault - Congé Martine Hérault - Congé ``` **APRÈS** (2 lignes) : ``` Vacances ●🔵 ●🟢 (2 pastilles) Congé ●🔴 ●🟡 (2 pastilles) ``` ### Dashboard **AVANT** : ``` ┌─────────────────────┐ │ Robert Hérault │ ← Aucune indication ├─────────────────────┤ ``` **APRÈS** : ``` ┌──────────────────────────┐ │ Robert Hérault [Congé] │ ← Badge visible ├──────────────────────────┤ ``` --- ## 📊 Avantages de l'optimisation ### 1. **Gain d'espace** - Calendrier : **Réduction de 75%** de l'espace utilisé pour les congés multiples - Dashboard : Information compacte sur une ligne ### 2. **Meilleure lisibilité** - Vue d'ensemble immédiate avec les couleurs - Identification rapide des personnes en congé - Plus d'espace pour les vraies activités ### 3. **Ergonomie améliorée** - Moins de scroll nécessaire - Information contextuelle sans surcharger - Design plus moderne et épuré ### 4. **Cohérence visuelle** - Les couleurs des profils sont utilisées partout - Style uniforme entre calendrier et dashboard - Pastilles visibles au survol (title attribute) --- ## 🔧 Détails techniques ### Types de congés gérés 1. **Jours fériés publics** (`type: "public"`) - Affichés normalement avec 🎉 - Couleur : `#ffa726` (orange) - Non regroupés (un seul par jour généralement) 2. **Vacances scolaires** (`type: "school"`) - Regroupées sur une ligne "Vacances" - Pastilles avec couleur de chaque enfant - Filtré par zone scolaire 3. **Congés personnels** (`type: "personal"`) - Regroupés sur une ligne "Congé" - Pastilles avec couleur de chaque profil (parent/grand-parent) - Stockés dans le champ `vacations` du profil ### Logique de détection ```javascript // Pour une date donnée const todayDate = new Date(dateISO); // Vérifier si dans la plage const start = new Date(holiday.startDate); const end = new Date(holiday.endDate); const isInRange = todayDate >= start && todayDate <= end; ``` ### Performances - Calcul uniquement pour les profils sélectionnés - Mise en cache via `useMemo` pour éviter les recalculs - Chargement asynchrone des données de congés --- ## 📝 Fichiers modifiés ### Créés - ✅ `OPTIMISATION_AFFICHAGE_CONGES.md` (ce document) ### Modifiés 1. ✅ `frontend/src/screens/MonthlyCalendarScreen.js` - Lignes 194-219 : Nouveaux composants styled - Lignes 489-507 : Logique de regroupement 2. ✅ `frontend/src/screens/DashboardScreen.js` - Ligne 8 : Imports des APIs de congés - Lignes 142-143 : États holidays et personalLeaves - Lignes 264-286 : useEffect pour charger les congés - Lignes 430-497 : Ajout de vacationStatus dans profileColumns 3. ✅ `frontend/src/components/TimeGridMulti.js` - Lignes 32-40 : Modification de ColHeader (flex-wrap) - Lignes 42-51 : Nouveau composant VacationBadge - Ligne 136 : Affichage conditionnel du badge --- ## 🚀 Pour tester 1. **Ajouter des congés** : - Aller sur le profil d'un parent ou grand-parent - Section "Congés" → Ajouter une période incluant aujourd'hui 2. **Configurer les zones scolaires** : - Aller sur le profil d'un enfant - Section "Congés scolaires" → Sélectionner une zone 3. **Vérifier le calendrier mensuel** : - Naviguer vers "Calendrier mensuel" - Vérifier que plusieurs congés le même jour sont regroupés - Survoler les pastilles pour voir les noms 4. **Vérifier le dashboard** : - Aller sur "Agenda familial" - Vue "Vue générale" - Vérifier les badges "Congé" ou "Vacances" à côté des noms --- ## ✨ Résultat final Les congés sont maintenant affichés de manière **compacte, visuelle et ergonomique** : - **Calendrier** : 1 ligne "Vacances" + 1 ligne "Congé" au lieu de X lignes individuelles - **Dashboard** : Badge discret mais visible à côté du nom - **Couleurs** : Identification immédiate grâce aux pastilles colorées - **Espace** : Plus de place pour les vraies activités et événements 🎉 **Objectif atteint : Optimisation réussie !**