From 87995be91d58078551f4c9a97bfd4d33597ba1d7 Mon Sep 17 00:00:00 2001
From: "fefe.clochette"
Date: Mon, 8 Dec 2025 17:46:31 +0100
Subject: [PATCH] Auto-commit for deploy to production - 2025-12-08 17:46:31
---
assets/js/family-calendar.js | 357 ++++++++++++++++++++++++-----------
family-calendar.php | 35 +++-
2 files changed, 274 insertions(+), 118 deletions(-)
diff --git a/assets/js/family-calendar.js b/assets/js/family-calendar.js
index 5c8f5d3..f390c0f 100644
--- a/assets/js/family-calendar.js
+++ b/assets/js/family-calendar.js
@@ -1,48 +1,128 @@
// assets/js/family-calendar.js
-const weeks = [
- {
- month: "September",
- code: "W36",
- dates: "01/09 - 07/09",
- caroleOffDays: 0,
- isSchoolHoliday: false,
- isBankHoliday: false,
- alex: { cp: 0, rtt: 0, ja: 0 },
- laia: { cp: 0, rtt: 0, ja: 0 },
- },
- {
- month: "September",
- code: "W38",
- dates: "15/09 - 21/09",
- caroleOffDays: 2,
- isSchoolHoliday: false,
- isBankHoliday: false,
- alex: { cp: 0, rtt: 0, ja: 0 },
- laia: { cp: 0, rtt: 0, ja: 0 },
- },
- {
- month: "October",
- code: "W40",
- dates: "29/09 - 05/10",
- caroleOffDays: 0,
- isSchoolHoliday: false,
- isBankHoliday: false,
- alex: { cp: 0, rtt: 0, ja: 0 },
- laia: { cp: 0, rtt: 0, ja: 0 },
- },
- {
- month: "August",
- code: "W32",
- dates: "03/08 - 09/08",
- caroleOffDays: 5,
- isSchoolHoliday: true,
- isBankHoliday: false,
- alex: { cp: 0, rtt: 0, ja: 0 },
- laia: { cp: 0, rtt: 0, ja: 0 },
- },
- // TODO: compléter le reste des semaines W36 → W35
-];
+// === 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",
+ 1: "Fevrier",
+ 2: "Mars",
+ 3: "Avril",
+ 4: "Mai",
+ 5: "Juin",
+ 6: "Juillet",
+ 7: "Aout",
+ 8: "Septembre",
+ 9: "Octobre",
+ 10: "Novembre",
+ 11: "Decembre",
+ };
+ return map[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 }
+ */
+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)
+
+ let current = new Date(start);
+
+ // se placer sur le premier lundi >= 1er septembre 2025
+ while (current.getDay() !== 1) {
+ // 1 = lundi
+ current.setDate(current.getDate() + 1);
+ }
+
+ let weekCount = 1;
+
+ while (current <= end) {
+ const monday = new Date(current);
+ const tuesday = new Date(current);
+ tuesday.setDate(monday.getDate() + 1);
+ const wednesday = new Date(current);
+ wednesday.setDate(monday.getDate() + 2);
+ const thursday = new Date(current);
+ thursday.setDate(monday.getDate() + 3);
+ const friday = new Date(current);
+ friday.setDate(monday.getDate() + 4);
+
+ const monthIndex = monday.getMonth();
+ const year = monday.getFullYear();
+ const monthKey = `${year}-${String(monthIndex + 1).padStart(2, "0")}`;
+ const monthName = getMonthNameFr(monthIndex);
+
+ weeks.push({
+ monthKey,
+ monthName,
+ weekLabel: `W${weekCount}`,
+ days: {
+ mon: formatDayMonth(monday),
+ tue: formatDayMonth(tuesday),
+ wed: formatDayMonth(wednesday),
+ thu: formatDayMonth(thursday),
+ fri: formatDayMonth(friday),
+ },
+ offCarole: 0,
+ extraOffCarole: 0,
+ centre: 0,
+ avis: 0,
+ alex: {
+ total: 0,
+ detail: "",
+ },
+ laia: {
+ total: 0,
+ detail: "",
+ },
+ });
+
+ current.setDate(current.getDate() + 7);
+ weekCount++;
+ }
+
+ return weeks;
+}
+
+const weeks = generateWeeks();
+
+// === 2. Calcul des rowspans pour la colonne Mois ===
+
+function computeMonthSpans(weeks) {
+ const counts = {};
+ weeks.forEach((w) => {
+ counts[w.monthKey] = (counts[w.monthKey] || 0) + 1;
+ });
+ return counts;
+}
+
+const monthSpans = computeMonthSpans(weeks);
+
+// === 3. Rendu du tableau ===
function renderTable() {
const planningBody = document.getElementById("planningBody");
@@ -52,46 +132,81 @@ function renderTable() {
const showOnlyCaroleOff =
document.getElementById("showOnlyCaroleOff")?.checked;
- const showOnlySchoolHoliday = document.getElementById(
- "showOnlySchoolHoliday"
- )?.checked;
+ // showOnlySchoolHoliday est ignore pour l'instant
+
+ const monthRowRendered = {}; // monthKey -> bool
weeks.forEach((week, index) => {
- if (showOnlyCaroleOff && week.caroleOffDays === 0) return;
- if (showOnlySchoolHoliday && !week.isSchoolHoliday) return;
+ if (showOnlyCaroleOff && week.offCarole === 0) return;
const tr = document.createElement("tr");
- if (week.caroleOffDays > 0) tr.classList.add("fc-row--carole-off");
- if (week.isSchoolHoliday) tr.classList.add("fc-row--school-holiday");
- if (week.isBankHoliday) tr.classList.add("fc-row--bank-holiday");
+ // Colonne Mois avec rowspan uniquement pour la 1ere ligne du mois
+ if (!monthRowRendered[week.monthKey]) {
+ monthRowRendered[week.monthKey] = true;
+ const tdMonth = document.createElement("td");
+ tdMonth.rowSpan = monthSpans[week.monthKey] || 1;
+ tdMonth.textContent = week.monthName;
+ tr.appendChild(tdMonth);
+ }
- tr.innerHTML = `
- | ${week.month} |
- ${week.code} |
- ${week.dates} |
- ${week.caroleOffDays || ""} |
- ${week.isSchoolHoliday ? "Oui" : ""} |
- ${week.isBankHoliday ? "Oui" : ""} |
- |
- |
- |
- |
- |
- |
- `;
+ // Colonne Semaine
+ const tdWeek = document.createElement("td");
+ tdWeek.textContent = week.weekLabel;
+ tr.appendChild(tdWeek);
+
+ // Jours Lundi -> Vendredi
+ ["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => {
+ const td = document.createElement("td");
+ td.textContent = week.days[dayKey];
+ tr.appendChild(td);
+ });
+
+ // # Off Carole
+ const tdOff = document.createElement("td");
+ tdOff.innerHTML = ``;
+ tr.appendChild(tdOff);
+
+ // # Extra off Carole
+ const tdExtraOff = document.createElement("td");
+ tdExtraOff.innerHTML = ``;
+ tr.appendChild(tdExtraOff);
+
+ // #Centre
+ const tdCentre = document.createElement("td");
+ tdCentre.innerHTML = ``;
+ tr.appendChild(tdCentre);
+
+ // #Avis
+ const tdAvis = document.createElement("td");
+ tdAvis.innerHTML = ``;
+ tr.appendChild(tdAvis);
+
+ // Alex total & détail
+ const tdAlexTotal = document.createElement("td");
+ tdAlexTotal.textContent = week.alex.total.toFixed
+ ? week.alex.total.toFixed(2)
+ : week.alex.total;
+ tr.appendChild(tdAlexTotal);
+
+ const tdAlexDetail = document.createElement("td");
+ tdAlexDetail.innerHTML = ``;
+ 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;
+ tr.appendChild(tdLaiaTotal);
+
+ const tdLaiaDetail = document.createElement("td");
+ tdLaiaDetail.innerHTML = ``;
+ tr.appendChild(tdLaiaDetail);
planningBody.appendChild(tr);
});
@@ -100,22 +215,44 @@ function renderTable() {
updateSummary();
}
+// === 4. Listeners sur les inputs ===
+
function attachInputListeners() {
const planningBody = document.getElementById("planningBody");
if (!planningBody) return;
- planningBody.querySelectorAll("input[type='number']").forEach((input) => {
+ planningBody.querySelectorAll("input").forEach((input) => {
input.addEventListener("change", (e) => {
- const w = parseInt(e.target.dataset.week, 10);
- const person = e.target.dataset.person;
- const type = e.target.dataset.type;
- const value = parseFloat(e.target.value || "0");
- weeks[w][person][type] = value;
+ 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) ===
+
function updateSummary() {
const summaryDiv = document.getElementById("summaryText");
if (!summaryDiv) return;
@@ -140,22 +277,14 @@ function updateSummary() {
document.getElementById("laiaJaInit")?.value || "0"
);
- let alexCpUsed = 0,
- alexRttUsed = 0,
- alexJaUsed = 0;
- let laiaCpUsed = 0,
- laiaRttUsed = 0,
- laiaJaUsed = 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;
- weeks.forEach((week) => {
- alexCpUsed += week.alex.cp;
- alexRttUsed += week.alex.rtt;
- alexJaUsed += week.alex.ja;
-
- laiaCpUsed += week.laia.cp;
- laiaRttUsed += week.laia.rtt;
- laiaJaUsed += week.laia.ja;
- });
+ const laiaCpUsed = 0;
+ const laiaRttUsed = 0;
+ const laiaJaUsed = 0;
const alexCpLeft = alexCpInit - alexCpUsed;
const alexRttLeft = alexRttInit - alexRttUsed;
@@ -167,30 +296,35 @@ function updateSummary() {
summaryDiv.innerHTML = `
Alex
- CP utilisés : ${alexCpUsed.toFixed(2)} / ${alexCpInit.toFixed(
+ CP utilises : ${alexCpUsed.toFixed(2)} / ${alexCpInit.toFixed(
2
)} (reste ${alexCpLeft.toFixed(2)})
- RTT utilisés : ${alexRttUsed.toFixed(2)} / ${alexRttInit.toFixed(
+ RTT utilises : ${alexRttUsed.toFixed(2)} / ${alexRttInit.toFixed(
2
)} (reste ${alexRttLeft.toFixed(2)})
- JA utilisés : ${alexJaUsed.toFixed(2)} / ${alexJaInit.toFixed(
+ JA utilises : ${alexJaUsed.toFixed(2)} / ${alexJaInit.toFixed(
2
)} (reste ${alexJaLeft.toFixed(2)})
Laia
- CP utilisés : ${laiaCpUsed.toFixed(2)} / ${laiaCpInit.toFixed(
+ CP utilises : ${laiaCpUsed.toFixed(2)} / ${laiaCpInit.toFixed(
2
)} (reste ${laiaCpLeft.toFixed(2)})
- RTT utilisés : ${laiaRttUsed.toFixed(2)} / ${laiaRttInit.toFixed(
+ RTT utilises : ${laiaRttUsed.toFixed(2)} / ${laiaRttInit.toFixed(
2
)} (reste ${laiaRttLeft.toFixed(2)})
- JA utilisés : ${laiaJaUsed.toFixed(2)} / ${laiaJaInit.toFixed(2)})
+ JA utilises : ${laiaJaUsed.toFixed(2)} / ${laiaJaInit.toFixed(
+ 2
+ )} (reste ${laiaJaLeft.toFixed(2)})
`;
}
+// === 6. Init ===
+
function initFamilyCalendar() {
if (!document.getElementById("planningBody")) return;
+ // Soldes initiaux
[
"alexCpInit",
"alexRttInit",
@@ -203,10 +337,17 @@ function initFamilyCalendar() {
if (el) el.addEventListener("change", updateSummary);
});
- ["showOnlyCaroleOff", "showOnlySchoolHoliday"].forEach((id) => {
- const el = document.getElementById(id);
- if (el) el.addEventListener("change", renderTable);
- });
+ // Filtres (pour l'instant seul showOnlyCaroleOff a un effet)
+ const showOnlyCaroleOff = document.getElementById("showOnlyCaroleOff");
+ if (showOnlyCaroleOff) {
+ showOnlyCaroleOff.addEventListener("change", renderTable);
+ }
+ const showOnlySchoolHoliday = document.getElementById(
+ "showOnlySchoolHoliday"
+ );
+ if (showOnlySchoolHoliday) {
+ showOnlySchoolHoliday.addEventListener("change", renderTable);
+ }
renderTable();
}
diff --git a/family-calendar.php b/family-calendar.php
index 33f9699..e558023 100644
--- a/family-calendar.php
+++ b/family-calendar.php
@@ -72,18 +72,34 @@ require __DIR__ . '/header.php';
| Mois |
Semaine |
- Dates (lun-dim) |
+ Lundi |
+ Mardi |
+ Mercredi |
+ Jeudi |
+ Vendredi |
# Off Carole |
- Vacances scolaires |
- Bank holiday |
- Alex - jours poses (semaine) |
- Laia - jours poses (semaine) |
+ # Extra off Carole |
+ #Centre |
+ #Avis |
+ Alex |
+ Laia |
- | | |
- | | |
- CP | RTT | JA |
- CP | RTT | JA |
+ |
+ |
+ jj/mm |
+ jj/mm |
+ jj/mm |
+ jj/mm |
+ jj/mm |
+ jours |
+ jours |
+ jours |
+ jours |
+ Total |
+ Détail |
+ Total |
+ Détail |
@@ -93,7 +109,6 @@ require __DIR__ . '/header.php';
-