calendar display mobile
This commit is contained in:
+31
-20
@@ -94,23 +94,30 @@ require __DIR__ . '/header.php';
|
|||||||
|
|
||||||
<section class="pf-section">
|
<section class="pf-section">
|
||||||
<div class="fc-month-calendar-wrapper">
|
<div class="fc-month-calendar-wrapper">
|
||||||
|
|
||||||
<div class="fc-month-header">
|
<div class="fc-month-header">
|
||||||
|
|
||||||
|
<div class="fc-month-nav-row">
|
||||||
|
<button id="fc-prev-month" class="fc-nav-button">‹</button>
|
||||||
|
<h3 id="fc-current-month-year"></h3>
|
||||||
|
<button id="fc-next-month" class="fc-nav-button">›</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="fc-view-controls">
|
<div class="fc-view-controls">
|
||||||
<button class="fc-view-button fc-view-button--active" data-view="1month"><?= tr('fc_view_1m') ?></button>
|
<button class="fc-view-button fc-view-button--active" data-view="1month"><?= tr('fc_view_1m') ?></button>
|
||||||
<button class="fc-view-button" data-view="2months"><?= tr('fc_view_2m') ?></button>
|
<button class="fc-view-button" data-view="2months"><?= tr('fc_view_2m') ?></button>
|
||||||
<button class="fc-view-button" data-view="year"><?= tr('fc_view_year') ?></button>
|
<button class="fc-view-button" data-view="3months">3 Mois</button>
|
||||||
</div>
|
|
||||||
<h3 id="fc-current-month-year"></h3>
|
|
||||||
<div class="fc-nav-controls">
|
|
||||||
<button id="fc-prev-month" class="fc-nav-button">‹</button>
|
|
||||||
<button id="fc-next-month" class="fc-nav-button">›</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fc-calendar-container">
|
<div class="fc-calendar-container">
|
||||||
<div id="fc-month-calendar" class="fc-month-calendar"></div>
|
<div id="fc-month-calendar" class="fc-month-calendar"></div>
|
||||||
<div id="fc-month-selectionMenu" class="fc-selection-menu" style="display:none;"></div>
|
<div id="fc-month-selectionMenu" class="fc-selection-menu" style="display:none;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="fc-month-balances" class="fc-month-balances"></div>
|
<div id="fc-month-balances" class="fc-month-balances"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -165,20 +172,6 @@ require __DIR__ . '/header.php';
|
|||||||
|
|
||||||
<section class="pf-section pf-section--bottom-panels">
|
<section class="pf-section pf-section--bottom-panels">
|
||||||
<div class="fc-bottom-grid">
|
<div class="fc-bottom-grid">
|
||||||
<div class="pf-card">
|
|
||||||
<h2 class="pf-card-title"><?= tr('fc_legend_title') ?></h2>
|
|
||||||
<div class="pf-card-body">
|
|
||||||
<div class="pf-legend-grid">
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-school-holiday"></div><span><?= tr('leg_school_holidays') ?></span></div>
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-public-holiday"></div><span><?= tr('leg_public_holiday') ?></span></div>
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-off-carole"></div><span><?= tr('leg_off_carole') ?></span></div>
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-extra-off-carole"></div><span><?= tr('leg_extra_off') ?></span></div>
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-centre"></div><span><?= tr('leg_centre') ?></span></div>
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-avis"></div><span><?= tr('leg_avis') ?></span></div>
|
|
||||||
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-pep-sick"></div><span><?= tr('leg_pep_sick') ?></span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pf-card">
|
<div class="pf-card">
|
||||||
<div class="pf-card-title fc-summary-header">
|
<div class="pf-card-title fc-summary-header">
|
||||||
@@ -195,6 +188,21 @@ require __DIR__ . '/header.php';
|
|||||||
<div id="globalSummary" class="fc-summary-vertical"></div>
|
<div id="globalSummary" class="fc-summary-vertical"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pf-card">
|
||||||
|
<h2 class="pf-card-title"><?= tr('fc_legend_title') ?></h2>
|
||||||
|
<div class="pf-card-body">
|
||||||
|
<div class="pf-legend-grid">
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-school-holiday"></div><span><?= tr('leg_school_holidays') ?></span></div>
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-public-holiday"></div><span><?= tr('leg_public_holiday') ?></span></div>
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-off-carole"></div><span><?= tr('leg_off_carole') ?></span></div>
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-extra-off-carole"></div><span><?= tr('leg_extra_off') ?></span></div>
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-centre"></div><span><?= tr('leg_centre') ?></span></div>
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-avis"></div><span><?= tr('leg_avis') ?></span></div>
|
||||||
|
<div class="pf-legend-item"><div class="pf-legend-color fc-legend-pep-sick"></div><span><?= tr('leg_pep_sick') ?></span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,6 +216,9 @@ window.I18N = {
|
|||||||
'leg_centre': "<?= tr('leg_centre') ?>",
|
'leg_centre': "<?= tr('leg_centre') ?>",
|
||||||
'leg_avis': "<?= tr('leg_avis') ?>",
|
'leg_avis': "<?= tr('leg_avis') ?>",
|
||||||
'leg_pep_sick': "<?= tr('leg_pep_sick') ?>",
|
'leg_pep_sick': "<?= tr('leg_pep_sick') ?>",
|
||||||
|
'leg_off_carole': "<?= tr('leg_off_carole') ?>",
|
||||||
|
'leg_extra_off': "<?= tr('leg_extra_off') ?>",
|
||||||
|
'leg_presence Pep': "<?= tr('leg_presence Pep') ?>",
|
||||||
'fc_menu_kids_leaves': "<?= tr('fc_menu_kids_leaves') ?>",
|
'fc_menu_kids_leaves': "<?= tr('fc_menu_kids_leaves') ?>",
|
||||||
'fc_clear': "<?= tr('fc_clear') ?>",
|
'fc_clear': "<?= tr('fc_clear') ?>",
|
||||||
'fc_unit_days': "<?= tr('fc_unit_days') ?>",
|
'fc_unit_days': "<?= tr('fc_unit_days') ?>",
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ return [
|
|||||||
'fc_btn_save_snap' => 'Desar el correctiu',
|
'fc_btn_save_snap' => 'Desar el correctiu',
|
||||||
'fc_view_1m' => '1 mes',
|
'fc_view_1m' => '1 mes',
|
||||||
'fc_view_2m' => '2 mesos',
|
'fc_view_2m' => '2 mesos',
|
||||||
|
'fc_view_3m' => '3 mesos',
|
||||||
'fc_view_year' => 'Any',
|
'fc_view_year' => 'Any',
|
||||||
'fc_weekly_planning' => 'Planificació setmanal',
|
'fc_weekly_planning' => 'Planificació setmanal',
|
||||||
'fc_col_month' => 'Mes',
|
'fc_col_month' => 'Mes',
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ return [
|
|||||||
'fc_btn_save_snap' => 'Enregistrer le correctif',
|
'fc_btn_save_snap' => 'Enregistrer le correctif',
|
||||||
'fc_view_1m' => '1 mois',
|
'fc_view_1m' => '1 mois',
|
||||||
'fc_view_2m' => '2 mois',
|
'fc_view_2m' => '2 mois',
|
||||||
|
'fc_view_3m' => '3 mois',
|
||||||
'fc_view_year' => 'Année',
|
'fc_view_year' => 'Année',
|
||||||
'fc_weekly_planning' => 'Planning hebdomadaire',
|
'fc_weekly_planning' => 'Planning hebdomadaire',
|
||||||
'fc_col_month' => 'Mois',
|
'fc_col_month' => 'Mois',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -689,40 +689,42 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
|
|
||||||
const y = this.currentMonth.getFullYear();
|
const y = this.currentMonth.getFullYear();
|
||||||
const m = this.currentMonth.getMonth();
|
const m = this.currentMonth.getMonth();
|
||||||
|
|
||||||
const lang = window.I18N_LANG || "fr-FR";
|
const lang = window.I18N_LANG || "fr-FR";
|
||||||
const titleEl = document.querySelector("#fc-current-month-year");
|
const titleEl = document.querySelector("#fc-current-month-year");
|
||||||
|
|
||||||
if (titleEl) {
|
if (titleEl) {
|
||||||
if (this.viewMode === "year") {
|
if (this.viewMode === "3months") {
|
||||||
titleEl.textContent = `${tr("fc_school_year")} ${this.currentSchoolYearStart} – ${this.currentSchoolYearStart + 1}`;
|
const nextM2 = new Date(y, m + 2, 1);
|
||||||
} else if (this.viewMode === "2months") {
|
const m1 = new Intl.DateTimeFormat(lang, { month: "short" }).format(
|
||||||
const nextM = new Date(y, m + 1, 1);
|
|
||||||
const m1 = new Intl.DateTimeFormat(lang, { month: "long" }).format(
|
|
||||||
this.currentMonth,
|
this.currentMonth,
|
||||||
);
|
);
|
||||||
const m2 = new Intl.DateTimeFormat(lang, {
|
const m2 = new Intl.DateTimeFormat(lang, {
|
||||||
month: "long",
|
month: "short",
|
||||||
|
year: "numeric",
|
||||||
|
}).format(nextM2);
|
||||||
|
titleEl.textContent = `${m1} - ${m2}`;
|
||||||
|
this.renderThreeMonthsView();
|
||||||
|
} else if (this.viewMode === "2months") {
|
||||||
|
const nextM = new Date(y, m + 1, 1);
|
||||||
|
const m1 = new Intl.DateTimeFormat(lang, { month: "short" }).format(
|
||||||
|
this.currentMonth,
|
||||||
|
);
|
||||||
|
const m2 = new Intl.DateTimeFormat(lang, {
|
||||||
|
month: "short",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}).format(nextM);
|
}).format(nextM);
|
||||||
titleEl.textContent = `${m1} - ${m2}`;
|
titleEl.textContent = `${m1} - ${m2}`;
|
||||||
|
this.renderTwoMonthsView();
|
||||||
} else {
|
} else {
|
||||||
titleEl.textContent = new Intl.DateTimeFormat(lang, {
|
titleEl.textContent = new Intl.DateTimeFormat(lang, {
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}).format(this.currentMonth);
|
}).format(this.currentMonth);
|
||||||
|
this.monthCalendar.innerHTML = this.generateMonthHTML(y, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.viewMode === "year") {
|
|
||||||
this.renderYearView();
|
|
||||||
} else if (this.viewMode === "2months") {
|
|
||||||
this.renderTwoMonthsView();
|
|
||||||
} else {
|
|
||||||
this.monthCalendar.innerHTML = this.generateMonthHTML(y, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderMonthBalances();
|
this.renderMonthBalances();
|
||||||
|
|
||||||
this.syncSummaryWithMonth();
|
this.syncSummaryWithMonth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,86 +732,107 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const y = this.currentMonth.getFullYear();
|
const y = this.currentMonth.getFullYear();
|
||||||
const m = this.currentMonth.getMonth();
|
const m = this.currentMonth.getMonth();
|
||||||
const nextDate = new Date(y, m + 1, 1);
|
const nextDate = new Date(y, m + 1, 1);
|
||||||
|
const lang = window.I18N_LANG || "fr-FR";
|
||||||
|
|
||||||
let html = `<div class="fc-two-months-container">`;
|
let html = `<div class="fc-two-months-container">`;
|
||||||
html += `<div class="fc-month-container"><div class="fc-month-title">${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(this.currentMonth)}</div>${this.generateMonthHTML(y, m)}</div>`;
|
html += `<div class="fc-month-container"><div class="fc-month-title">${new Intl.DateTimeFormat(lang, { month: "long" }).format(this.currentMonth)}</div>${this.generateMonthHTML(y, m)}</div>`;
|
||||||
html += `<div class="fc-month-container"><div class="fc-month-title">${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(nextDate)}</div>${this.generateMonthHTML(nextDate.getFullYear(), nextDate.getMonth())}</div>`;
|
html += `<div class="fc-month-container"><div class="fc-month-title">${new Intl.DateTimeFormat(lang, { month: "long" }).format(nextDate)}</div>${this.generateMonthHTML(nextDate.getFullYear(), nextDate.getMonth())}</div>`;
|
||||||
|
html += `</div>`;
|
||||||
|
|
||||||
|
this.monthCalendar.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderThreeMonthsView() {
|
||||||
|
const y = this.currentMonth.getFullYear();
|
||||||
|
const m = this.currentMonth.getMonth();
|
||||||
|
const d1 = this.currentMonth;
|
||||||
|
const d2 = new Date(y, m + 1, 1);
|
||||||
|
const d3 = new Date(y, m + 2, 1);
|
||||||
|
|
||||||
|
let html = `<div class="fc-three-months-container">`;
|
||||||
|
[d1, d2, d3].forEach((d) => {
|
||||||
|
html += `<div class="fc-month-container"><div class="fc-month-title">${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(d)}</div>${this.generateMonthHTML(d.getFullYear(), d.getMonth())}</div>`;
|
||||||
|
});
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
this.monthCalendar.innerHTML = html;
|
this.monthCalendar.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderYearView() {
|
|
||||||
const startYear = this.currentSchoolYearStart;
|
|
||||||
let html = '<div class="fc-year-container">';
|
|
||||||
for (let i = 8; i < 12; i++)
|
|
||||||
html += `<div class="fc-year-month"><div class="fc-year-month-title">${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(new Date(startYear, i))}</div>${this.generateMonthHTML(startYear, i)}</div>`;
|
|
||||||
for (let i = 0; i < 8; i++)
|
|
||||||
html += `<div class="fc-year-month"><div class="fc-year-month-title">${new Intl.DateTimeFormat("fr-FR", { month: "long" }).format(new Date(startYear + 1, i))}</div>${this.generateMonthHTML(startYear + 1, i)}</div>`;
|
|
||||||
html += "</div>";
|
|
||||||
this.monthCalendar.innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Affiche le décompte des congés (Début, Utilisé, Reste) sous le calendrier
|
|
||||||
renderMonthBalances() {
|
renderMonthBalances() {
|
||||||
const container = document.getElementById("fc-month-balances");
|
const container = document.getElementById("fc-month-balances");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
// On n'affiche les soldes que si on regarde 1 seul mois pour éviter la confusion
|
// 1. Déterminer les mois affichés selon la vue
|
||||||
if (this.viewMode !== "1month") {
|
const monthsToDisplay = [];
|
||||||
container.innerHTML = "";
|
const y = this.currentMonth.getFullYear();
|
||||||
container.style.display = "none";
|
const m = this.currentMonth.getMonth();
|
||||||
return;
|
|
||||||
|
let numMonths = 1;
|
||||||
|
if (this.viewMode === "2months") numMonths = 2;
|
||||||
|
if (this.viewMode === "3months") numMonths = 3;
|
||||||
|
|
||||||
|
for (let i = 0; i < numMonths; i++) {
|
||||||
|
const d = new Date(y, m + i, 1);
|
||||||
|
monthsToDisplay.push(
|
||||||
|
`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
container.style.display = "grid";
|
container.style.display = "flex";
|
||||||
const ym = `${this.currentMonth.getFullYear()}-${String(this.currentMonth.getMonth() + 1).padStart(2, "0")}`;
|
|
||||||
let html = "";
|
let html = "";
|
||||||
|
|
||||||
|
// 2. Calcul dynamique pour Alex et Laia
|
||||||
[FAMILY.ALEX, FAMILY.LAIA].forEach((person) => {
|
[FAMILY.ALEX, FAMILY.LAIA].forEach((person) => {
|
||||||
html += `<div class="fc-balance-person">
|
html += `<div class="fc-minimal-balance-card">
|
||||||
<div class="fc-balance-name ${person.prefix}">${person.prefix}</div>
|
<strong class="${person.prefix}">${person.prefix.toUpperCase()}</strong>
|
||||||
<div class="fc-balance-grid">`;
|
<div class="fc-minimal-chips">`;
|
||||||
|
|
||||||
["CP", "JRA", "JA"].forEach((type) => {
|
["CP", "JRA", "JA"].forEach((type) => {
|
||||||
// Utilisation des données pré-calculées par calculateMonthlyBalances()
|
// Solde de départ = celui du PREMIER mois affiché
|
||||||
const info = this.monthlyLeaveBalances[person.id]?.[type]?.[ym];
|
const startInfo =
|
||||||
const start = info ? info.availableAtMonthStart : 0;
|
this.monthlyLeaveBalances[person.id]?.[type]?.[monthsToDisplay[0]];
|
||||||
const used = info ? info.usedInMonth : 0;
|
const startBal = startInfo ? startInfo.availableAtMonthStart : 0;
|
||||||
const end = Math.max(0, start - used);
|
|
||||||
|
|
||||||
|
// Jours posés = Somme sur TOUS les mois affichés
|
||||||
|
let totalUsed = 0;
|
||||||
|
monthsToDisplay.forEach((ym) => {
|
||||||
|
const info = this.monthlyLeaveBalances[person.id]?.[type]?.[ym];
|
||||||
|
if (info) totalUsed += info.usedInMonth;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Solde de fin (théorique) à la fin de la période
|
||||||
|
const endBal = Math.max(0, startBal - totalUsed);
|
||||||
const fmt = (n) =>
|
const fmt = (n) =>
|
||||||
n > 0 ? (Number.isInteger(n) ? n : n.toFixed(1)) : "0";
|
n > 0 ? (Number.isInteger(n) ? n : n.toFixed(1)) : "0";
|
||||||
|
|
||||||
html += `<div class="fc-balance-col">
|
// Petit badge rouge uniquement s'il y a des congés posés
|
||||||
<span class="fc-balance-type">${type}</span>
|
const usedHtml =
|
||||||
<div class="fc-balance-numbers">
|
totalUsed > 0
|
||||||
<div class="fc-bal-val start"><span title="Début de mois">▶</span><span>${fmt(start)}</span></div>
|
? `<span class="fc-used-badge" title="Posé sur la période">-${fmt(totalUsed)}</span>`
|
||||||
<div class="fc-bal-val used"><span title="Posé ce mois">➖</span><span>${fmt(used)}</span></div>
|
: "";
|
||||||
<div class="fc-bal-val end"><span title="Solde fin de mois">⏸</span><span>${fmt(end)}</span></div>
|
|
||||||
</div>
|
html += `<div class="fc-min-chip" title="Solde de départ: ${fmt(startBal)}">
|
||||||
|
<span class="type">${type}</span>
|
||||||
|
<span class="val" title="Restant">${fmt(endBal)}</span>
|
||||||
|
${usedHtml}
|
||||||
</div>`;
|
</div>`;
|
||||||
});
|
});
|
||||||
|
html += `</div></div>`;
|
||||||
html += ` </div></div>`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
container.innerHTML = html;
|
container.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force le menu déroulant du récapitulatif à se caler sur le mois affiché
|
|
||||||
syncSummaryWithMonth() {
|
syncSummaryWithMonth() {
|
||||||
const typeSelect = document.getElementById("summType");
|
const typeSelect = document.getElementById("summType");
|
||||||
const valueSelect = document.getElementById("summValue");
|
const valueSelect = document.getElementById("summValue");
|
||||||
|
|
||||||
if (typeSelect && valueSelect && this.viewMode === "1month") {
|
if (typeSelect && valueSelect) {
|
||||||
|
// Le récap se synchronise avec le PREMIER mois affiché de la période
|
||||||
const ym = `${this.currentMonth.getFullYear()}-${String(this.currentMonth.getMonth() + 1).padStart(2, "0")}`;
|
const ym = `${this.currentMonth.getFullYear()}-${String(this.currentMonth.getMonth() + 1).padStart(2, "0")}`;
|
||||||
|
|
||||||
// Si on passe d'année à mois, on doit forcer le peuplement du select
|
|
||||||
if (typeSelect.value !== "month") {
|
if (typeSelect.value !== "month") {
|
||||||
typeSelect.value = "month";
|
typeSelect.value = "month";
|
||||||
typeSelect.dispatchEvent(new Event("change")); // Déclenche populateValues()
|
typeSelect.dispatchEvent(new Event("change"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// On sélectionne le mois actuel
|
|
||||||
valueSelect.value = ym;
|
valueSelect.value = ym;
|
||||||
this.updateGlobalSummary();
|
this.updateGlobalSummary();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user