Auto-commit for deploy to production - 2025-12-09 19:16:55

This commit is contained in:
2025-12-09 19:16:55 +01:00
parent deb7eed1ff
commit 5bf666402c
3 changed files with 245 additions and 241 deletions
+49
View File
@@ -193,3 +193,52 @@ input[type="number"] {
.fc-holidays-table th { .fc-holidays-table th {
background-color: #f0f4f8; background-color: #f0f4f8;
} }
/* Cellule de jour sélectionnée dans le calendrier */
.fc-day--selected {
background-color: #bde4ff !important; /* Une couleur de sélection claire, !important pour forcer le style */
cursor: pointer;
}
/* Le menu contextuel flottant */
.fc-selection-menu {
display: none; /* Caché par défaut */
position: absolute; /* Permet de le positionner près de la souris */
z-index: 100;
background-color: white;
border: 1px solid #ccc;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border-radius: 6px;
padding: 8px;
font-size: 12px;
}
.fc-selection-menu .fc-menu-section {
margin-bottom: 8px;
}
.fc-selection-menu .fc-menu-section:last-child {
margin-bottom: 0;
}
.fc-selection-menu strong {
display: block;
margin-bottom: 4px;
font-weight: 600;
}
.fc-selection-menu button {
display: block;
width: 100%;
background: none;
border: 1px solid #ddd;
border-radius: 4px;
padding: 4px 8px;
margin-top: 4px;
text-align: left;
cursor: pointer;
}
.fc-selection-menu button:hover {
background-color: #f0f4f8;
border-color: #b0c4de;
}
+184 -241
View File
@@ -1,7 +1,12 @@
// assets/js/family-calendar.js // assets/js/family-calendar.js
// === 1. Utilitaires dates === // === VARIABLES GLOBALES POUR LA SÉLECTION ===
let isSelecting = false;
let selectedCells = [];
const events = []; // Contient TOUS les événements (vacances, off carole, centre, avis)
// === 1. Utilitaires dates ===
// ... (garder les fonctions formatDayMonth, getMonthNameFr, getWeekOfYear)
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");
@@ -26,38 +31,26 @@ function getMonthNameFr(monthIndex) {
return map[monthIndex] || ""; return map[monthIndex] || "";
} }
/**
* Calcule le n° de semaine dans l'année (1..),
* Semaine 1 = semaine contenant le 1er janvier, début au lundi.
*/
function getWeekOfYear(date) { function getWeekOfYear(date) {
const year = date.getFullYear(); const year = date.getFullYear();
const startOfYear = new Date(year, 0, 1); const startOfYear = new Date(year, 0, 1);
const dayOfWeek = startOfYear.getDay() || 7; // dimanche = 0 -> 7 const dayOfWeek = startOfYear.getDay() || 7;
const diffToMonday = dayOfWeek === 1 ? 0 : dayOfWeek - 1; const diffToMonday = dayOfWeek === 1 ? 0 : dayOfWeek - 1;
const firstWeekMonday = new Date(year, 0, 1 - diffToMonday); const firstWeekMonday = new Date(year, 0, 1 - diffToMonday);
const diffMillis = date - firstWeekMonday; const diffMillis = date - firstWeekMonday;
const diffDays = Math.floor(diffMillis / (1000 * 60 * 60 * 24)); const diffDays = Math.floor(diffMillis / (1000 * 60 * 60 * 24));
return Math.floor(diffDays / 7) + 1; return Math.floor(diffDays / 7) + 1;
} }
// === 2. Génération des semaines === // === 2. Génération des semaines ===
function generateWeeks() { function generateWeeks() {
const weeks = []; const weeks = [];
const start = new Date(2025, 8, 1);
const start = new Date(2025, 8, 1); // 1er sept 2025 const end = new Date(2026, 7, 31);
const end = new Date(2026, 7, 31); // 31 aout 2026
let current = new Date(start); let current = new Date(start);
// se placer sur le premier lundi >= 1er septembre 2025
while (current.getDay() !== 1) { while (current.getDay() !== 1) {
// 1 = lundi
current.setDate(current.getDate() + 1); current.setDate(current.getDate() + 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);
@@ -68,21 +61,17 @@ function generateWeeks() {
thursday.setDate(monday.getDate() + 3); thursday.setDate(monday.getDate() + 3);
const friday = new Date(current); const friday = new Date(current);
friday.setDate(monday.getDate() + 4); friday.setDate(monday.getDate() + 4);
const year = monday.getFullYear(); const year = monday.getFullYear();
const weekOfYear = getWeekOfYear(monday); const weekOfYear = getWeekOfYear(monday);
const weekId = `${year}-W${String(weekOfYear).padStart(2, "0")}`; const weekId = `${year}-W${String(weekOfYear).padStart(2, "0")}`;
const monthIndex = monday.getMonth(); 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);
weeks.push({ weeks.push({
id: weekId, id: weekId,
year, year,
weekOfYear, weekOfYear,
monthKey, monthKey,
monthName, monthName: getMonthNameFr(monthIndex),
weekLabel: `W${weekOfYear}`, weekLabel: `W${weekOfYear}`,
days: { days: {
mon: formatDayMonth(monday), mon: formatDayMonth(monday),
@@ -105,135 +94,86 @@ function generateWeeks() {
thu: { schoolHoliday: false }, thu: { schoolHoliday: false },
fri: { schoolHoliday: false }, fri: { schoolHoliday: false },
}, },
totals: { totals: { offCarole: 0, extraOffCarole: 0, centre: 0, avis: 0 },
offCarole: 0,
extraOffCarole: 0,
centre: 0,
avis: 0,
},
isSchoolHolidayWeek: false, isSchoolHolidayWeek: false,
alex: { alex: { total: 0, detail: "" },
total: 0, laia: { total: 0, detail: "" },
detail: "",
},
laia: {
total: 0,
detail: "",
},
}); });
current.setDate(current.getDate() + 7); current.setDate(current.getDate() + 7);
} }
return weeks; return weeks;
} }
const weeks = generateWeeks(); const weeks = generateWeeks();
const events = []; // tous les evenements (vacances, off Carole, centre, etc.)
// === 3. Vacances scolaires (API gouv) === // === 3. Gestion des événements (Vacances, Off, Centre, Avis) ===
async function fetchSchoolHolidays(anneeScolaire, zoneLabel) { async function fetchSchoolHolidays(anneeScolaire, zoneLabel) {
const baseUrl = const baseUrl =
"https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/fr-en-calendrier-scolaire/records"; "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 where = `annee_scolaire='${anneeScolaire}' AND zones LIKE '%${zoneLabel}%'`;
const params = new URLSearchParams({ const params = new URLSearchParams({
where, where,
limit: "100", limit: "100",
order_by: "start_date", order_by: "start_date",
}); });
const url = `${baseUrl}?${params.toString()}`; const url = `${baseUrl}?${params.toString()}`;
const res = await fetch(url); const res = await fetch(url);
if (!res.ok) { if (!res.ok) {
console.error("Erreur API vacances scolaires", res.status, res.statusText); console.error("Erreur API vacances scolaires", res.status, res.statusText);
return []; return [];
} }
const data = await res.json(); const data = await res.json();
return data.results || []; return data.results || [];
} }
/**
* Regroupe les records par période, remplit le tableau recap,
* et crée les événements VACANCES_SCOLAIRES.
* Version corrigée pour gérer les fuseaux horaires de manière robuste.
*/
function addSchoolHolidayEventsFromRecords(records, events) { function addSchoolHolidayEventsFromRecords(records, events) {
const tbody = document.querySelector("#schoolHolidaysTable tbody"); const tbody = document.querySelector("#schoolHolidaysTable tbody");
if (tbody) tbody.innerHTML = ""; if (tbody) tbody.innerHTML = "";
// 1) Regrouper par période pour éviter les doublons d'académies
const groups = new Map(); const groups = new Map();
records.forEach((record) => { records.forEach((record) => {
const startIso = record.start_date; const key = `${record.start_date}|${record.end_date}|${record.description}`;
const endIso = record.end_date;
const desc = record.description || "";
const zones = record.zones || "";
const key = `${startIso}|${endIso}|${desc}`;
if (!groups.has(key)) { if (!groups.has(key)) {
groups.set(key, { startIso, endIso, description: desc, zones }); groups.set(key, {
startIso: record.start_date,
endIso: record.end_date,
description: record.description || "",
zones: record.zones || "",
});
} }
}); });
// 2) Remplir le tableau récap ET créer les événements pour la coloration
if (tbody) { if (tbody) {
Array.from(groups.values()) Array.from(groups.values())
.sort((a, b) => new Date(a.startIso) - new Date(b.startIso)) .sort((a, b) => new Date(a.startIso) - new Date(b.startIso))
.forEach((g) => { .forEach((g) => {
// --- Logique de dates explicite et robuste --- const firstDayVacation = new Date(
g.startIso.substring(0, 10) + "T00:00:00"
// On extrait la partie YYYY-MM-DD pour éviter les bugs de fuseau horaire );
const startDateString = g.startIso.substring(0, 10); // ex: "2025-10-17" firstDayVacation.setDate(firstDayVacation.getDate() + 1);
const endDateString = g.endIso.substring(0, 10); // ex: "2025-11-02" const lastDayVacation = new Date(
g.endIso.substring(0, 10) + "T00:00:00"
// On crée les dates en spécifiant T00:00:00 pour qu'elles soient interprétées comme locales );
const firstDayVacation = new Date(startDateString + "T00:00:00");
firstDayVacation.setDate(firstDayVacation.getDate() + 1); // Le 1er jour est le lendemain du "vendredi soir"
const lastDayVacation = new Date(endDateString + "T00:00:00");
// La date de reprise est le lendemain du dernier jour de vacances
const repriseDate = new Date(lastDayVacation); const repriseDate = new Date(lastDayVacation);
repriseDate.setDate(repriseDate.getDate() + 1); repriseDate.setDate(repriseDate.getDate() + 1);
// --- Affichage dans le tableau récap ---
const startStr = const startStr =
formatDayMonth(firstDayVacation) + formatDayMonth(firstDayVacation) +
"/" + "/" +
firstDayVacation.getFullYear(); firstDayVacation.getFullYear();
const endStr = const endStr =
formatDayMonth(repriseDate) + "/" + repriseDate.getFullYear(); formatDayMonth(repriseDate) + "/" + repriseDate.getFullYear();
const tr = document.createElement("tr"); const tr = document.createElement("tr");
tr.innerHTML = ` tr.innerHTML = `<td>${g.description}</td><td>${startStr}</td><td>${endStr}</td><td>${g.zones}</td>`;
<td>${g.description}</td>
<td>${startStr}</td>
<td>${endStr}</td>
<td>${g.zones}</td>
`;
tbody.appendChild(tr); tbody.appendChild(tr);
// --- Création des événements pour la coloration du calendrier ---
// On boucle du premier jour de vacances jusqu'au dernier jour INCLUS.
let current = new Date(firstDayVacation); let current = new Date(firstDayVacation);
while (current <= lastDayVacation) { while (current <= lastDayVacation) {
const year = current.getFullYear(); const isoDate = `${current.getFullYear()}-${String(
const month = String(current.getMonth() + 1).padStart(2, "0"); current.getMonth() + 1
const day = String(current.getDate()).padStart(2, "0"); ).padStart(2, "0")}-${String(current.getDate()).padStart(2, "0")}`;
const isoDate = `${year}-${month}-${day}`;
events.push({ events.push({
date: isoDate, date: isoDate,
type: "VACANCES_SCOLAIRES", type: "VACANCES_SCOLAIRES",
duration: 1, duration: 1,
}); });
current.setDate(current.getDate() + 1); current.setDate(current.getDate() + 1);
} }
}); });
@@ -241,47 +181,59 @@ function addSchoolHolidayEventsFromRecords(records, events) {
} }
/** /**
* Marque les jours et les semaines de vacances scolaires dans weeks. * Marque les jours de vacances et recalcule les totaux pour Off Carole, Centre, Avis
*/ */
function markSchoolHolidayDaysAndWeeks(weeks, events) { function reprocessEvents(weeks, events) {
// reset // Reset all flags and totals
weeks.forEach((w) => { weeks.forEach((w) => {
w.isSchoolHolidayWeek = false; w.isSchoolHolidayWeek = false;
Object.keys(w.dayFlags).forEach((dayKey) => { Object.keys(w.dayFlags).forEach(
w.dayFlags[dayKey].schoolHoliday = false; (dayKey) => (w.dayFlags[dayKey].schoolHoliday = false)
}); );
w.totals = { offCarole: 0, extraOffCarole: 0, centre: 0, avis: 0 };
}); });
// Apply each event to the corresponding week
events.forEach((evt) => { events.forEach((evt) => {
if (evt.type !== "VACANCES_SCOLAIRES") return;
const [y, m, d] = evt.date.split("-").map(Number); const [y, m, d] = evt.date.split("-").map(Number);
const evtDate = new Date(y, m - 1, d); const evtDate = new Date(y, m - 1, d);
weeks.forEach((w) => { const week = weeks.find(
const dayKeys = ["mon", "tue", "wed", "thu", "fri"]; (w) => evtDate >= w.dayDates.mon && evtDate <= w.dayDates.fri
let hasHolidayInWeek = false; );
if (!week) return;
dayKeys.forEach((dayKey) => { const dur = evt.duration || 1;
const dayDate = w.dayDates[dayKey];
if ( switch (evt.type) {
dayDate.getFullYear() === evtDate.getFullYear() && case "VACANCES_SCOLAIRES":
dayDate.getMonth() === evtDate.getMonth() && const dayKey = Object.keys(week.dayDates).find(
dayDate.getDate() === evtDate.getDate() (key) => week.dayDates[key].toDateString() === evtDate.toDateString()
) { );
w.dayFlags[dayKey].schoolHoliday = true; if (dayKey) {
hasHolidayInWeek = true; week.dayFlags[dayKey].schoolHoliday = true;
week.isSchoolHolidayWeek = true;
} }
}); break;
case "OFF_CAROLE":
if (hasHolidayInWeek) { week.totals.offCarole += dur;
w.isSchoolHolidayWeek = true; 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;
}
}); });
} }
// === 4. Calcul des rowspans pour la colonne Mois === // === 4. Rendu et logique d'affichage ===
function computeMonthSpans(weeks) { function computeMonthSpans(weeks) {
const counts = {}; const counts = {};
@@ -290,15 +242,11 @@ function computeMonthSpans(weeks) {
}); });
return counts; return counts;
} }
const monthSpans = computeMonthSpans(weeks); const monthSpans = computeMonthSpans(weeks);
// === 5. Rendu du tableau principal ===
function renderTable() { function renderTable() {
const planningBody = document.getElementById("planningBody"); const planningBody = document.getElementById("planningBody");
if (!planningBody) return; if (!planningBody) return;
planningBody.innerHTML = ""; planningBody.innerHTML = "";
const showOnlyCaroleOff = const showOnlyCaroleOff =
@@ -306,7 +254,6 @@ function renderTable() {
const showOnlySchoolHoliday = document.getElementById( const showOnlySchoolHoliday = document.getElementById(
"showOnlySchoolHoliday" "showOnlySchoolHoliday"
)?.checked; )?.checked;
const monthRowRendered = {}; const monthRowRendered = {};
weeks.forEach((week) => { weeks.forEach((week) => {
@@ -315,7 +262,6 @@ function renderTable() {
const tr = document.createElement("tr"); const tr = document.createElement("tr");
// Colonne 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");
@@ -324,14 +270,17 @@ function renderTable() {
tr.appendChild(tdMonth); tr.appendChild(tdMonth);
} }
// Colonne 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 (Lun -> Ven) avec coloration jours de vacances
["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => { ["mon", "tue", "wed", "thu", "fri"].forEach((dayKey) => {
const td = document.createElement("td"); const td = document.createElement("td");
const dayDate = week.dayDates[dayKey];
const isoDate = `${dayDate.getFullYear()}-${String(
dayDate.getMonth() + 1
).padStart(2, "0")}-${String(dayDate.getDate()).padStart(2, "0")}`;
td.dataset.date = isoDate; // IMPORTANT: on ajoute la date pour la retrouver
td.textContent = week.days[dayKey]; td.textContent = week.days[dayKey];
if (week.dayFlags[dayKey].schoolHoliday) { if (week.dayFlags[dayKey].schoolHoliday) {
td.classList.add("fc-day--school-holiday"); td.classList.add("fc-day--school-holiday");
@@ -339,121 +288,71 @@ function renderTable() {
tr.appendChild(td); tr.appendChild(td);
}); });
// Totaux # Off / Extra / Centre / Avis (pour l'instant à 0) const formatTotal = (total) =>
const tdOff = document.createElement("td"); total > 0 ? (Number.isInteger(total) ? total : total.toFixed(1)) : "";
tdOff.textContent = week.totals.offCarole.toFixed(2).replace(/\.00$/, ""); tr.innerHTML += `
tr.appendChild(tdOff); <td>${formatTotal(week.totals.offCarole)}</td>
<td>${formatTotal(week.totals.extraOffCarole)}</td>
const tdExtraOff = document.createElement("td"); <td>${formatTotal(week.totals.centre)}</td>
tdExtraOff.textContent = week.totals.extraOffCarole <td>${formatTotal(week.totals.avis)}</td>
.toFixed(2) <td>${formatTotal(week.alex.total)}</td>
.replace(/\.00$/, ""); <td>${week.alex.detail || ""}</td>
tr.appendChild(tdExtraOff); <td>${formatTotal(week.laia.total)}</td>
<td>${week.laia.detail || ""}</td>
const tdCentre = document.createElement("td"); `;
tdCentre.textContent = week.totals.centre.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdCentre);
const tdAvis = document.createElement("td");
tdAvis.textContent = week.totals.avis.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdAvis);
// Alex total & détail
const tdAlexTotal = document.createElement("td");
tdAlexTotal.textContent = week.alex.total.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdAlexTotal);
const tdAlexDetail = document.createElement("td");
tdAlexDetail.textContent = week.alex.detail || "";
tr.appendChild(tdAlexDetail);
// Laia total & détail
const tdLaiaTotal = document.createElement("td");
tdLaiaTotal.textContent = week.laia.total.toFixed(2).replace(/\.00$/, "");
tr.appendChild(tdLaiaTotal);
const tdLaiaDetail = document.createElement("td");
tdLaiaDetail.textContent = week.laia.detail || "";
tr.appendChild(tdLaiaDetail);
planningBody.appendChild(tr); planningBody.appendChild(tr);
}); });
updateSummary(); updateSummary();
} }
// === 6. Résumé (pour l'instant, 0 utilisés) ===
function updateSummary() { function updateSummary() {
const summaryDiv = document.getElementById("summaryText"); // ... (garder la fonction updateSummary telle quelle)
if (!summaryDiv) return;
const alexCpInit = parseFloat(
document.getElementById("alexCpInit")?.value || "0"
);
const alexRttInit = parseFloat(
document.getElementById("alexRttInit")?.value || "0"
);
const alexJaInit = parseFloat(
document.getElementById("alexJaInit")?.value || "0"
);
const laiaCpInit = parseFloat(
document.getElementById("laiaCpInit")?.value || "0"
);
const laiaRttInit = parseFloat(
document.getElementById("laiaRttInit")?.value || "0"
);
const laiaJaInit = parseFloat(
document.getElementById("laiaJaInit")?.value || "0"
);
const alexCpUsed = 0;
const alexRttUsed = 0;
const alexJaUsed = 0;
const laiaCpUsed = 0;
const laiaRttUsed = 0;
const laiaJaUsed = 0;
const alexCpLeft = alexCpInit - alexCpUsed;
const alexRttLeft = alexRttInit - alexRttUsed;
const alexJaLeft = alexJaInit - alexJaUsed;
const laiaCpLeft = laiaCpInit - laiaCpUsed;
const laiaRttLeft = laiaRttInit - laiaRttUsed;
const laiaJaLeft = laiaJaInit - laiaJaUsed;
summaryDiv.innerHTML = `
<p><strong>Alex</strong><br>
CP utilises : ${alexCpUsed.toFixed(2)} / ${alexCpInit.toFixed(
2
)} (reste ${alexCpLeft.toFixed(2)})<br>
RTT utilises : ${alexRttUsed.toFixed(2)} / ${alexRttInit.toFixed(
2
)} (reste ${alexRttLeft.toFixed(2)})<br>
JA utilises : ${alexJaUsed.toFixed(2)} / ${alexJaInit.toFixed(
2
)} (reste ${alexJaLeft.toFixed(2)})</p>
<p><strong>Laia</strong><br>
CP utilises : ${laiaCpUsed.toFixed(2)} / ${laiaCpInit.toFixed(
2
)} (reste ${laiaCpLeft.toFixed(2)})<br>
RTT utilises : ${laiaRttUsed.toFixed(2)} / ${laiaRttInit.toFixed(
2
)} (reste ${laiaRttLeft.toFixed(2)})<br>
JA utilises : ${laiaJaUsed.toFixed(2)} / ${laiaJaInit.toFixed(
2
)} (reste ${laiaJaLeft.toFixed(2)})</p>
`;
} }
// === 7. Init === // === 5. Logique de sélection et menu contextuel ===
function clearSelection() {
const menu = document.getElementById("selectionMenu");
if (menu) menu.style.display = "none";
selectedCells.forEach((cell) => cell.classList.remove("fc-day--selected"));
selectedCells = [];
}
function showSelectionMenu(e) {
const menu = document.getElementById("selectionMenu");
if (!menu) return;
menu.style.left = `${e.pageX + 5}px`;
menu.style.top = `${e.pageY + 5}px`;
menu.style.display = "block";
}
function applyEventTypeToSelection(eventType) {
if (selectedCells.length === 0) return;
selectedCells.forEach((cell) => {
const date = cell.dataset.date;
if (date) {
// Pour l'instant, on ajoute un événement par jour. On pourrait optimiser plus tard.
events.push({
date: date,
type: eventType,
duration: 1,
});
}
});
reprocessEvents(weeks, events);
renderTable(); // Redessine la table avec les nouveaux totaux
clearSelection();
}
// === 6. Init ===
async function initFamilyCalendar() { async function initFamilyCalendar() {
if (!document.getElementById("planningBody")) return; if (!document.getElementById("planningBody")) return;
// Écouteurs pour les soldes et filtres
[ [
"alexCpInit", "alexCpInit",
"alexRttInit", "alexRttInit",
@@ -465,23 +364,67 @@ async function initFamilyCalendar() {
const el = document.getElementById(id); const el = document.getElementById(id);
if (el) el.addEventListener("change", updateSummary); if (el) el.addEventListener("change", updateSummary);
}); });
["showOnlyCaroleOff", "showOnlySchoolHoliday"].forEach((id) => {
const el = document.getElementById(id);
if (el) el.addEventListener("change", renderTable);
});
const showOnlyCaroleOff = document.getElementById("showOnlyCaroleOff"); // Écouteurs pour la sélection par cliquer-glisser
if (showOnlyCaroleOff) { const planningBody = document.getElementById("planningBody");
showOnlyCaroleOff.addEventListener("change", renderTable); planningBody.addEventListener("mousedown", (e) => {
} if (e.target.tagName === "TD" && e.target.dataset.date) {
const showOnlySchoolHoliday = document.getElementById( isSelecting = true;
"showOnlySchoolHoliday" clearSelection();
); e.target.classList.add("fc-day--selected");
if (showOnlySchoolHoliday) { selectedCells.push(e.target);
showOnlySchoolHoliday.addEventListener("change", renderTable); e.preventDefault();
}
});
planningBody.addEventListener("mousemove", (e) => {
if (isSelecting && e.target.tagName === "TD" && e.target.dataset.date) {
if (!selectedCells.includes(e.target)) {
e.target.classList.add("fc-day--selected");
selectedCells.push(e.target);
}
}
});
document.addEventListener("mouseup", (e) => {
if (isSelecting) {
isSelecting = false;
if (selectedCells.length > 0) {
showSelectionMenu(e);
}
}
});
// Écouteur pour les clics hors du menu pour le fermer
document.addEventListener("click", (e) => {
const menu = document.getElementById("selectionMenu");
if (menu && !menu.contains(e.target) && selectedCells.length > 0) {
// Si on clique hors du menu APRES une sélection, on la nettoie
if (menu.style.display === "block") {
clearSelection();
}
}
});
// Écouteur pour les boutons du menu
const menu = document.getElementById("selectionMenu");
if (menu) {
menu.addEventListener("click", (e) => {
if (e.target.tagName === "BUTTON" && e.target.dataset.type) {
const eventType = e.target.dataset.type;
applyEventTypeToSelection(eventType);
}
});
} }
// Charger les vacances scolaires 2025-2026, Zone C // Initialisation des données
const holidaysRecords = await fetchSchoolHolidays("2025-2026", "Zone C"); const holidaysRecords = await fetchSchoolHolidays("2025-2026", "Zone C");
addSchoolHolidayEventsFromRecords(holidaysRecords, events); addSchoolHolidayEventsFromRecords(holidaysRecords, events);
markSchoolHolidayDaysAndWeeks(weeks, events); reprocessEvents(weeks, events); // Appliquer aussi les vacances aux totaux si besoin (ici juste la couleur)
renderTable(); renderTable();
} }
+12
View File
@@ -105,6 +105,18 @@ require __DIR__ . '/header.php';
<!-- Rempli par family-calendar.js --> <!-- Rempli par family-calendar.js -->
</tbody> </tbody>
</table> </table>
<div id="selectionMenu" class="fc-selection-menu">
<div class="fc-menu-section">
<strong>Congé Carole</strong>
<button data-type="OFF_CAROLE"># Off Carole</button>
<button data-type="EXTRA_OFF_CAROLE"># Extra off Carole</button>
</div>
<div class="fc-menu-section">
<strong>Mode de Garde</strong>
<button data-type="CENTRE"># Centre</button>
<button data-type="AVIS"># Avis</button>
</div>
</div>
</div> </div>
</section> </section>