From a2e0904132241edc78a5f1259e0e4b34e0452354 Mon Sep 17 00:00:00 2001 From: "fefe.clochette" Date: Thu, 3 Sep 2026 13:40:50 +0200 Subject: [PATCH] recap carole --- family-calendar.php | 57 ++- includes/lang/ca.php | 14 +- includes/lang/en.php | 14 +- includes/lang/fr.php | 14 +- mockup_epargne.html | 334 ----------------- modules/family-calendar/family-calendar.css | 163 +++++++-- modules/family-calendar/family-calendar.js | 382 +++++++++++++++++--- 7 files changed, 536 insertions(+), 442 deletions(-) delete mode 100644 mockup_epargne.html diff --git a/family-calendar.php b/family-calendar.php index 5e5eaa3..5f22102 100644 --- a/family-calendar.php +++ b/family-calendar.php @@ -207,7 +207,7 @@ require __DIR__ . '/header.php'; @@ -393,20 +393,32 @@ require __DIR__ . '/header.php'; - - + + - + + + + + + + + - + $parent): @@ -447,6 +459,19 @@ require __DIR__ . '/header.php'; + +
+
+
+ + + + + +
+
+ +

@@ -456,15 +481,22 @@ require __DIR__ . '/header.php';
- - -
Off
-
Extra
- + + $type): + ?> +
+
+ +
+ - + $mode): $modeLower = strtolower($mode); + if ($modeLower === 'nounou' && !empty($helpers)) continue; if ($modeLower === 'avis'): ?>
Avis @@ -483,9 +515,8 @@ require __DIR__ . '/header.php'; - +
diff --git a/includes/lang/ca.php b/includes/lang/ca.php index 6800ac7..d3042c8 100644 --- a/includes/lang/ca.php +++ b/includes/lang/ca.php @@ -300,6 +300,7 @@ return [ 'fc_weekly_planning' => 'Planificació setmanal', 'fc_col_month' => 'Mes', 'fc_col_week_short' => 'Set.', + 'fc_col_week' => 'Setmana', 'fc_col_av' => 'Av.', 'fc_col_use' => 'Use', 'fc_legend_title' => 'Llegenda', @@ -310,7 +311,7 @@ return [ 'fc_unit_days' => 'dies', 'fc_menu_carole' => 'Permisos Carole', 'fc_clear' => 'Esborrar', - 'fc_menu_kids_leaves' => 'Permisos nens', + 'fc_menu_kids_leaves' => 'Permisos pares', 'fc_err_save_snap' => 'Error en desar el correctiu.', 'fc_err_fetch_gov' => 'Error en la connexió amb l\'API governamental.', 'fc_err_no_data_gov' => 'No s\'han trobat dades a l\'API del govern per a aquest any.', @@ -342,6 +343,15 @@ return [ 'fc_add_mode_placeholder' => 'Ex: Mainadera, Casal, Avis...', 'fc_settings_updated' => 'Configuració actualitzada correctament!', 'fc_first_day' => 'Primer dia de la setmana', + 'fc_helper_recap' => 'Resum Interventor', + 'fc_no_helper_leaves' => 'Cap permís sol·licitat aquest mes.', + 'fc_col_date' => 'Data', + 'fc_col_type' => 'Tipus', + 'fc_col_duration' => 'Durada', + 'fc_full_year' => 'Any sencer', + 'fc_custom_period' => 'Període específic...', + 'fc_worked_days' => 'Treballats (Est.)', + // --- CALENDARI : PARÀMETRES (MEMBRES I VISUALITZACIÓ) --- 'fc_tab_display' => '🖥️ Visualització', 'fc_display_title' => 'Ajustos de visualització', @@ -456,7 +466,7 @@ return [ 'leg_extra_off' => 'Extra Off', 'leg_centre' => 'Casal', 'leg_avis' => 'Avís', - 'leg_pep_sick' => 'Pep Malalt', + 'fc_menu_sick' => 'Malalt', 'care_nounou' => 'Kangur', 'care_centre' => 'Casal', 'care_avis' => 'Avis', diff --git a/includes/lang/en.php b/includes/lang/en.php index 4426fc1..9e0632a 100644 --- a/includes/lang/en.php +++ b/includes/lang/en.php @@ -301,6 +301,7 @@ return [ 'fc_weekly_planning' => 'Weekly planning', 'fc_col_month' => 'Month', 'fc_col_week_short' => 'Wk.', + 'fc_col_week' => 'Week', 'fc_col_av' => 'Av.', 'fc_col_use' => 'Use', 'fc_legend_title' => 'Legend', @@ -311,7 +312,7 @@ return [ 'fc_unit_days' => 'days', 'fc_menu_carole' => 'Carole\'s Leave', 'fc_clear' => 'Clear', - 'fc_menu_kids_leaves' => 'Children\'s Leave', + 'fc_menu_kids_leaves' => 'Parent\'s Leave', 'fc_err_save_snap' => 'Error saving adjustment.', 'fc_err_fetch_gov' => 'Error connecting to the government API.', 'fc_err_no_data_gov' => 'No data found on the government API for this year.', @@ -343,6 +344,15 @@ return [ 'fc_add_mode_placeholder' => 'E.g., Nanny, Center, Grandparents...', 'fc_settings_updated' => 'Settings updated successfully!', 'fc_first_day' => 'First day of the week', + 'fc_helper_recap' => 'Helper Summary', + 'fc_no_helper_leaves' => 'No leaves taken this month.', + 'fc_col_date' => 'Date', + 'fc_col_type' => 'Type', + 'fc_col_duration' => 'Duration', + 'fc_full_year' => 'Full year', + 'fc_custom_period' => 'Custom period...', + 'fc_worked_days' => 'Worked (Est.)', + // --- CALENDAR: SETTINGS (MEMBERS & DISPLAY) --- 'fc_tab_display' => '🖥️ Display', 'fc_display_title' => 'Display Settings', @@ -457,7 +467,7 @@ return [ 'leg_extra_off' => 'Extra off', 'leg_centre' => 'Centre', 'leg_avis' => 'Notice', - 'leg_pep_sick' => 'Pep sick', + 'fc_menu_sick' => 'Sick', 'care_nounou' => 'Nanny', 'care_centre' => 'Daycare', 'care_avis' => 'Grandparents', diff --git a/includes/lang/fr.php b/includes/lang/fr.php index 51e9339..5a199e5 100644 --- a/includes/lang/fr.php +++ b/includes/lang/fr.php @@ -302,6 +302,7 @@ return [ 'fc_weekly_planning' => 'Planning hebdomadaire', 'fc_col_month' => 'Mois', 'fc_col_week_short' => 'Sem.', + 'fc_col_week' => 'Semaine', 'fc_col_av' => 'Av.', 'fc_col_use' => 'Use', 'fc_legend_title' => 'Légende', @@ -312,7 +313,7 @@ return [ 'fc_unit_days' => 'jours', 'fc_menu_carole' => 'Congés Carole', 'fc_clear' => 'Effacer', - 'fc_menu_kids_leaves' => 'Congés Enfants', + 'fc_menu_kids_leaves' => 'Congés Parents', 'fc_err_save_snap' => 'Erreur lors de la sauvegarde du correctif.', 'fc_err_fetch_gov' => 'Erreur lors de la connexion à l\'API gouvernementale.', 'fc_err_no_data_gov' => 'Aucune donnée trouvée sur l\'API du gouvernement pour cette année.', @@ -347,6 +348,15 @@ return [ 'fc_add_mode_placeholder' => 'Ex: Nounou, Casal, Grands-parents...', 'fc_settings_updated' => 'Paramètres mis à jour avec succès !', 'fc_first_day' => 'Premier jour de la semaine', + 'fc_helper_recap' => 'Récapitulatif Intervenant', + 'fc_no_helper_leaves' => 'Aucun congé posé ce mois-ci.', + 'fc_col_date' => 'Date', + 'fc_col_type' => 'Type', + 'fc_col_duration' => 'Durée', + 'fc_full_year' => 'Année complète', + 'fc_custom_period' => 'Période spécifique...', + 'fc_worked_days' => 'Travaillés (Est.)', + // --- CALENDRIER : PARAMÈTRES (MEMBRES & AFFICHAGE) --- 'fc_tab_display' => '🖥️ Affichage', 'fc_display_title' => 'Paramètres d\'affichage', @@ -462,7 +472,7 @@ return [ 'leg_extra_off' => 'Extra Off', 'leg_centre' => 'Centre', 'leg_avis' => 'Avis', - 'leg_pep_sick' => 'Pep Malade', + 'fc_menu_sick' => 'Malade', 'vac_toussaint' => 'Vacances de la Toussaint', 'vac_noel' => 'Vacances de Noël', diff --git a/mockup_epargne.html b/mockup_epargne.html deleted file mode 100644 index 815a3ba..0000000 --- a/mockup_epargne.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - Mockup Épargne HouseHub - - - -
- - - -
- - -
-
-
Poste / Mois
-
Août 2026
-
Juillet 2026
-
Juin 2026
-
-
-
- TOTAL BANQUE -
-
- - € -
-
- - € -
-
- - € -
-
-
-
Ecole P&P
-
- -
-
- -
-
- -
-
-
-
Extra casa
-
- -
-
- -
-
- -
-
-
-
Vacances
-
- -
-
- -
-
- -
-
-
-
- NON ALLOUÉ -
-
- 1230 € -
-
- 660 € -
-
- 699 € -
-
-
- - - - diff --git a/modules/family-calendar/family-calendar.css b/modules/family-calendar/family-calendar.css index 9f9be8b..31e232a 100644 --- a/modules/family-calendar/family-calendar.css +++ b/modules/family-calendar/family-calendar.css @@ -481,7 +481,7 @@ td.col-laia-sub { width: 40px; min-width: 40px; text-align: center; - padding: 4px; /* Réduit les marges internes */ + padding-bottom: 10px; /* Réduit les marges internes */ } /* 3. On s'assure que le tableau utilise tout l'espace disponible intelligemment */ @@ -536,7 +536,7 @@ td.col-laia-sub { #planningTable tbody td.col-sticky-sem { writing-mode: horizontal-tb; transform: none; - padding: 6px !important; + padding-bottom: 10px !important; text-align: center; } @@ -660,27 +660,32 @@ td.col-laia-sub { #selectionMenu, #fc-month-selectionMenu, .fc-selection-menu { - position: absolute; - z-index: 9000; + position: fixed !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + z-index: 9999; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(8px); border: 1px solid rgba(226, 232, 240, 0.8); - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2) !important; border-radius: 12px; - padding: 8px 12px; - min-width: 210px; + padding: 16px; + width: 90%; + max-width: 320px; + max-height: 85vh; + overflow-y: auto; display: none; - animation: menuPopIn 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards; - transform-origin: top center; + animation: menuPopCenter 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards !important; } -@keyframes menuPopIn { +@keyframes menuPopCenter { from { opacity: 0; - transform: scale(0.95) translateY(10px); + transform: translate(-50%, -45%) scale(0.95); } to { opacity: 1; - transform: scale(1) translateY(0); + transform: translate(-50%, -50%) scale(1); } } @@ -917,30 +922,6 @@ td.col-laia-sub { padding: 10px; } - #selectionMenu, - #fc-month-selectionMenu, - .fc-selection-menu { - position: fixed !important; - top: auto !important; - left: 0 !important; - bottom: 0 !important; - width: 100% !important; - border-radius: 24px 24px 0 0; - padding: 24px 20px; - transform: translateY(100%); - animation: slideUpSheet 0.3s forwards; - z-index: 10000 !important; - } - #selectionMenu::before, - #fc-month-selectionMenu::before { - content: ""; - display: block; - width: 40px; - height: 5px; - background: #cbd5e1; - border-radius: 10px; - margin: 0 auto 15px auto; - } .fc-two-months-container, .fc-three-months-container { display: flex !important; @@ -977,7 +958,6 @@ td.col-laia-sub { font-size: 0.85rem !important; } -/* 3. CORRECTION CRITIQUE : Le décalage "Sticky" de la colonne Semaine */ /* Puisque la colonne Mois fait 35px, la colonne Semaine doit démarrer à 35px (et non plus 54px) */ #planningTable tbody td.col-sticky-sem, #planningTable thead tr th.col-sticky-sem { @@ -1037,3 +1017,112 @@ td.col-laia-sub { #planningTable thead tr:nth-child(3) th { top: 64px !important; } + +#planningTable th.rotated-text { + height: 120px; /* Augmente la hauteur pour laisser respirer le texte */ + vertical-align: bottom; + padding-bottom: 10px !important; +} +.rotated-text span { + white-space: nowrap; /* Force le texte sur une seule ligne */ + display: inline-block; +} + +/* --- RÉCAPITULATIF INTERVENANT (DASHBOARD) --- */ +.fc-recap-controls { + display: flex; + gap: 12px; + align-items: center; + flex-wrap: wrap; +} +.fc-recap-custom-dates { + display: flex; + gap: 8px; + align-items: center; + background: var(--pf-bg-lighter); + padding: 4px 8px; + border-radius: 8px; + border: 1px solid var(--pf-border); +} +.fc-recap-kpi-container { + background: var(--pf-bg-lighter); + border-radius: 12px; + border: 1px solid var(--pf-border); + padding: 20px; + margin-top: 16px; +} +.fc-recap-kpi-main { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24px; + padding-bottom: 16px; + border-bottom: 1px solid var(--pf-border); +} +.fc-recap-kpi-main-label { + font-size: 0.95rem; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + display: flex; + align-items: center; + gap: 8px; +} +.fc-recap-kpi-main-val { + font-size: 1.8rem; + font-weight: 800; + color: var(--pf-primary); + line-height: 1; +} +.fc-recap-kpi-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 16px; +} +.fc-recap-kpi-card { + background: var(--bg-panel); + border: 1px solid var(--pf-border); + border-radius: 8px; + padding: 16px; + text-align: center; + box-shadow: var(--pf-shadow-sm); + transition: border-color 0.2s; +} +.fc-recap-kpi-card:hover { + border-color: var(--warning); +} +.fc-recap-kpi-label { + font-size: 0.8rem; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + margin-bottom: 8px; +} +.fc-recap-kpi-val { + font-size: 1.5rem; + font-weight: 800; + color: var(--warning); + line-height: 1; +} +.fc-recap-empty { + text-align: center; + color: var(--text-muted); + font-style: italic; + padding: 20px; + grid-column: 1 / -1; +} +.fc-recap-error { + text-align: center; + color: var(--danger); + font-weight: bold; + padding: 20px; +} + +[data-theme="dark"] .fc-recap-custom-dates, +[data-theme="dark"] .fc-recap-kpi-container { + background: var(--bg-panel); + border-color: var(--border-light); +} +[data-theme="dark"] .fc-recap-kpi-card { + background: var(--bg-page); +} diff --git a/modules/family-calendar/family-calendar.js b/modules/family-calendar/family-calendar.js index d009465..ee6d3dc 100644 --- a/modules/family-calendar/family-calendar.js +++ b/modules/family-calendar/family-calendar.js @@ -782,6 +782,7 @@ document.addEventListener("DOMContentLoaded", () => { const selectMonth = document.getElementById("fc-select-month"); const selectYear = document.getElementById("fc-select-year"); if (!selectMonth || !selectYear) return; + const lang = window.appLang || "fr-FR"; for (let i = 0; i < 12; i++) { selectMonth.add( @@ -793,9 +794,11 @@ document.addEventListener("DOMContentLoaded", () => { ), ); } + const currentY = new Date().getFullYear(); - for (let y = currentY - 2; y <= currentY + 5; y++) + for (let y = currentY - 2; y <= currentY + 5; y++) { selectYear.add(new Option(y, y)); + } const handleChange = () => { this.currentMonth = new Date( @@ -805,11 +808,248 @@ document.addEventListener("DOMContentLoaded", () => { ); this.renderMonthCalendar(); }; + selectMonth.addEventListener("change", handleChange); selectYear.addEventListener("change", handleChange); + + // --- Selecteurs Recap Intervenant (Logique masquée, pilotée par le nouveau DOM généré) --- + const recapMonth = document.getElementById("recapHelperMonth"); + const recapYear = document.getElementById("recapHelperYear"); + + if (recapMonth && recapYear) { + recapMonth.add(new Option("Année complète", "all")); + recapMonth.add(new Option("Période Spécifique...", "custom")); + for (let i = 0; i < 12; i++) { + recapMonth.add( + new Option( + new Intl.DateTimeFormat(lang, { month: "long" }).format( + new Date(2000, i, 1), + ), + i + 1, + ), + ); + } + for (let y = currentY - 2; y <= currentY + 5; y++) { + recapYear.add(new Option(y, y)); + } + recapMonth.value = new Date().getMonth() + 1; + recapYear.value = currentY; + + // L'écouteur est conservé si appelé manuellement, mais l'interaction se fera via les selecteurs injectés + } + } + + renderHelperRecap() { + const content = document.getElementById("recapHelperContent"); + const hiddenMonthSel = document.getElementById("recapHelperMonth"); + const hiddenYearSel = document.getElementById("recapHelperYear"); + const hiddenStartInp = document.getElementById("recapHelperStart"); + const hiddenEndInp = document.getElementById("recapHelperEnd"); + + if ( + !content || + !hiddenMonthSel || + !hiddenYearSel || + this.helpers.length === 0 + ) + return; + + const mStr = hiddenMonthSel.value; + const y = parseInt(hiddenYearSel.value); + let startDateStr, endDateStr; + let isCustom = mStr === "custom"; + + if (isCustom) { + startDateStr = hiddenStartInp.value; + endDateStr = hiddenEndInp.value; + } else if (mStr === "all") { + startDateStr = `${y}-01-01`; + endDateStr = `${y}-12-31`; + } else { + const m = parseInt(mStr); + startDateStr = `${y}-${String(m).padStart(2, "0")}-01`; + const lastDay = new Date(y, m, 0).getDate(); + endDateStr = `${y}-${String(m).padStart(2, "0")}-${String(lastDay).padStart(2, "0")}`; + } + + let theoreticalWorkingDays = 0; + let hasValidDates = true; + + if ( + isCustom && + (!startDateStr || !endDateStr || startDateStr > endDateStr) + ) { + hasValidDates = false; + } else { + let dObj = new Date(startDateStr + "T00:00:00"); + const endObj = new Date(endDateStr + "T00:00:00"); + + while (dObj <= endObj) { + const dayOfWeek = dObj.getDay(); + if (dayOfWeek !== 0 && dayOfWeek !== 6) { + const iso = this.getLocalIsoDate(dObj); + if (!this.publicHolidayDates.has(iso)) theoreticalWorkingDays++; + } + dObj.setDate(dObj.getDate() + 1); + } + } + + let html = ""; + this.helpers.forEach((h) => { + const hLeaves = + this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || []; + + const helperEvents = [...this.leaves, ...this.events] + .filter((e) => { + const eDate = e.leave_date || e.date; + const eType = e.leave_type || e.type; + const isOldOff = + eType === "HELPER_OFF" || + eType === "HELPER_EXTRA" || + eType.includes("OFF"); + + if (e.person_id != h.id) return false; + if (!e.leave_date && !isOldOff) return false; + + if (isCustom && !hasValidDates) return false; + return eDate >= startDateStr && eDate <= endDateStr; + }) + .map((e) => ({ + type: e.leave_type || e.type, + duration: parseFloat(e.duration) || 1, + })); + + const totals = {}; + hLeaves.forEach( + (lt) => (totals[typeof lt === "object" ? lt.type : lt] = 0), + ); + totals["OFF"] = 0; + totals["EXTRA"] = 0; + + let totalLeavesTaken = 0; + + helperEvents.forEach((e) => { + let mappedType = + e.type === "HELPER_OFF" + ? "OFF" + : e.type === "HELPER_EXTRA" + ? "EXTRA" + : e.type; + if (totals[mappedType] === undefined) totals[mappedType] = 0; + totals[mappedType] += e.duration; + totalLeavesTaken += e.duration; + }); + + const workedDays = hasValidDates + ? Math.max(0, theoreticalWorkingDays - totalLeavesTaken) + : 0; + + // Construction des options du sélecteur + const lang = window.appLang || "fr-FR"; + const trLang = window.I18N || {}; + let optionsHtml = ``; + optionsHtml += ``; + for (let i = 0; i < 12; i++) { + const monthName = new Intl.DateTimeFormat(lang, { + month: "long", + }).format(new Date(2000, i, 1)); + const capitalizedMonth = + monthName.charAt(0).toUpperCase() + monthName.slice(1); + optionsHtml += ``; + } + + let yearOptionsHtml = ""; + const currentY = new Date().getFullYear(); + for (let yr = currentY - 2; yr <= currentY + 5; yr++) { + yearOptionsHtml += ``; + } + + const isCustomDisplay = isCustom ? "flex" : "none"; + const isYearDisplay = isCustom ? "none" : "block"; + + // --- GÉNÉRATION DU HTML (Design Ultra-Compact + Micro Pilules) --- + let cardHtml = ` +
+ + +
+ + +
+ 📅 ${h.name} + Récapitulatif +
+ + +
+ Travaillés (Est.) + ${hasValidDates ? workedDays : "-"} j +
+ + +
`; + + if (!hasValidDates && isCustom) { + cardHtml += `
Sélectionnez des dates valides.
`; + } else { + let hasLeaves = false; + for (const [t, val] of Object.entries(totals)) { + if ( + val > 0 || + hLeaves.some( + (lt) => (typeof lt === "object" ? lt.type : lt) === t, + ) + ) { + hasLeaves = true; + let label = + t === "HELPER_OFF" ? "Off" : t === "HELPER_EXTRA" ? "Extra" : t; + cardHtml += ` +
+ ${label} + ${val}j +
`; + } + } + if (!hasLeaves) + cardHtml += `
Aucun congé posé.
`; + } + + cardHtml += ` +
+
+ + +
+ + + +
+ + ➔ + +
+
+ +
`; + html += cardHtml; + }); + + content.innerHTML = html; + + // Attachement de la fonction globale pour les selecteurs injectés + window.updateHiddenRecap = (el, type) => { + if (type === "month") hiddenMonthSel.value = el.value; + if (type === "year") hiddenYearSel.value = el.value; + if (type === "start") hiddenStartInp.value = el.value; + if (type === "end") hiddenEndInp.value = el.value; + this.renderHelperRecap(); + }; } - // 🔥 LE FIX (refreshAllData avec schoolHols injecté et fusionné) async refreshAllData() { try { const zone = window.calGlobalData?.foyer?.zone_scolaire || "C"; @@ -984,6 +1224,8 @@ document.addEventListener("DOMContentLoaded", () => { this.calculateMonthlyBalances(); this.renderTable(); this.renderMonthCalendar(); + if (typeof this.renderHelperRecap === "function") + this.renderHelperRecap(); } reprocessEvents() { @@ -994,8 +1236,12 @@ document.addEventListener("DOMContentLoaded", () => { this.careModes.forEach((m) => (w.totals["mode_" + m] = 0)); this.kids.forEach((k) => (w.totals["sick_" + k.id] = 0)); this.helpers.forEach((h) => { - w.totals["off_" + h.id] = 0; - w.totals["extra_" + h.id] = 0; + const hLeaves = + this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || []; + hLeaves.forEach((lt) => { + const typeName = typeof lt === "object" ? lt.type : lt; + w.totals[`leave_${h.id}_${typeName}`] = 0; + }); }); this.parents.forEach((p) => { const types = this.leaveMatrix[p.id] || []; @@ -1051,12 +1297,14 @@ document.addEventListener("DOMContentLoaded", () => { }); let helperAbsences = 0; - this.helpers.forEach( - (h) => - (helperAbsences += - (w.totals["off_" + h.id] || 0) + - (w.totals["extra_" + h.id] || 0)), - ); + this.helpers.forEach((h) => { + const hLeaves = + this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || []; + hLeaves.forEach((lt) => { + const typeName = typeof lt === "object" ? lt.type : lt; + helperAbsences += w.totals[`leave_${h.id}_${typeName}`] || 0; + }); + }); if (this.kids.length > 0) { w.totals.presenceKid = Math.max( @@ -1261,10 +1509,6 @@ document.addEventListener("DOMContentLoaded", () => { td.classList.add("fc-day--public-holiday"); if (evt.type === "VACANCES_SCOLAIRES") td.classList.add("fc-day--school-holiday"); - if (evt.type === "HELPER_OFF") - td.classList.add("fc-day--off-carole"); - if (evt.type === "HELPER_EXTRA") - td.classList.add("fc-day--extra-off-carole"); if (upperCareModes.includes(evt.type)) td.classList.add("fc-day--has-guard"); }); @@ -1320,13 +1564,30 @@ document.addEventListener("DOMContentLoaded", () => { tr.appendChild(td); }); + // 1. Congés intervenant (Dynamiques) + (this.helpers || []).forEach((h) => { + const hLeaves = + this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || []; + hLeaves.forEach((lt) => { + const typeName = typeof lt === "object" ? lt.type : lt; + const td = document.createElement("td"); + td.className = "col-total"; + td.textContent = fmt(w.totals[`leave_${h.id}_${typeName}`] || 0); + tr.appendChild(td); + }); + }); + + // 2. Modes de garde (On ignore Nounou si Helper présent) (this.careModes || []).forEach((mode) => { + if (mode.toLowerCase() === "nounou" && this.helpers.length > 0) + return; const td = document.createElement("td"); td.className = "col-total"; td.textContent = fmt(w.totals["mode_" + mode] || 0); tr.appendChild(td); }); + // 3. Maladie enfants (this.kids || []).forEach((kid) => { const td = document.createElement("td"); td.className = "col-total"; @@ -1371,7 +1632,7 @@ document.addEventListener("DOMContentLoaded", () => { }); } catch (e) { console.error("🔥 Erreur fatale dans renderTable :", e); - this.planningBody.innerHTML = `
`; + this.planningBody.innerHTML = ``; } } @@ -2053,7 +2314,9 @@ document.addEventListener("DOMContentLoaded", () => { }); const activeLeaves = {}; - this.parents.forEach((p) => (activeLeaves[p.id] = new Set())); + [...this.parents, ...this.helpers].forEach( + (p) => (activeLeaves[p.id] = new Set()), + ); this.leaves.forEach((l) => { if (dates.includes(l.leave_date) && activeLeaves[l.person_id]) activeLeaves[l.person_id].add(l.leave_type); @@ -2079,40 +2342,54 @@ document.addEventListener("DOMContentLoaded", () => { }); const trashSvg = ``; - const buildHeader = (title, action, cat) => ` -
- ${title} - ${action ? `` : ""} -
`; + + // Ajout de la classe "btn-icon-action delete" pour activer le hover natif (rouge clair) + const buildHeader = (title, action, cat, pid) => + `
${title}${action ? `` : ""}
`; let html = `
${dateLabel}
`; + // 1. Congés Intervenants if (this.helpers.length > 0) { this.helpers.forEach((h) => { - html += `
${buildHeader(h.name, "clear-type", "HELPER_" + h.id)}
- - -
`; + const hLeaves = + this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || []; + if (hLeaves.length > 0) { + const hColor = h.color || "var(--warning)"; + html += `
${buildHeader(h.name, "clear-leaves-person", null, h.id)}
`; + hLeaves.forEach((lt) => { + const lType = typeof lt === "object" ? lt.type : lt; + html += ``; + }); + html += `
`; + } }); } + // 2. Modes de Garde if (this.careModes.length > 0) { - html += `
${buildHeader(trLang.fc_care_modes_title || "Modes de garde", "clear-type", "CARE_MODE")}
`; - this.careModes.forEach((m) => { - let iconHtml = - m.toLowerCase() === "avis" - ? ` ` - : m.toLowerCase() === "centre" - ? `🏫 ` - : ""; - const modeType = m.toUpperCase(); - html += ``; - }); - html += `
`; + const displayModes = this.careModes.filter( + (m) => !(m.toLowerCase() === "nounou" && this.helpers.length > 0), + ); + if (displayModes.length > 0) { + html += `
${buildHeader(trLang.fc_care_modes_title || "Modes de garde", "clear-type", "CARE_MODE", null)}
`; + displayModes.forEach((m) => { + let iconHtml = + m.toLowerCase() === "avis" + ? ` ` + : m.toLowerCase() === "centre" + ? `🏫 ` + : ""; + const modeType = m.toUpperCase(); + html += ``; + }); + html += `
`; + } } + // 3. Maladie Enfants if (this.kids.length > 0) { - html += `
${buildHeader(trLang.leg_pep_sick || "Maladie", "clear-type", "CHILD_SICK")}
`; + html += `
${buildHeader(trLang.fc_menu_sick || "Maladie", "clear-type", "CHILD_SICK", null)}
`; this.kids.forEach((k) => { const color = k.color || "var(--danger)"; html += ``; @@ -2120,39 +2397,40 @@ document.addEventListener("DOMContentLoaded", () => { html += `
`; } - html += `
${buildHeader(trLang.fc_menu_kids_leaves || "Congés Adultes", null, null)}
`; + // 4. Congés Parents (Répartition en 2 colonnes !) + html += `
${buildHeader(trLang.fc_menu_adult_leaves || "Congés Parents", null, null, null)}`; + html += `
`; const allParentLeaveTypes = new Set(); this.parents.forEach((p) => { (this.leaveMatrix[p.id] || []).forEach((l) => - allParentLeaveTypes.add(l.type), + allParentLeaveTypes.add(typeof l === "object" ? l.type : l), ); }); this.parents.forEach((p) => { const pColor = p.color || "var(--primary)"; - html += `
- ${p.name} + html += `
`; + html += `
+ ${p.name}
`; html += `
`; Array.from(allParentLeaveTypes).forEach((t) => { - const hasThisLeave = (this.leaveMatrix[p.id] || []).some( - (l) => l.type === t, - ); - if (hasThisLeave) { - html += ``; + if ( + (this.leaveMatrix[p.id] || []).some( + (l) => (typeof l === "object" ? l.type : l) === t, + ) + ) { + html += ``; } }); - html += `
`; + html += `
`; }); html += `
`; menu.innerHTML = html; - let left = x + 10; - if (left + 240 > window.innerWidth) left = x - 250; - menu.style.left = `${left}px`; - menu.style.top = `${y + 10}px`; menu.style.display = "block"; + this.menuJustOpened = true; setTimeout(() => (this.menuJustOpened = false), 100); }
Maladie
Erreur d'affichage : ${e.message}
Regarde la console pour plus de détails.
Erreur d'affichage : ${e.message}