Auto-commit for deploy to production - 2025-12-09 09:55:50
This commit is contained in:
+122
-95
@@ -2,18 +2,12 @@
|
|||||||
|
|
||||||
// === 1. Utilitaires dates ===
|
// === 1. Utilitaires dates ===
|
||||||
|
|
||||||
/**
|
|
||||||
* Formate une Date en "dd/mm".
|
|
||||||
*/
|
|
||||||
function formatDayMonth(date) {
|
function formatDayMonth(date) {
|
||||||
const d = String(date.getDate()).padStart(2, "0");
|
const d = String(date.getDate()).padStart(2, "0");
|
||||||
const m = String(date.getMonth() + 1).padStart(2, "0");
|
const m = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
return `${d}/${m}`;
|
return `${d}/${m}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retourne le nom de mois en français à partir du monthIndex JS (0..11).
|
|
||||||
*/
|
|
||||||
function getMonthNameFr(monthIndex) {
|
function getMonthNameFr(monthIndex) {
|
||||||
const map = {
|
const map = {
|
||||||
0: "Janvier",
|
0: "Janvier",
|
||||||
@@ -33,22 +27,29 @@ function getMonthNameFr(monthIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Genere les semaines de la 1ere semaine de septembre 2025
|
* Calcule le numéro de semaine dans l'année (1..52/53),
|
||||||
* a la derniere semaine d'aout 2026.
|
* en prenant le lundi comme début de semaine.
|
||||||
* 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 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() {
|
function generateWeeks() {
|
||||||
const weeks = [];
|
const weeks = [];
|
||||||
|
|
||||||
const start = new Date(2025, 8, 1); // 1er septembre 2025 (mois 8 car 0-based)
|
const start = new Date(2025, 8, 1); // 1er sept 2025
|
||||||
const end = new Date(2026, 7, 31); // 31 aout 2026 (mois 7)
|
const end = new Date(2026, 7, 31); // 31 aout 2026
|
||||||
|
|
||||||
let current = new Date(start);
|
let current = new Date(start);
|
||||||
|
|
||||||
@@ -58,8 +59,6 @@ function generateWeeks() {
|
|||||||
current.setDate(current.getDate() + 1);
|
current.setDate(current.getDate() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let weekCount = 1;
|
|
||||||
|
|
||||||
while (current <= end) {
|
while (current <= end) {
|
||||||
const monday = new Date(current);
|
const monday = new Date(current);
|
||||||
const tuesday = new Date(current);
|
const tuesday = new Date(current);
|
||||||
@@ -71,15 +70,21 @@ function generateWeeks() {
|
|||||||
const friday = new Date(current);
|
const friday = new Date(current);
|
||||||
friday.setDate(monday.getDate() + 4);
|
friday.setDate(monday.getDate() + 4);
|
||||||
|
|
||||||
const monthIndex = monday.getMonth();
|
|
||||||
const year = monday.getFullYear();
|
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 monthKey = `${year}-${String(monthIndex + 1).padStart(2, "0")}`;
|
||||||
const monthName = getMonthNameFr(monthIndex);
|
const monthName = getMonthNameFr(monthIndex);
|
||||||
|
|
||||||
weeks.push({
|
weeks.push({
|
||||||
|
id: weekId,
|
||||||
|
year,
|
||||||
|
weekOfYear,
|
||||||
monthKey,
|
monthKey,
|
||||||
monthName,
|
monthName,
|
||||||
weekLabel: `W${weekCount}`,
|
weekLabel: `W${weekOfYear}`,
|
||||||
days: {
|
days: {
|
||||||
mon: formatDayMonth(monday),
|
mon: formatDayMonth(monday),
|
||||||
tue: formatDayMonth(tuesday),
|
tue: formatDayMonth(tuesday),
|
||||||
@@ -87,10 +92,19 @@ function generateWeeks() {
|
|||||||
thu: formatDayMonth(thursday),
|
thu: formatDayMonth(thursday),
|
||||||
fri: formatDayMonth(friday),
|
fri: formatDayMonth(friday),
|
||||||
},
|
},
|
||||||
|
dayDates: {
|
||||||
|
mon: monday,
|
||||||
|
tue: tuesday,
|
||||||
|
wed: wednesday,
|
||||||
|
thu: thursday,
|
||||||
|
fri: friday,
|
||||||
|
},
|
||||||
|
totals: {
|
||||||
offCarole: 0,
|
offCarole: 0,
|
||||||
extraOffCarole: 0,
|
extraOffCarole: 0,
|
||||||
centre: 0,
|
centre: 0,
|
||||||
avis: 0,
|
avis: 0,
|
||||||
|
},
|
||||||
alex: {
|
alex: {
|
||||||
total: 0,
|
total: 0,
|
||||||
detail: "",
|
detail: "",
|
||||||
@@ -102,7 +116,6 @@ function generateWeeks() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
current.setDate(current.getDate() + 7);
|
current.setDate(current.getDate() + 7);
|
||||||
weekCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return weeks;
|
return weeks;
|
||||||
@@ -110,7 +123,70 @@ function generateWeeks() {
|
|||||||
|
|
||||||
const weeks = 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) {
|
function computeMonthSpans(weeks) {
|
||||||
const counts = {};
|
const counts = {};
|
||||||
@@ -122,7 +198,7 @@ function computeMonthSpans(weeks) {
|
|||||||
|
|
||||||
const monthSpans = computeMonthSpans(weeks);
|
const monthSpans = computeMonthSpans(weeks);
|
||||||
|
|
||||||
// === 3. Rendu du tableau ===
|
// === 5. Rendu du tableau ===
|
||||||
|
|
||||||
function renderTable() {
|
function renderTable() {
|
||||||
const planningBody = document.getElementById("planningBody");
|
const planningBody = document.getElementById("planningBody");
|
||||||
@@ -132,16 +208,16 @@ function renderTable() {
|
|||||||
|
|
||||||
const showOnlyCaroleOff =
|
const showOnlyCaroleOff =
|
||||||
document.getElementById("showOnlyCaroleOff")?.checked;
|
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) => {
|
weeks.forEach((week) => {
|
||||||
if (showOnlyCaroleOff && week.offCarole === 0) return;
|
if (showOnlyCaroleOff && week.totals.offCarole === 0) return;
|
||||||
|
|
||||||
const tr = document.createElement("tr");
|
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]) {
|
if (!monthRowRendered[week.monthKey]) {
|
||||||
monthRowRendered[week.monthKey] = true;
|
monthRowRendered[week.monthKey] = true;
|
||||||
const tdMonth = document.createElement("td");
|
const tdMonth = document.createElement("td");
|
||||||
@@ -150,108 +226,62 @@ function renderTable() {
|
|||||||
tr.appendChild(tdMonth);
|
tr.appendChild(tdMonth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colonne Semaine
|
// Semaine
|
||||||
const tdWeek = document.createElement("td");
|
const tdWeek = document.createElement("td");
|
||||||
tdWeek.textContent = week.weekLabel;
|
tdWeek.textContent = week.weekLabel;
|
||||||
tr.appendChild(tdWeek);
|
tr.appendChild(tdWeek);
|
||||||
|
|
||||||
// Jours Lundi -> Vendredi
|
// Jours
|
||||||
["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => {
|
["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => {
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
td.textContent = week.days[dayKey];
|
td.textContent = week.days[dayKey];
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
|
|
||||||
// # Off Carole
|
// Totaux # Off Carole, # Extra off, #Centre, #Avis
|
||||||
const tdOff = document.createElement("td");
|
const tdOff = document.createElement("td");
|
||||||
tdOff.innerHTML = `<input type="number" step="0.25" min="0" value="${week.offCarole}" data-week="${index}" data-field="offCarole">`;
|
tdOff.textContent = week.totals.offCarole.toFixed(2).replace(/\.00$/, "");
|
||||||
tr.appendChild(tdOff);
|
tr.appendChild(tdOff);
|
||||||
|
|
||||||
// # Extra off Carole
|
|
||||||
const tdExtraOff = document.createElement("td");
|
const tdExtraOff = document.createElement("td");
|
||||||
tdExtraOff.innerHTML = `<input type="number" step="0.25" min="0" value="${week.extraOffCarole}" data-week="${index}" data-field="extraOffCarole">`;
|
tdExtraOff.textContent = week.totals.extraOffCarole
|
||||||
|
.toFixed(2)
|
||||||
|
.replace(/\.00$/, "");
|
||||||
tr.appendChild(tdExtraOff);
|
tr.appendChild(tdExtraOff);
|
||||||
|
|
||||||
// #Centre
|
|
||||||
const tdCentre = document.createElement("td");
|
const tdCentre = document.createElement("td");
|
||||||
tdCentre.innerHTML = `<input type="number" step="0.25" min="0" value="${week.centre}" data-week="${index}" data-field="centre">`;
|
tdCentre.textContent = week.totals.centre.toFixed(2).replace(/\.00$/, "");
|
||||||
tr.appendChild(tdCentre);
|
tr.appendChild(tdCentre);
|
||||||
|
|
||||||
// #Avis
|
|
||||||
const tdAvis = document.createElement("td");
|
const tdAvis = document.createElement("td");
|
||||||
tdAvis.innerHTML = `<input type="number" step="0.25" min="0" value="${week.avis}" data-week="${index}" data-field="avis">`;
|
tdAvis.textContent = week.totals.avis.toFixed(2).replace(/\.00$/, "");
|
||||||
tr.appendChild(tdAvis);
|
tr.appendChild(tdAvis);
|
||||||
|
|
||||||
// Alex total & détail
|
// Alex total & détail (pour l'instant, juste placeholders)
|
||||||
const tdAlexTotal = document.createElement("td");
|
const tdAlexTotal = document.createElement("td");
|
||||||
tdAlexTotal.textContent = week.alex.total.toFixed
|
tdAlexTotal.textContent = week.alex.total.toFixed(2).replace(/\.00$/, "");
|
||||||
? week.alex.total.toFixed(2)
|
|
||||||
: week.alex.total;
|
|
||||||
tr.appendChild(tdAlexTotal);
|
tr.appendChild(tdAlexTotal);
|
||||||
|
|
||||||
const tdAlexDetail = document.createElement("td");
|
const tdAlexDetail = document.createElement("td");
|
||||||
tdAlexDetail.innerHTML = `<input type="text" value="${
|
tdAlexDetail.textContent = week.alex.detail || "";
|
||||||
week.alex.detail || ""
|
|
||||||
}" data-week="${index}" data-field="alex.detail">`;
|
|
||||||
tr.appendChild(tdAlexDetail);
|
tr.appendChild(tdAlexDetail);
|
||||||
|
|
||||||
// Laia total & détail
|
// Laia total & détail
|
||||||
const tdLaiaTotal = document.createElement("td");
|
const tdLaiaTotal = document.createElement("td");
|
||||||
tdLaiaTotal.textContent = week.laia.total.toFixed
|
tdLaiaTotal.textContent = week.laia.total.toFixed(2).replace(/\.00$/, "");
|
||||||
? week.laia.total.toFixed(2)
|
|
||||||
: week.laia.total;
|
|
||||||
tr.appendChild(tdLaiaTotal);
|
tr.appendChild(tdLaiaTotal);
|
||||||
|
|
||||||
const tdLaiaDetail = document.createElement("td");
|
const tdLaiaDetail = document.createElement("td");
|
||||||
tdLaiaDetail.innerHTML = `<input type="text" value="${
|
tdLaiaDetail.textContent = week.laia.detail || "";
|
||||||
week.laia.detail || ""
|
|
||||||
}" data-week="${index}" data-field="laia.detail">`;
|
|
||||||
tr.appendChild(tdLaiaDetail);
|
tr.appendChild(tdLaiaDetail);
|
||||||
|
|
||||||
planningBody.appendChild(tr);
|
planningBody.appendChild(tr);
|
||||||
});
|
});
|
||||||
|
|
||||||
attachInputListeners();
|
|
||||||
updateSummary();
|
updateSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 4. Listeners sur les inputs ===
|
// === 6. Résumé (encore 0 utilisés pour l’instant) ===
|
||||||
|
|
||||||
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) ===
|
|
||||||
|
|
||||||
function updateSummary() {
|
function updateSummary() {
|
||||||
const summaryDiv = document.getElementById("summaryText");
|
const summaryDiv = document.getElementById("summaryText");
|
||||||
@@ -277,7 +307,6 @@ function updateSummary() {
|
|||||||
document.getElementById("laiaJaInit")?.value || "0"
|
document.getElementById("laiaJaInit")?.value || "0"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Pour l'instant, on n'a pas encore branché les CP/RTT/JA par semaine
|
|
||||||
const alexCpUsed = 0;
|
const alexCpUsed = 0;
|
||||||
const alexRttUsed = 0;
|
const alexRttUsed = 0;
|
||||||
const alexJaUsed = 0;
|
const alexJaUsed = 0;
|
||||||
@@ -319,12 +348,11 @@ function updateSummary() {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 6. Init ===
|
// === 7. Init ===
|
||||||
|
|
||||||
function initFamilyCalendar() {
|
function initFamilyCalendar() {
|
||||||
if (!document.getElementById("planningBody")) return;
|
if (!document.getElementById("planningBody")) return;
|
||||||
|
|
||||||
// Soldes initiaux
|
|
||||||
[
|
[
|
||||||
"alexCpInit",
|
"alexCpInit",
|
||||||
"alexRttInit",
|
"alexRttInit",
|
||||||
@@ -337,7 +365,6 @@ function initFamilyCalendar() {
|
|||||||
if (el) el.addEventListener("change", updateSummary);
|
if (el) el.addEventListener("change", updateSummary);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Filtres (pour l'instant seul showOnlyCaroleOff a un effet)
|
|
||||||
const showOnlyCaroleOff = document.getElementById("showOnlyCaroleOff");
|
const showOnlyCaroleOff = document.getElementById("showOnlyCaroleOff");
|
||||||
if (showOnlyCaroleOff) {
|
if (showOnlyCaroleOff) {
|
||||||
showOnlyCaroleOff.addEventListener("change", renderTable);
|
showOnlyCaroleOff.addEventListener("change", renderTable);
|
||||||
|
|||||||
@@ -111,5 +111,6 @@ require __DIR__ . '/header.php';
|
|||||||
|
|
||||||
<script src="/assets/js/family-calendar.js"></script>
|
<script src="/assets/js/family-calendar.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
require __DIR__ . '/footer.php';
|
require __DIR__ . '/footer.php';
|
||||||
|
|||||||
Reference in New Issue
Block a user