Auto-commit for deploy to production - 2025-12-09 12:01:13

This commit is contained in:
2025-12-09 12:01:14 +01:00
parent 035adcbced
commit dd41f0c6c0
3 changed files with 193 additions and 67 deletions
+29
View File
@@ -173,3 +173,32 @@ input[type="number"] {
.fc-row--bank-holiday {
background: #d9f7be;
}
/* Ligne de semaine contenant au moins un jour de vacances scolaires */
.fc-row--school-holiday {
background-color: #fff5cc;
}
/* Jour individuel en vacances scolaires (cellule) */
.fc-day--school-holiday {
background-color: #ffe9a6;
}
/* Tableau recap vacances scolaires */
.fc-holidays-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
margin-top: 12px;
}
.fc-holidays-table th,
.fc-holidays-table td {
border: 1px solid #d9e2ec;
padding: 4px 6px;
text-align: left;
}
.fc-holidays-table th {
background-color: #f0f4f8;
}
+142 -67
View File
@@ -27,18 +27,17 @@ function getMonthNameFr(monthIndex) {
}
/**
* Calcule le numéro de semaine dans l'année (1..52/53),
* en prenant le lundi comme début de semaine.
* Calcule le n° de semaine dans l'année (1..),
* Semaine 1 = semaine contenant le 1er janvier, début au lundi.
*/
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 dayOfWeek = startOfYear.getDay() || 7; // dimanche = 0 -> 7
const diffToMonday = dayOfWeek === 1 ? 0 : dayOfWeek - 1;
const firstWeekMonday = new Date(year, 0, 1 - diffToMonday);
const diffMillis = date - firstMonday;
const diffMillis = date - firstWeekMonday;
const diffDays = Math.floor(diffMillis / (1000 * 60 * 60 * 24));
return Math.floor(diffDays / 7) + 1;
}
@@ -99,12 +98,20 @@ function generateWeeks() {
thu: thursday,
fri: friday,
},
dayFlags: {
mon: { schoolHoliday: false },
tue: { schoolHoliday: false },
wed: { schoolHoliday: false },
thu: { schoolHoliday: false },
fri: { schoolHoliday: false },
},
totals: {
offCarole: 0,
extraOffCarole: 0,
centre: 0,
avis: 0,
},
isSchoolHolidayWeek: false,
alex: {
total: 0,
detail: "",
@@ -123,68 +130,119 @@ function generateWeeks() {
const weeks = generateWeeks();
// === 3. Événements calendrier (exemple, plus tard ce sera ton UI/DB) ===
// === 3. Événements & vacances scolaires ===
/**
* 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.
];
const events = []; // on pourra y ajouter OFF_CAROLE, CENTRE, etc. plus tard
/**
* 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;
async function fetchSchoolHolidays(anneeScolaire, zoneLabel) {
const baseUrl =
"https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/fr-en-calendrier-scolaire/records";
const where = `annee_scolaire='${anneeScolaire}' AND zones LIKE '%${zoneLabel}%'`;
const params = new URLSearchParams({
where,
limit: "100",
order_by: "start_date",
});
events.forEach((evt) => {
const [y, m, d] = evt.date.split("-").map(Number);
const evtDate = new Date(y, m - 1, d);
const url = `${baseUrl}?${params.toString()}`;
// 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 res = await fetch(url);
if (!res.ok) {
console.error("Erreur API vacances scolaires", res.status, res.statusText);
return [];
}
const dur = evt.duration || 1;
const data = await res.json();
return data.results || [];
}
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;
/**
* Ajoute les vacances scolaires comme événements de type VACANCES_SCOLAIRES
* ET remplit le tableau recap.
*/
function addSchoolHolidayEventsFromRecords(records, events) {
const tbody = document.querySelector("#schoolHolidaysTable tbody");
if (tbody) tbody.innerHTML = "";
records.forEach((record) => {
const start = new Date(record.start_date);
const end = new Date(record.end_date);
// Remplir le tableau recap
if (tbody) {
const tr = document.createElement("tr");
const startStr = formatDayMonth(start) + "/" + start.getFullYear();
const endStr = formatDayMonth(end) + "/" + end.getFullYear();
tr.innerHTML = `
<td>${record.description || ""}</td>
<td>${startStr}</td>
<td>${endStr}</td>
<td>${record.zones || ""}</td>
<td>${record.location || ""}</td>
`;
tbody.appendChild(tr);
}
// Chaque jour de la plage -> event VACANCES_SCOLAIRES
let current = new Date(start);
while (current <= end) {
const year = current.getFullYear();
const month = String(current.getMonth() + 1).padStart(2, "0");
const day = String(current.getDate()).padStart(2, "0");
const isoDate = `${year}-${month}-${day}`;
events.push({
date: isoDate,
type: "VACANCES_SCOLAIRES",
duration: 1,
});
current.setDate(current.getDate() + 1);
}
});
}
// première agrégation
recomputeTotalsFromEvents(weeks, events);
/**
* Marque les jours & semaines de vacances scolaires dans weeks.
*/
function markSchoolHolidayDaysAndWeeks(weeks, events) {
// reset
weeks.forEach((w) => {
w.isSchoolHolidayWeek = false;
Object.keys(w.dayFlags).forEach((dayKey) => {
w.dayFlags[dayKey].schoolHoliday = false;
});
});
events.forEach((evt) => {
if (evt.type !== "VACANCES_SCOLAIRES") return;
const [y, m, d] = evt.date.split("-").map(Number);
const evtDate = new Date(y, m - 1, d);
weeks.forEach((w) => {
const dayKeys = ["mon", "tue", "wed", "thu", "fri"];
let hasHolidayInWeek = false;
dayKeys.forEach((dayKey) => {
const dayDate = w.dayDates[dayKey];
if (
dayDate.getFullYear() === evtDate.getFullYear() &&
dayDate.getMonth() === evtDate.getMonth() &&
dayDate.getDate() === evtDate.getDate()
) {
w.dayFlags[dayKey].schoolHoliday = true;
hasHolidayInWeek = true;
}
});
if (hasHolidayInWeek) {
w.isSchoolHolidayWeek = true;
}
});
});
}
// === 4. Calcul des rowspans pour la colonne Mois ===
@@ -208,16 +266,23 @@ function renderTable() {
const showOnlyCaroleOff =
document.getElementById("showOnlyCaroleOff")?.checked;
// showOnlySchoolHoliday est ignoré pour l'instant
const showOnlySchoolHoliday = document.getElementById(
"showOnlySchoolHoliday"
)?.checked;
const monthRowRendered = {};
weeks.forEach((week) => {
if (showOnlyCaroleOff && week.totals.offCarole === 0) return;
if (showOnlySchoolHoliday && !week.isSchoolHolidayWeek) return;
const tr = document.createElement("tr");
// Colonne Mois (rowspan sur toutes les semaines du mois)
if (week.isSchoolHolidayWeek) {
tr.classList.add("fc-row--school-holiday");
}
// Colonne Mois
if (!monthRowRendered[week.monthKey]) {
monthRowRendered[week.monthKey] = true;
const tdMonth = document.createElement("td");
@@ -226,19 +291,22 @@ function renderTable() {
tr.appendChild(tdMonth);
}
// Semaine
// Colonne Semaine
const tdWeek = document.createElement("td");
tdWeek.textContent = week.weekLabel;
tr.appendChild(tdWeek);
// Jours
// Jours (Lun -> Ven) avec coloration jours de vacances
["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => {
const td = document.createElement("td");
td.textContent = week.days[dayKey];
if (week.dayFlags[dayKey].schoolHoliday) {
td.classList.add("fc-day--school-holiday");
}
tr.appendChild(td);
});
// Totaux # Off Carole, # Extra off, #Centre, #Avis
// Totaux # Off / Extra / Centre / Avis (pour l'instant à 0)
const tdOff = document.createElement("td");
tdOff.textContent = week.totals.offCarole.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdOff);
@@ -257,7 +325,7 @@ function renderTable() {
tdAvis.textContent = week.totals.avis.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdAvis);
// Alex total & détail (pour l'instant, juste placeholders)
// Alex total & détail
const tdAlexTotal = document.createElement("td");
tdAlexTotal.textContent = week.alex.total.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdAlexTotal);
@@ -281,7 +349,7 @@ function renderTable() {
updateSummary();
}
// === 6. Résumé (encore 0 utilisés pour linstant) ===
// === 6. Résumé (toujours 0 utilisés pour l'instant) ===
function updateSummary() {
const summaryDiv = document.getElementById("summaryText");
@@ -350,7 +418,7 @@ function updateSummary() {
// === 7. Init ===
function initFamilyCalendar() {
async function initFamilyCalendar() {
if (!document.getElementById("planningBody")) return;
[
@@ -376,7 +444,14 @@ function initFamilyCalendar() {
showOnlySchoolHoliday.addEventListener("change", renderTable);
}
// Charger vacances scolaires 2025-2026, Zone C
const holidaysRecords = await fetchSchoolHolidays("2025-2026", "Zone C");
addSchoolHolidayEventsFromRecords(holidaysRecords, events);
markSchoolHolidayDaysAndWeeks(weeks, events);
renderTable();
}
document.addEventListener("DOMContentLoaded", initFamilyCalendar);
document.addEventListener("DOMContentLoaded", () => {
initFamilyCalendar().catch((err) => console.error(err));
});
+22
View File
@@ -109,6 +109,28 @@ require __DIR__ . '/header.php';
</div>
</section>
<section class="pf-section">
<h2>Vacances scolaires - Zone C (2025-2026)</h2>
<p>Source : data.education.gouv.fr - calendrier officiel.</p>
<div class="pf-table-wrapper">
<table id="schoolHolidaysTable" class="fc-holidays-table">
<thead>
<tr>
<th>Période</th>
<th>Du</th>
<th>Au</th>
<th>Zones</th>
<th>Académies</th>
</tr>
</thead>
<tbody>
<!-- Rempli par JS -->
</tbody>
</table>
</div>
</section>
<script src="/assets/js/family-calendar.js"></script>