@@ -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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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 = `
Erreur d'affichage : ${e.message} Regarde la console pour plus de détails. |
`;
+ this.planningBody.innerHTML = `
| Erreur d'affichage : ${e.message} |
`;
}
}
@@ -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 = ``;
+ // 1. Congés Intervenants
if (this.helpers.length > 0) {
this.helpers.forEach((h) => {
- html += ``;
+ const hLeaves =
+ this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || [];
+ if (hLeaves.length > 0) {
+ const hColor = h.color || "var(--warning)";
+ html += ``;
+ }
});
}
+ // 2. Modes de Garde
if (this.careModes.length > 0) {
- html += ``;
+ const displayModes = this.careModes.filter(
+ (m) => !(m.toLowerCase() === "nounou" && this.helpers.length > 0),
+ );
+ if (displayModes.length > 0) {
+ html += ``;
+ }
}
+ // 3. Maladie Enfants
if (this.kids.length > 0) {
- html += `