diff --git a/assets/js/family-calendar.js b/assets/js/family-calendar.js index f390c0f..faea965 100644 --- a/assets/js/family-calendar.js +++ b/assets/js/family-calendar.js @@ -2,18 +2,12 @@ // === 1. Utilitaires dates === -/** - * Formate une Date en "dd/mm". - */ function formatDayMonth(date) { const d = String(date.getDate()).padStart(2, "0"); const m = String(date.getMonth() + 1).padStart(2, "0"); return `${d}/${m}`; } -/** - * Retourne le nom de mois en français à partir du monthIndex JS (0..11). - */ function getMonthNameFr(monthIndex) { const map = { 0: "Janvier", @@ -33,22 +27,29 @@ function getMonthNameFr(monthIndex) { } /** - * Genere les semaines de la 1ere semaine de septembre 2025 - * a la derniere semaine d'aout 2026. - * Chaque element contient: - * - monthKey (ex: "2025-09") - * - monthName (ex: "Septembre") - * - weekLabel (W1, W2, ...) - * - days: { mon, tue, wed, thu, fri } en "dd/mm" - * - offCarole, extraOffCarole, centre, avis - * - alex: { total, detail } - * - laia: { total, detail } + * Calcule le numéro de semaine dans l'année (1..52/53), + * en prenant le lundi comme début de semaine. */ +function getWeekOfYear(date) { + const year = date.getFullYear(); + const startOfYear = new Date(year, 0, 1); + // se placer au lundi de la semaine contenant le 1er janvier + const day = startOfYear.getDay() || 7; // dimanche=0 => 7 + const diffToMonday = day > 1 ? day - 1 : 0; + const firstMonday = new Date(year, 0, 1 - diffToMonday); + + const diffMillis = date - firstMonday; + const diffDays = Math.floor(diffMillis / (1000 * 60 * 60 * 24)); + return Math.floor(diffDays / 7) + 1; +} + +// === 2. Génération des semaines === + function generateWeeks() { const weeks = []; - const start = new Date(2025, 8, 1); // 1er septembre 2025 (mois 8 car 0-based) - const end = new Date(2026, 7, 31); // 31 aout 2026 (mois 7) + const start = new Date(2025, 8, 1); // 1er sept 2025 + const end = new Date(2026, 7, 31); // 31 aout 2026 let current = new Date(start); @@ -58,8 +59,6 @@ function generateWeeks() { current.setDate(current.getDate() + 1); } - let weekCount = 1; - while (current <= end) { const monday = new Date(current); const tuesday = new Date(current); @@ -71,15 +70,21 @@ function generateWeeks() { const friday = new Date(current); friday.setDate(monday.getDate() + 4); - const monthIndex = monday.getMonth(); const year = monday.getFullYear(); + const weekOfYear = getWeekOfYear(monday); + const weekId = `${year}-W${String(weekOfYear).padStart(2, "0")}`; + + const monthIndex = monday.getMonth(); const monthKey = `${year}-${String(monthIndex + 1).padStart(2, "0")}`; const monthName = getMonthNameFr(monthIndex); weeks.push({ + id: weekId, + year, + weekOfYear, monthKey, monthName, - weekLabel: `W${weekCount}`, + weekLabel: `W${weekOfYear}`, days: { mon: formatDayMonth(monday), tue: formatDayMonth(tuesday), @@ -87,10 +92,19 @@ function generateWeeks() { thu: formatDayMonth(thursday), fri: formatDayMonth(friday), }, - offCarole: 0, - extraOffCarole: 0, - centre: 0, - avis: 0, + dayDates: { + mon: monday, + tue: tuesday, + wed: wednesday, + thu: thursday, + fri: friday, + }, + totals: { + offCarole: 0, + extraOffCarole: 0, + centre: 0, + avis: 0, + }, alex: { total: 0, detail: "", @@ -102,7 +116,6 @@ function generateWeeks() { }); current.setDate(current.getDate() + 7); - weekCount++; } return weeks; @@ -110,7 +123,70 @@ function generateWeeks() { const weeks = generateWeeks(); -// === 2. Calcul des rowspans pour la colonne Mois === +// === 3. Événements calendrier (exemple, plus tard ce sera ton UI/DB) === + +/** + * Exemple de liste d'événements. Plus tard : + * - tu auras une UI pour ajouter/supprimer ces événements + * - tu les chargeras depuis/vers la DB. + */ +const events = [ + // Exemple : Carole off le 15/09/2025 + { date: "2025-09-15", type: "OFF_CAROLE", duration: 1 }, + // Exemple : Centre le 20/10/2025 + { date: "2025-10-20", type: "CENTRE", duration: 1 }, + // etc. +]; + +/** + * Recalcule les totaux par semaine à partir des events. + */ +function recomputeTotalsFromEvents(weeks, events) { + // reset + weeks.forEach((w) => { + w.totals.offCarole = 0; + w.totals.extraOffCarole = 0; + w.totals.centre = 0; + w.totals.avis = 0; + }); + + events.forEach((evt) => { + const [y, m, d] = evt.date.split("-").map(Number); + const evtDate = new Date(y, m - 1, d); + + // trouver la semaine qui contient evtDate (entre lundi et vendredi) + const week = weeks.find((w) => { + const md = w.dayDates.mon; + const fd = w.dayDates.fri; + return evtDate >= md && evtDate <= fd; + }); + if (!week) return; + + const dur = evt.duration || 1; + + switch (evt.type) { + case "OFF_CAROLE": + week.totals.offCarole += dur; + break; + case "EXTRA_OFF_CAROLE": + week.totals.extraOffCarole += dur; + break; + case "CENTRE": + week.totals.centre += dur; + break; + case "AVIS": + week.totals.avis += dur; + break; + default: + break; + } + }); +} + +// première agrégation +recomputeTotalsFromEvents(weeks, events); + +// === 4. Calcul des rowspans pour la colonne Mois === function computeMonthSpans(weeks) { const counts = {}; @@ -122,7 +198,7 @@ function computeMonthSpans(weeks) { const monthSpans = computeMonthSpans(weeks); -// === 3. Rendu du tableau === +// === 5. Rendu du tableau === function renderTable() { const planningBody = document.getElementById("planningBody"); @@ -132,16 +208,16 @@ function renderTable() { const showOnlyCaroleOff = document.getElementById("showOnlyCaroleOff")?.checked; - // showOnlySchoolHoliday est ignore pour l'instant + // showOnlySchoolHoliday est ignoré pour l'instant - const monthRowRendered = {}; // monthKey -> bool + const monthRowRendered = {}; - weeks.forEach((week, index) => { - if (showOnlyCaroleOff && week.offCarole === 0) return; + weeks.forEach((week) => { + if (showOnlyCaroleOff && week.totals.offCarole === 0) return; const tr = document.createElement("tr"); - // Colonne Mois avec rowspan uniquement pour la 1ere ligne du mois + // Colonne Mois (rowspan sur toutes les semaines du mois) if (!monthRowRendered[week.monthKey]) { monthRowRendered[week.monthKey] = true; const tdMonth = document.createElement("td"); @@ -150,108 +226,62 @@ function renderTable() { tr.appendChild(tdMonth); } - // Colonne Semaine + // Semaine const tdWeek = document.createElement("td"); tdWeek.textContent = week.weekLabel; tr.appendChild(tdWeek); - // Jours Lundi -> Vendredi + // Jours ["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => { const td = document.createElement("td"); td.textContent = week.days[dayKey]; tr.appendChild(td); }); - // # Off Carole + // Totaux # Off Carole, # Extra off, #Centre, #Avis const tdOff = document.createElement("td"); - tdOff.innerHTML = ``; + tdOff.textContent = week.totals.offCarole.toFixed(2).replace(/\.00$/, ""); tr.appendChild(tdOff); - // # Extra off Carole const tdExtraOff = document.createElement("td"); - tdExtraOff.innerHTML = ``; + tdExtraOff.textContent = week.totals.extraOffCarole + .toFixed(2) + .replace(/\.00$/, ""); tr.appendChild(tdExtraOff); - // #Centre const tdCentre = document.createElement("td"); - tdCentre.innerHTML = ``; + tdCentre.textContent = week.totals.centre.toFixed(2).replace(/\.00$/, ""); tr.appendChild(tdCentre); - // #Avis const tdAvis = document.createElement("td"); - tdAvis.innerHTML = ``; + tdAvis.textContent = week.totals.avis.toFixed(2).replace(/\.00$/, ""); tr.appendChild(tdAvis); - // Alex total & détail + // Alex total & détail (pour l'instant, juste placeholders) const tdAlexTotal = document.createElement("td"); - tdAlexTotal.textContent = week.alex.total.toFixed - ? week.alex.total.toFixed(2) - : week.alex.total; + tdAlexTotal.textContent = week.alex.total.toFixed(2).replace(/\.00$/, ""); tr.appendChild(tdAlexTotal); const tdAlexDetail = document.createElement("td"); - tdAlexDetail.innerHTML = ``; + tdAlexDetail.textContent = week.alex.detail || ""; tr.appendChild(tdAlexDetail); // Laia total & détail const tdLaiaTotal = document.createElement("td"); - tdLaiaTotal.textContent = week.laia.total.toFixed - ? week.laia.total.toFixed(2) - : week.laia.total; + tdLaiaTotal.textContent = week.laia.total.toFixed(2).replace(/\.00$/, ""); tr.appendChild(tdLaiaTotal); const tdLaiaDetail = document.createElement("td"); - tdLaiaDetail.innerHTML = ``; + tdLaiaDetail.textContent = week.laia.detail || ""; tr.appendChild(tdLaiaDetail); planningBody.appendChild(tr); }); - attachInputListeners(); updateSummary(); } -// === 4. Listeners sur les inputs === - -function attachInputListeners() { - const planningBody = document.getElementById("planningBody"); - if (!planningBody) return; - - planningBody.querySelectorAll("input").forEach((input) => { - input.addEventListener("change", (e) => { - const weekIndex = parseInt(e.target.dataset.week, 10); - const field = e.target.dataset.field; - const value = - e.target.type === "number" - ? parseFloat(e.target.value || "0") - : e.target.value; - - if (Number.isNaN(weekIndex) || !weeks[weekIndex]) return; - - if ( - field === "offCarole" || - field === "extraOffCarole" || - field === "centre" || - field === "avis" - ) { - weeks[weekIndex][field] = value; - } else if (field === "alex.detail") { - weeks[weekIndex].alex.detail = value; - } else if (field === "laia.detail") { - weeks[weekIndex].laia.detail = value; - } - - // plus tard : calculer alex.total / laia.total en fonction des CP/RTT/JA - updateSummary(); - }); - }); -} - -// === 5. Résumé (pour l'instant, 0 utilisés) === +// === 6. Résumé (encore 0 utilisés pour l’instant) === function updateSummary() { const summaryDiv = document.getElementById("summaryText"); @@ -277,7 +307,6 @@ function updateSummary() { document.getElementById("laiaJaInit")?.value || "0" ); - // Pour l'instant, on n'a pas encore branché les CP/RTT/JA par semaine const alexCpUsed = 0; const alexRttUsed = 0; const alexJaUsed = 0; @@ -319,12 +348,11 @@ function updateSummary() { `; } -// === 6. Init === +// === 7. Init === function initFamilyCalendar() { if (!document.getElementById("planningBody")) return; - // Soldes initiaux [ "alexCpInit", "alexRttInit", @@ -337,7 +365,6 @@ function initFamilyCalendar() { if (el) el.addEventListener("change", updateSummary); }); - // Filtres (pour l'instant seul showOnlyCaroleOff a un effet) const showOnlyCaroleOff = document.getElementById("showOnlyCaroleOff"); if (showOnlyCaroleOff) { showOnlyCaroleOff.addEventListener("change", renderTable); diff --git a/family-calendar.php b/family-calendar.php index e558023..2f1e807 100644 --- a/family-calendar.php +++ b/family-calendar.php @@ -111,5 +111,6 @@ require __DIR__ . '/header.php'; +