1 parent
a2e0904132
commit
8a7b5b6644
6 files changed
+337
-119
No files matched your search
+10
-9
@@ -85,7 +85,7 @@ $pageCss = "/modules/family-calendar/family-calendar.css";
|
|||||||
require __DIR__ . '/header.php';
|
require __DIR__ . '/header.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="pf-container" style="max-width:100%; padding:0;">
|
<div class="pf-container" style="--p1-main: <?= $parents[0]['color'] ?? '#0891b2' ?>; --p2-main: <?= $parents[1]['color'] ?? '#f59e0b' ?>; max-width:100%; padding:0;">
|
||||||
<div class="fc-header-row" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; margin-bottom: 24px;">
|
<div class="fc-header-row" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; margin-bottom: 24px;">
|
||||||
|
|
||||||
<!-- Bloc Titre + Roue crantée -->
|
<!-- Bloc Titre + Roue crantée -->
|
||||||
@@ -422,7 +422,7 @@ require __DIR__ . '/header.php';
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<?php foreach ($parents as $index => $parent):
|
<?php foreach ($parents as $index => $parent):
|
||||||
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia'; // Couleurs alternées
|
$parentClass = ($index % 2 === 0) ? 'col-p1' : 'col-p2';
|
||||||
$pLeaves = $leaveMatrix[$parent['id']] ?? [];
|
$pLeaves = $leaveMatrix[$parent['id']] ?? [];
|
||||||
$colspan = count($pLeaves) * 2;
|
$colspan = count($pLeaves) * 2;
|
||||||
?>
|
?>
|
||||||
@@ -433,7 +433,7 @@ require __DIR__ . '/header.php';
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<?php foreach ($parents as $index => $parent):
|
<?php foreach ($parents as $index => $parent):
|
||||||
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
|
$parentClass = ($index % 2 === 0) ? 'col-p1' : 'col-p2';
|
||||||
$pLeaves = $leaveMatrix[$parent['id']] ?? [];
|
$pLeaves = $leaveMatrix[$parent['id']] ?? [];
|
||||||
?>
|
?>
|
||||||
<?php foreach ($pLeaves as $type): ?>
|
<?php foreach ($pLeaves as $type): ?>
|
||||||
@@ -443,7 +443,7 @@ require __DIR__ . '/header.php';
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<?php foreach ($parents as $index => $parent):
|
<?php foreach ($parents as $index => $parent):
|
||||||
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
|
$parentClass = ($index % 2 === 0) ? 'col-p1' : 'col-p2';
|
||||||
$pLeaves = $leaveMatrix[$parent['id']] ?? [];
|
$pLeaves = $leaveMatrix[$parent['id']] ?? [];
|
||||||
?>
|
?>
|
||||||
<?php foreach ($pLeaves as $type): ?>
|
<?php foreach ($pLeaves as $type): ?>
|
||||||
@@ -482,16 +482,17 @@ require __DIR__ . '/header.php';
|
|||||||
<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-public-holiday"></div><span><?= tr('leg_public_holiday') ?></span></div>
|
||||||
|
|
||||||
<!-- Intervenants (Dynamique selon les congés paramétrés) -->
|
<!-- Intervenants (Dynamique selon les congés paramétrés) -->
|
||||||
<?php foreach ($helpers as $helper):
|
<?php
|
||||||
|
$helperColorIndex = 0;
|
||||||
|
foreach ($helpers as $helper):
|
||||||
$hLeaves = $leaveMatrix[$helper['id']] ?? [];
|
$hLeaves = $leaveMatrix[$helper['id']] ?? [];
|
||||||
$colors = ['var(--warning)', 'var(--danger)', 'var(--primary)'];
|
foreach ($hLeaves as $type):
|
||||||
foreach ($hLeaves as $index => $type):
|
|
||||||
?>
|
?>
|
||||||
<div class="pf-legend-item">
|
<div class="pf-legend-item">
|
||||||
<div class="pf-legend-color" style="background: <?= $colors[$index % count($colors)] ?>;"></div>
|
<div class="pf-legend-color fc-bg-palette-<?= $helperColorIndex % 8 ?>"></div>
|
||||||
<span><?= htmlspecialchars($type) ?> <?= htmlspecialchars($helper['name']) ?></span>
|
<span><?= htmlspecialchars($type) ?> <?= htmlspecialchars($helper['name']) ?></span>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; endforeach; ?>
|
<?php $helperColorIndex++; endforeach; endforeach; ?>
|
||||||
|
|
||||||
<!-- Modes de garde (On masque "Nounou" si l'intervenant gère lui-même ses présences) -->
|
<!-- Modes de garde (On masque "Nounou" si l'intervenant gère lui-même ses présences) -->
|
||||||
<?php foreach ($activeCareModes as $index => $mode):
|
<?php foreach ($activeCareModes as $index => $mode):
|
||||||
|
|||||||
@@ -351,6 +351,13 @@ return [
|
|||||||
'fc_full_year' => 'Any sencer',
|
'fc_full_year' => 'Any sencer',
|
||||||
'fc_custom_period' => 'Període específic...',
|
'fc_custom_period' => 'Període específic...',
|
||||||
'fc_worked_days' => 'Treballats (Est.)',
|
'fc_worked_days' => 'Treballats (Est.)',
|
||||||
|
'fc_presence' => 'Presència',
|
||||||
|
'fc_working_days' => 'Feiners',
|
||||||
|
'fc_absences' => 'Abs.',
|
||||||
|
'fc_recap_title' => 'Resum',
|
||||||
|
'fc_worked_est' => 'Treballats (Est.)',
|
||||||
|
'fc_invalid_dates' => 'Selecciona dates vàlides.',
|
||||||
|
'fc_no_leaves_taken' => 'Cap permís sol·licitat.',
|
||||||
|
|
||||||
// --- CALENDARI : PARÀMETRES (MEMBRES I VISUALITZACIÓ) ---
|
// --- CALENDARI : PARÀMETRES (MEMBRES I VISUALITZACIÓ) ---
|
||||||
'fc_tab_display' => '🖥️ Visualització',
|
'fc_tab_display' => '🖥️ Visualització',
|
||||||
|
|||||||
@@ -352,6 +352,13 @@ return [
|
|||||||
'fc_full_year' => 'Full year',
|
'fc_full_year' => 'Full year',
|
||||||
'fc_custom_period' => 'Custom period...',
|
'fc_custom_period' => 'Custom period...',
|
||||||
'fc_worked_days' => 'Worked (Est.)',
|
'fc_worked_days' => 'Worked (Est.)',
|
||||||
|
'fc_presence' => 'Presence',
|
||||||
|
'fc_working_days' => 'Working days',
|
||||||
|
'fc_absences' => 'Abs.',
|
||||||
|
'fc_recap_title' => 'Summary',
|
||||||
|
'fc_worked_est' => 'Worked (Est.)',
|
||||||
|
'fc_invalid_dates' => 'Please select valid dates.',
|
||||||
|
'fc_no_leaves_taken' => 'No leave taken.',
|
||||||
|
|
||||||
// --- CALENDAR: SETTINGS (MEMBERS & DISPLAY) ---
|
// --- CALENDAR: SETTINGS (MEMBERS & DISPLAY) ---
|
||||||
'fc_tab_display' => '🖥️ Display',
|
'fc_tab_display' => '🖥️ Display',
|
||||||
|
|||||||
@@ -356,6 +356,13 @@ return [
|
|||||||
'fc_full_year' => 'Année complète',
|
'fc_full_year' => 'Année complète',
|
||||||
'fc_custom_period' => 'Période spécifique...',
|
'fc_custom_period' => 'Période spécifique...',
|
||||||
'fc_worked_days' => 'Travaillés (Est.)',
|
'fc_worked_days' => 'Travaillés (Est.)',
|
||||||
|
'fc_presence' => 'Présence',
|
||||||
|
'fc_working_days' => 'J. Ouvrés',
|
||||||
|
'fc_absences' => 'Abs.',
|
||||||
|
'fc_recap_title' => 'Récapitulatif',
|
||||||
|
'fc_worked_est' => 'Travaillés (Est.)',
|
||||||
|
'fc_invalid_dates' => 'Sélectionnez des dates valides.',
|
||||||
|
'fc_no_leaves_taken' => 'Aucun congé posé.',
|
||||||
|
|
||||||
// --- CALENDRIER : PARAMÈTRES (MEMBRES & AFFICHAGE) ---
|
// --- CALENDRIER : PARAMÈTRES (MEMBRES & AFFICHAGE) ---
|
||||||
'fc_tab_display' => '🖥️ Affichage',
|
'fc_tab_display' => '🖥️ Affichage',
|
||||||
|
|||||||
@@ -10,15 +10,26 @@
|
|||||||
#f1f5f9 8px,
|
#f1f5f9 8px,
|
||||||
#f1f5f9 16px
|
#f1f5f9 16px
|
||||||
);
|
);
|
||||||
--c-off-carole: #fef3c7;
|
|
||||||
--c-extra-off: #fee2e2;
|
|
||||||
--c-selected: #dbeafe;
|
|
||||||
|
|
||||||
/* Thèmes Parents (Sync Budget) */
|
/* Palette dynamique pour les congés intervenants */
|
||||||
--bg-alex: #ecfeff;
|
--fc-palette-0: #fef3c7;
|
||||||
--text-alex: #0891b2;
|
--fc-palette-text-0: #b45309;
|
||||||
--bg-laia: #fffbeb;
|
--fc-palette-1: #fee2e2;
|
||||||
--text-laia: #d97706;
|
--fc-palette-text-1: #b91c1c;
|
||||||
|
--fc-palette-2: #dbeafe;
|
||||||
|
--fc-palette-text-2: #1d4ed8;
|
||||||
|
--fc-palette-3: #dcfce7;
|
||||||
|
--fc-palette-text-3: #15803d;
|
||||||
|
--fc-palette-4: #f3e8ff;
|
||||||
|
--fc-palette-text-4: #7e22ce;
|
||||||
|
--fc-palette-5: #ffedd5;
|
||||||
|
--fc-palette-text-5: #c2410c;
|
||||||
|
--fc-palette-6: #ccfbf1;
|
||||||
|
--fc-palette-text-6: #0f766e;
|
||||||
|
--fc-palette-7: #fce7f3;
|
||||||
|
--fc-palette-text-7: #be185d;
|
||||||
|
|
||||||
|
--c-selected: #dbeafe;
|
||||||
|
|
||||||
/* Rappel des variables Global Design System pour cohérence */
|
/* Rappel des variables Global Design System pour cohérence */
|
||||||
--pf-primary: #3b82f6;
|
--pf-primary: #3b82f6;
|
||||||
@@ -301,11 +312,30 @@
|
|||||||
background: var(--c-public-holiday) !important;
|
background: var(--c-public-holiday) !important;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
.fc-day--off-carole {
|
|
||||||
background: var(--c-off-carole) !important;
|
.fc-bg-palette-0 {
|
||||||
|
background: var(--fc-palette-0) !important;
|
||||||
}
|
}
|
||||||
.fc-day--extra-off-carole {
|
.fc-bg-palette-1 {
|
||||||
background: var(--c-extra-off) !important;
|
background: var(--fc-palette-1) !important;
|
||||||
|
}
|
||||||
|
.fc-bg-palette-2 {
|
||||||
|
background: var(--fc-palette-2) !important;
|
||||||
|
}
|
||||||
|
.fc-bg-palette-3 {
|
||||||
|
background: var(--fc-palette-3) !important;
|
||||||
|
}
|
||||||
|
.fc-bg-palette-4 {
|
||||||
|
background: var(--fc-palette-4) !important;
|
||||||
|
}
|
||||||
|
.fc-bg-palette-5 {
|
||||||
|
background: var(--fc-palette-5) !important;
|
||||||
|
}
|
||||||
|
.fc-bg-palette-6 {
|
||||||
|
background: var(--fc-palette-6) !important;
|
||||||
|
}
|
||||||
|
.fc-bg-palette-7 {
|
||||||
|
background: var(--fc-palette-7) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-day--selected {
|
.fc-day--selected {
|
||||||
@@ -314,8 +344,14 @@
|
|||||||
z-index: 5;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-day--off-carole.fc-day--school-holiday,
|
.fc-bg-palette-0.fc-day--school-holiday,
|
||||||
.fc-day--extra-off-carole.fc-day--school-holiday,
|
.fc-bg-palette-1.fc-day--school-holiday,
|
||||||
|
.fc-bg-palette-2.fc-day--school-holiday,
|
||||||
|
.fc-bg-palette-3.fc-day--school-holiday,
|
||||||
|
.fc-bg-palette-4.fc-day--school-holiday,
|
||||||
|
.fc-bg-palette-5.fc-day--school-holiday,
|
||||||
|
.fc-bg-palette-6.fc-day--school-holiday,
|
||||||
|
.fc-bg-palette-7.fc-day--school-holiday,
|
||||||
.fc-day--centre.fc-day--school-holiday,
|
.fc-day--centre.fc-day--school-holiday,
|
||||||
.fc-day--avis.fc-day--school-holiday {
|
.fc-day--avis.fc-day--school-holiday {
|
||||||
box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
|
box-shadow: inset 0 -8px 0 0 var(--c-school-holiday) !important;
|
||||||
@@ -409,15 +445,23 @@
|
|||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-alex.header-group,
|
.col-p1.header-group,
|
||||||
.col-alex-sub {
|
.col-p1-sub {
|
||||||
background: var(--bg-alex) !important;
|
background: color-mix(
|
||||||
color: var(--text-alex) !important;
|
in srgb,
|
||||||
|
var(--p1-main, #0891b2) 8%,
|
||||||
|
#ffffff
|
||||||
|
) !important;
|
||||||
|
color: color-mix(in srgb, var(--p1-main, #0891b2) 85%, #000000) !important;
|
||||||
}
|
}
|
||||||
.col-laia.header-group,
|
.col-p2.header-group,
|
||||||
.col-laia-sub {
|
.col-p2-sub {
|
||||||
background: var(--bg-laia) !important;
|
background: color-mix(
|
||||||
color: var(--text-laia) !important;
|
in srgb,
|
||||||
|
var(--p2-main, #f59e0b) 8%,
|
||||||
|
#ffffff
|
||||||
|
) !important;
|
||||||
|
color: color-mix(in srgb, var(--p2-main, #f59e0b) 85%, #000000) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#planningTable tbody td {
|
#planningTable tbody td {
|
||||||
@@ -448,10 +492,10 @@ td.col-day {
|
|||||||
}
|
}
|
||||||
th.col-total,
|
th.col-total,
|
||||||
td.col-total,
|
td.col-total,
|
||||||
th.col-alex-sub,
|
th.col-p1-sub,
|
||||||
td.col-alex-sub,
|
td.col-p1-sub,
|
||||||
th.col-laia-sub,
|
th.col-p2-sub,
|
||||||
td.col-laia-sub {
|
td.col-p2-sub {
|
||||||
width: 32px !important;
|
width: 32px !important;
|
||||||
min-width: 32px !important;
|
min-width: 32px !important;
|
||||||
max-width: 32px !important;
|
max-width: 32px !important;
|
||||||
@@ -594,12 +638,7 @@ td.col-laia-sub {
|
|||||||
.fc-legend-public-holiday {
|
.fc-legend-public-holiday {
|
||||||
background: var(--c-public-holiday);
|
background: var(--c-public-holiday);
|
||||||
}
|
}
|
||||||
.fc-legend-off-carole {
|
|
||||||
background: var(--c-off-carole);
|
|
||||||
}
|
|
||||||
.fc-legend-extra-off-carole {
|
|
||||||
background: var(--c-extra-off);
|
|
||||||
}
|
|
||||||
.fc-legend-centre::after {
|
.fc-legend-centre::after {
|
||||||
content: "🏫";
|
content: "🏫";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -682,6 +682,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
this.leaves = [];
|
this.leaves = [];
|
||||||
this.weeks = [];
|
this.weeks = [];
|
||||||
|
|
||||||
|
this.helperColorMap = {};
|
||||||
|
|
||||||
this.parents = [];
|
this.parents = [];
|
||||||
this.kids = [];
|
this.kids = [];
|
||||||
this.helpers = [];
|
this.helpers = [];
|
||||||
@@ -729,6 +731,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
this.careModes = res.data.foyer.care_modes || [];
|
this.careModes = res.data.foyer.care_modes || [];
|
||||||
this.leaveMatrix = res.data.leaves || {};
|
this.leaveMatrix = res.data.leaves || {};
|
||||||
|
|
||||||
|
let colorCounter = 0;
|
||||||
|
this.helpers.forEach((h) => {
|
||||||
|
const hLeaves =
|
||||||
|
this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || [];
|
||||||
|
hLeaves.forEach((lt) => {
|
||||||
|
const typeName = typeof lt === "object" ? lt.type : lt;
|
||||||
|
this.helperColorMap[`${h.id}_${typeName}`] = colorCounter % 8;
|
||||||
|
colorCounter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const settings = res.data.calendar_settings || {};
|
const settings = res.data.calendar_settings || {};
|
||||||
if (settings.calendar_default_view) {
|
if (settings.calendar_default_view) {
|
||||||
this.viewMode = settings.calendar_default_view;
|
this.viewMode = settings.calendar_default_view;
|
||||||
@@ -902,14 +915,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const helperEvents = [...this.leaves, ...this.events]
|
const helperEvents = [...this.leaves, ...this.events]
|
||||||
.filter((e) => {
|
.filter((e) => {
|
||||||
const eDate = e.leave_date || e.date;
|
const eDate = e.leave_date || e.date;
|
||||||
const eType = e.leave_type || e.type;
|
const eType = String(e.leave_type || e.type).toUpperCase();
|
||||||
const isOldOff =
|
const isOldEvent = eType.includes("OFF") || eType.includes("EXTRA");
|
||||||
eType === "HELPER_OFF" ||
|
|
||||||
eType === "HELPER_EXTRA" ||
|
|
||||||
eType.includes("OFF");
|
|
||||||
|
|
||||||
if (e.person_id != h.id) return false;
|
if (parseInt(e.person_id) !== parseInt(h.id)) return false;
|
||||||
if (!e.leave_date && !isOldOff) return false;
|
if (!e.leave_date && !isOldEvent) return false; // Ignore les événements standards sauf l'historique
|
||||||
|
|
||||||
if (isCustom && !hasValidDates) return false;
|
if (isCustom && !hasValidDates) return false;
|
||||||
return eDate >= startDateStr && eDate <= endDateStr;
|
return eDate >= startDateStr && eDate <= endDateStr;
|
||||||
@@ -929,12 +939,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
let totalLeavesTaken = 0;
|
let totalLeavesTaken = 0;
|
||||||
|
|
||||||
helperEvents.forEach((e) => {
|
helperEvents.forEach((e) => {
|
||||||
let mappedType =
|
const rawType = String(e.type).toUpperCase();
|
||||||
e.type === "HELPER_OFF"
|
let mappedType = e.type;
|
||||||
? "OFF"
|
if (rawType.includes("EXTRA")) mappedType = "EXTRA";
|
||||||
: e.type === "HELPER_EXTRA"
|
else if (rawType.includes("OFF")) mappedType = "OFF";
|
||||||
? "EXTRA"
|
|
||||||
: e.type;
|
|
||||||
if (totals[mappedType] === undefined) totals[mappedType] = 0;
|
if (totals[mappedType] === undefined) totals[mappedType] = 0;
|
||||||
totals[mappedType] += e.duration;
|
totals[mappedType] += e.duration;
|
||||||
totalLeavesTaken += e.duration;
|
totalLeavesTaken += e.duration;
|
||||||
@@ -967,22 +976,22 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const isCustomDisplay = isCustom ? "flex" : "none";
|
const isCustomDisplay = isCustom ? "flex" : "none";
|
||||||
const isYearDisplay = isCustom ? "none" : "block";
|
const isYearDisplay = isCustom ? "none" : "block";
|
||||||
|
|
||||||
// --- GÉNÉRATION DU HTML (Design Ultra-Compact + Micro Pilules) ---
|
// --- GÉNÉRATION DU HTML (Design Ultra-Compact + Micro Pilules + Flexbox Corrigé) ---
|
||||||
let cardHtml = `
|
let cardHtml = `
|
||||||
<div style="background: var(--bg-panel); border: 1px solid var(--border-light); border-radius: 12px; padding: 12px 20px; margin-bottom: 20px; box-shadow: var(--pf-shadow-sm); display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 15px; width: 100%;">
|
<div style="background: var(--bg-panel); border: 1px solid var(--border-light); border-radius: 12px; padding: 12px 20px; margin-bottom: 20px; box-shadow: var(--pf-shadow-sm); display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 15px; width: 100%;">
|
||||||
|
|
||||||
<!-- Zone Gauche : Identité + KPI + Pilules -->
|
<!-- Zone Gauche : Identité + KPI + Pilules -->
|
||||||
<div style="display: flex; align-items: center; gap: 20px; flex-wrap: wrap;">
|
<div style="display: flex; align-items: center; gap: 20px; flex-wrap: wrap; flex: 1;">
|
||||||
|
|
||||||
<!-- Identité -->
|
<!-- Identité -->
|
||||||
<div style="display: flex; flex-direction: column; gap: 2px;">
|
<div style="display: flex; flex-direction: column; gap: 2px;">
|
||||||
<span style="font-size: 0.95rem; font-weight: 700; color: var(--text-main); display: flex; align-items: center; gap: 6px;">📅 ${h.name}</span>
|
<span style="font-size: 0.95rem; font-weight: 700; color: var(--text-main); display: flex; align-items: center; gap: 6px;">📅 ${h.name}</span>
|
||||||
<span style="font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em;">Récapitulatif</span>
|
<span style="font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em;">${window.I18N?.fc_recap_title || "Récapitulatif"}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Jours Travaillés -->
|
<!-- Jours Travaillés -->
|
||||||
<div style="display: flex; align-items: baseline; gap: 6px; padding-right: 20px; border-right: 1px solid var(--border-light);">
|
<div style="display: flex; align-items: baseline; gap: 6px; padding-right: 20px; border-right: 1px solid var(--border-light);">
|
||||||
<span style="font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; font-weight: 700;">Travaillés (Est.)</span>
|
<span style="font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; font-weight: 700;">${window.I18N?.fc_worked_est || "Travaillés (Est.)"}</span>
|
||||||
<span style="font-size: 1.4rem; font-weight: 800; color: var(--primary); line-height: 1;">${hasValidDates ? workedDays : "-"} <span style="font-size: 0.85rem;">j</span></span>
|
<span style="font-size: 1.4rem; font-weight: 800; color: var(--primary); line-height: 1;">${hasValidDates ? workedDays : "-"} <span style="font-size: 0.85rem;">j</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -990,7 +999,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
<div style="display: flex; gap: 10px; align-items: center; flex-wrap: wrap;">`;
|
<div style="display: flex; gap: 10px; align-items: center; flex-wrap: wrap;">`;
|
||||||
|
|
||||||
if (!hasValidDates && isCustom) {
|
if (!hasValidDates && isCustom) {
|
||||||
cardHtml += `<div style="font-size: 0.85rem; color: var(--danger); font-weight: bold;">Sélectionnez des dates valides.</div>`;
|
cardHtml += `<div style="font-size: 0.85rem; color: var(--danger); font-weight: bold;">${window.I18N?.fc_invalid_dates || "Sélectionnez des dates valides."}</div>`;
|
||||||
} else {
|
} else {
|
||||||
let hasLeaves = false;
|
let hasLeaves = false;
|
||||||
for (const [t, val] of Object.entries(totals)) {
|
for (const [t, val] of Object.entries(totals)) {
|
||||||
@@ -1001,22 +1010,31 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
hasLeaves = true;
|
hasLeaves = true;
|
||||||
let label =
|
const rawT = String(t).toUpperCase();
|
||||||
t === "HELPER_OFF" ? "Off" : t === "HELPER_EXTRA" ? "Extra" : t;
|
let label = t;
|
||||||
|
if (rawT.includes("EXTRA"))
|
||||||
|
label = window.I18N?.btn_extra || "Extra";
|
||||||
|
else if (rawT.includes("OFF"))
|
||||||
|
label = window.I18N?.btn_off || "Off";
|
||||||
|
|
||||||
|
// 🎨 INJECTION DYNAMIQUE DE LA COULEUR CSS (La même que le calendrier !)
|
||||||
|
const colorIndex = this.helperColorMap[`${h.id}_${t}`] ?? 0;
|
||||||
|
const borderColor = `var(--fc-palette-text-${colorIndex})`;
|
||||||
|
|
||||||
cardHtml += `
|
cardHtml += `
|
||||||
<div style="display: flex; align-items: center; gap: 8px; background: var(--bg-page); border: 1px solid var(--border-light); border-left: 3px solid var(--warning); border-radius: 6px; padding: 4px 10px;">
|
<div style="display: flex; align-items: center; gap: 8px; background: var(--bg-page); border: 1px solid var(--border-light); border-left: 3px solid ${borderColor}; border-radius: 6px; padding: 4px 10px;">
|
||||||
<span style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">${label}</span>
|
<span style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">${label}</span>
|
||||||
<span style="font-size: 1rem; font-weight: 800; color: var(--text-main); line-height: 1;">${val}<span style="font-size: 0.8rem; margin-left: 2px;">j</span></span>
|
<span style="font-size: 1rem; font-weight: 800; color: var(--text-main); line-height: 1;">${val}<span style="font-size: 0.8rem; margin-left: 2px;">j</span></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasLeaves)
|
if (!hasLeaves)
|
||||||
cardHtml += `<div style="font-size: 0.85rem; color: var(--text-muted); font-style: italic;">Aucun congé posé.</div>`;
|
cardHtml += `<div style="font-size: 0.85rem; color: var(--text-muted); font-style: italic;">${window.I18N?.fc_no_leaves_taken || "Aucun congé posé."}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
cardHtml += `
|
cardHtml += `
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> <!-- /Zone Gauche -->
|
||||||
|
|
||||||
<!-- Zone Droite : Sélecteurs de Période Dynamiques -->
|
<!-- Zone Droite : Sélecteurs de Période Dynamiques -->
|
||||||
<div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
|
<div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
|
||||||
@@ -1260,15 +1278,28 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
|
|
||||||
const dur = parseFloat(e.duration) || 1;
|
const dur = parseFloat(e.duration) || 1;
|
||||||
|
|
||||||
if (e.type === "CHILD_SICK")
|
if (e.type === "CHILD_SICK") {
|
||||||
w.totals["sick_" + e.person_id] =
|
w.totals["sick_" + e.person_id] =
|
||||||
(w.totals["sick_" + e.person_id] || 0) + dur;
|
(w.totals["sick_" + e.person_id] || 0) + dur;
|
||||||
if (e.type === "HELPER_OFF")
|
} else {
|
||||||
w.totals["off_" + e.person_id] =
|
const rawType = String(e.type).toUpperCase();
|
||||||
(w.totals["off_" + e.person_id] || 0) + dur;
|
const isOldHelperEvent =
|
||||||
if (e.type === "HELPER_EXTRA")
|
rawType.includes("OFF") || rawType.includes("EXTRA");
|
||||||
w.totals["extra_" + e.person_id] =
|
|
||||||
(w.totals["extra_" + e.person_id] || 0) + dur;
|
if (isOldHelperEvent) {
|
||||||
|
const pId = this.helpers.some(
|
||||||
|
(h) => parseInt(h.id) === parseInt(e.person_id),
|
||||||
|
)
|
||||||
|
? e.person_id
|
||||||
|
: this.helpers[0]?.id || 0;
|
||||||
|
let mappedType = e.type;
|
||||||
|
if (rawType.includes("EXTRA")) mappedType = "EXTRA";
|
||||||
|
else if (rawType.includes("OFF")) mappedType = "OFF";
|
||||||
|
|
||||||
|
w.totals[`leave_${pId}_${mappedType}`] =
|
||||||
|
(w.totals[`leave_${pId}_${mappedType}`] || 0) + dur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Modes de garde dynamiques
|
// Modes de garde dynamiques
|
||||||
if (upperCareModes.includes(e.type)) {
|
if (upperCareModes.includes(e.type)) {
|
||||||
@@ -1448,8 +1479,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
this.planningBody.innerHTML = "";
|
this.planningBody.innerHTML = "";
|
||||||
|
|
||||||
if (!this.weeks || this.weeks.length === 0) {
|
if (!this.weeks || this.weeks.length === 0) {
|
||||||
this.planningBody.innerHTML =
|
this.planningBody.innerHTML = `<tr><td colspan='15' style='text-align:center; padding: 20px; color: var(--text-muted);'>${window.I18N?.["fc_no_data"] || "Aucune donnée pour cette année scolaire."}</td></tr>`;
|
||||||
"<tr><td colspan='15' style='text-align:center; padding: 20px; color: var(--text-muted);'>Aucune donnée pour cette année scolaire.</td></tr>";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1466,33 +1496,39 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const upperCareModes = (this.careModes || []).map((m) =>
|
const upperCareModes = (this.careModes || []).map((m) =>
|
||||||
String(m).toUpperCase(),
|
String(m).toUpperCase(),
|
||||||
);
|
);
|
||||||
|
const helperIds = (this.helpers || []).map((h) => parseInt(h.id));
|
||||||
|
|
||||||
this.weeks.forEach((w, idx) => {
|
this.weeks.forEach((w, idx) => {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
tr.setAttribute("data-month", w.monthKey);
|
tr.setAttribute("data-month", w.monthKey);
|
||||||
|
|
||||||
if (idx === 0 || this.weeks[idx - 1].monthKey !== w.monthKey)
|
if (idx === 0 || this.weeks[idx - 1].monthKey !== w.monthKey) {
|
||||||
tr.classList.add("fc-month-first-week-row");
|
tr.classList.add("fc-month-first-week-row");
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
idx === this.weeks.length - 1 ||
|
idx === this.weeks.length - 1 ||
|
||||||
this.weeks[idx + 1].monthKey !== w.monthKey
|
this.weeks[idx + 1].monthKey !== w.monthKey
|
||||||
)
|
) {
|
||||||
tr.classList.add("fc-month-last-week-row");
|
tr.classList.add("fc-month-last-week-row");
|
||||||
|
|
||||||
if (!processedMonths[w.monthKey]) {
|
|
||||||
processedMonths[w.monthKey] = true;
|
|
||||||
const td = document.createElement("td");
|
|
||||||
td.className = "col-month col-sticky-mois";
|
|
||||||
td.innerHTML = `<span class="fc-sticky-mois-label">${w.monthName || ""}</span>`;
|
|
||||||
td.rowSpan = monthSpans[w.monthKey];
|
|
||||||
tr.appendChild(td);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. Colonne Sticky MOIS
|
||||||
|
if (!processedMonths[w.monthKey]) {
|
||||||
|
processedMonths[w.monthKey] = true;
|
||||||
|
const tdMonth = document.createElement("td");
|
||||||
|
tdMonth.className = "col-month col-sticky-mois rotated-text";
|
||||||
|
tdMonth.innerHTML = `<span>${w.monthName || ""}</span>`;
|
||||||
|
tdMonth.rowSpan = monthSpans[w.monthKey];
|
||||||
|
tr.appendChild(tdMonth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Colonne Sticky SEMAINE
|
||||||
const tdW = document.createElement("td");
|
const tdW = document.createElement("td");
|
||||||
tdW.className = "col-month col-sticky-sem";
|
tdW.className = "col-month col-sticky-sem rotated-text";
|
||||||
tdW.textContent = w.weekLabel || "";
|
tdW.innerHTML = `<span>${w.weekLabel || ""}</span>`;
|
||||||
tr.appendChild(tdW);
|
tr.appendChild(tdW);
|
||||||
|
|
||||||
|
// 3. Jours de la semaine (Lundi à Vendredi)
|
||||||
["mon", "tue", "wed", "thu", "fri"].forEach((d) => {
|
["mon", "tue", "wed", "thu", "fri"].forEach((d) => {
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
const dateObj = w.dayDates[d];
|
const dateObj = w.dayDates[d];
|
||||||
@@ -1503,7 +1539,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
td.className = "col-day";
|
td.className = "col-day";
|
||||||
|
|
||||||
const events = w.dayFlags?.[d]?.events || [];
|
const events = w.dayFlags?.[d]?.events || [];
|
||||||
|
const dayLeaves = (this.leaves || []).filter(
|
||||||
|
(l) => (l.leave_date || l.date) === iso,
|
||||||
|
);
|
||||||
|
|
||||||
|
// A. Application des classes de coloration de fond CSS
|
||||||
events.forEach((evt) => {
|
events.forEach((evt) => {
|
||||||
if (evt.type === "PUBLIC_HOLIDAY")
|
if (evt.type === "PUBLIC_HOLIDAY")
|
||||||
td.classList.add("fc-day--public-holiday");
|
td.classList.add("fc-day--public-holiday");
|
||||||
@@ -1513,23 +1553,67 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
td.classList.add("fc-day--has-guard");
|
td.classList.add("fc-day--has-guard");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Détection dynamique et globale des congés de l'intervenant
|
||||||
|
let appliedColorIndex = -1;
|
||||||
|
|
||||||
|
const helperLeaf = dayLeaves.find((l) =>
|
||||||
|
helperIds.includes(parseInt(l.person_id)),
|
||||||
|
);
|
||||||
|
if (helperLeaf) {
|
||||||
|
appliedColorIndex =
|
||||||
|
this.helperColorMap[
|
||||||
|
`${helperLeaf.person_id}_${helperLeaf.leave_type}`
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
const helperEvent = events.find(
|
||||||
|
(e) =>
|
||||||
|
helperIds.includes(parseInt(e.person_id)) ||
|
||||||
|
String(e.type).toUpperCase().includes("OFF") ||
|
||||||
|
String(e.type).toUpperCase().includes("EXTRA"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (helperEvent) {
|
||||||
|
const pId = helperIds.includes(parseInt(helperEvent.person_id))
|
||||||
|
? helperEvent.person_id
|
||||||
|
: helperIds[0];
|
||||||
|
const rawType = String(helperEvent.type).toUpperCase();
|
||||||
|
|
||||||
|
let mappedType = helperEvent.type;
|
||||||
|
if (rawType.includes("EXTRA")) mappedType = "EXTRA";
|
||||||
|
else if (rawType.includes("OFF")) mappedType = "OFF";
|
||||||
|
|
||||||
|
appliedColorIndex =
|
||||||
|
this.helperColorMap[`${pId}_${mappedType}`] ??
|
||||||
|
this.helperColorMap[`${pId}_${helperEvent.type}`] ??
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appliedColorIndex !== -1 && appliedColorIndex !== undefined) {
|
||||||
|
td.classList.add(`fc-bg-palette-${appliedColorIndex}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// B. Contenu HTML de la cellule (Numéro du jour, Icônes de garde, Maladie Enfants, Initiales Parents)
|
||||||
let content = `<div style="position:relative; height:100%; width:100%; min-height:40px;">
|
let content = `<div style="position:relative; height:100%; width:100%; min-height:40px;">
|
||||||
<span style="display:block; padding:2px;">${String(dateObj.getDate()).padStart(2, "0")}</span>`;
|
<span style="display:block; padding:2px;">${String(dateObj.getDate()).padStart(2, "0")}</span>`;
|
||||||
|
|
||||||
|
// Icônes des modes de garde
|
||||||
let iconsHtml = `<div style="position:absolute; top:2px; right:2px; display:flex; gap:2px;">`;
|
let iconsHtml = `<div style="position:absolute; top:2px; right:2px; display:flex; gap:2px;">`;
|
||||||
events.forEach((evt) => {
|
events.forEach((evt) => {
|
||||||
if (upperCareModes.includes(evt.type)) {
|
if (upperCareModes.includes(evt.type)) {
|
||||||
const modeName = String(evt.type).toLowerCase();
|
const modeName = String(evt.type).toLowerCase();
|
||||||
if (modeName === "avis")
|
if (modeName === "avis") {
|
||||||
iconsHtml += `<img src="/modules/family-calendar/assets/img/avis.svg" class="fc-icon-avis" title="Avis" style="width:14px; height:14px; object-fit:contain;">`;
|
iconsHtml += `<img src="/modules/family-calendar/assets/img/avis.svg" class="fc-icon-avis" title="Avis" style="width:14px; height:14px; object-fit:contain;">`;
|
||||||
else if (modeName === "centre")
|
} else if (modeName === "centre") {
|
||||||
iconsHtml += `<span class="fc-icon-centre" title="Centre" style="font-size:1.1rem; line-height:1;">🏫</span>`;
|
iconsHtml += `<span class="fc-icon-centre" title="Centre" style="font-size:1.1rem; line-height:1;">🏫</span>`;
|
||||||
else
|
} else {
|
||||||
iconsHtml += `<span style="background:var(--primary); color:#fff; border-radius:3px; padding:0 3px; font-size:9px;">${modeName.substring(0, 3)}</span>`;
|
iconsHtml += `<span style="background:var(--primary); color:#fff; border-radius:3px; padding:0 3px; font-size:9px;">${modeName.substring(0, 3)}</span>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
content += iconsHtml + `</div>`;
|
content += iconsHtml + `</div>`;
|
||||||
|
|
||||||
|
// Icônes Enfant Malade
|
||||||
let sickHtml = `<div style="position:absolute; bottom:2px; right:2px; display:flex; flex-direction:column; align-items:flex-end; gap:1px; font-size:11px; font-weight:bold; line-height:1;">`;
|
let sickHtml = `<div style="position:absolute; bottom:2px; right:2px; display:flex; flex-direction:column; align-items:flex-end; gap:1px; font-size:11px; font-weight:bold; line-height:1;">`;
|
||||||
events.forEach((evt) => {
|
events.forEach((evt) => {
|
||||||
if (evt.type === "CHILD_SICK") {
|
if (evt.type === "CHILD_SICK") {
|
||||||
@@ -1543,11 +1627,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
content += sickHtml + `</div>`;
|
content += sickHtml + `</div>`;
|
||||||
|
|
||||||
const dayLeaves = (this.leaves || []).filter(
|
// Initiales des Parents en congé
|
||||||
(l) => l.leave_date === iso || l.date === iso,
|
|
||||||
);
|
|
||||||
if (dayLeaves.length) {
|
if (dayLeaves.length) {
|
||||||
let html = `<div style="position:absolute; bottom:0; left:0; width:100%; font-size:9px; display:flex; justify-content:center; gap:2px; pointer-events:none;">`;
|
let parentLeavesHtml = `<div style="position:absolute; bottom:0; left:0; width:100%; font-size:9px; display:flex; justify-content:center; gap:2px; pointer-events:none;">`;
|
||||||
(this.parents || []).forEach((person) => {
|
(this.parents || []).forEach((person) => {
|
||||||
if (
|
if (
|
||||||
dayLeaves.some(
|
dayLeaves.some(
|
||||||
@@ -1555,16 +1637,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
parseInt(l.person_id || l.person) === parseInt(person.id),
|
parseInt(l.person_id || l.person) === parseInt(person.id),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
html += `<span style="color:${person.color || "#000"}; font-weight:800; margin: 0 1px;">${String(person.name).charAt(0).toUpperCase()}</span>`;
|
parentLeavesHtml += `<span style="color:${person.color || "#000"}; font-weight:800; margin: 0 1px;">${String(person.name).charAt(0).toUpperCase()}</span>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
content += html + `</div>`;
|
content += parentLeavesHtml + `</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.innerHTML = content + `</div>`;
|
td.innerHTML = content + `</div>`;
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1. Congés intervenant (Dynamiques)
|
// 4. Totaux : Congés de l'intervenant / Helper (Nombres bruts)
|
||||||
(this.helpers || []).forEach((h) => {
|
(this.helpers || []).forEach((h) => {
|
||||||
const hLeaves =
|
const hLeaves =
|
||||||
this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || [];
|
this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || [];
|
||||||
@@ -1572,33 +1655,42 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const typeName = typeof lt === "object" ? lt.type : lt;
|
const typeName = typeof lt === "object" ? lt.type : lt;
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
td.className = "col-total";
|
td.className = "col-total";
|
||||||
td.textContent = fmt(w.totals[`leave_${h.id}_${typeName}`] || 0);
|
|
||||||
|
const val = w.totals[`leave_${h.id}_${typeName}`] || 0;
|
||||||
|
if (val > 0) {
|
||||||
|
td.textContent = fmt(val);
|
||||||
|
} else {
|
||||||
|
td.textContent = "";
|
||||||
|
}
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Modes de garde (On ignore Nounou si Helper présent)
|
// 5. Totaux : Modes de garde (On masque "Nounou" si un intervenant existe)
|
||||||
(this.careModes || []).forEach((mode) => {
|
(this.careModes || []).forEach((mode) => {
|
||||||
if (mode.toLowerCase() === "nounou" && this.helpers.length > 0)
|
if (mode.toLowerCase() === "nounou" && this.helpers.length > 0)
|
||||||
return;
|
return;
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
td.className = "col-total";
|
td.className = "col-total";
|
||||||
td.textContent = fmt(w.totals["mode_" + mode] || 0);
|
const val = w.totals["mode_" + mode] || 0;
|
||||||
|
td.textContent = fmt(val);
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Maladie enfants
|
// 6. Totaux : Maladie par enfant
|
||||||
(this.kids || []).forEach((kid) => {
|
(this.kids || []).forEach((kid) => {
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
td.className = "col-total";
|
td.className = "col-total";
|
||||||
td.textContent = fmt(w.totals["sick_" + kid.id] || 0);
|
const val = w.totals["sick_" + kid.id] || 0;
|
||||||
|
td.textContent = fmt(val);
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 7. Colonnes de suivi des soldes mensuels (Parents : Av. / Use)
|
||||||
if (!processedLeavesCols[w.monthKey]) {
|
if (!processedLeavesCols[w.monthKey]) {
|
||||||
processedLeavesCols[w.monthKey] = true;
|
processedLeavesCols[w.monthKey] = true;
|
||||||
(this.parents || []).forEach((parent, index) => {
|
(this.parents || []).forEach((parent, index) => {
|
||||||
const cssPrefix = index % 2 === 0 ? "col-alex" : "col-laia";
|
const cssPrefix = index % 2 === 0 ? "col-p1" : "col-p2";
|
||||||
const matrix =
|
const matrix =
|
||||||
this.leaveMatrix[String(parent.id)] ||
|
this.leaveMatrix[String(parent.id)] ||
|
||||||
this.leaveMatrix[Number(parent.id)] ||
|
this.leaveMatrix[Number(parent.id)] ||
|
||||||
@@ -1672,13 +1764,49 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
cls += " fc-day--school-holiday";
|
cls += " fc-day--school-holiday";
|
||||||
if (dayEvts.some((e) => e.type === "PUBLIC_HOLIDAY"))
|
if (dayEvts.some((e) => e.type === "PUBLIC_HOLIDAY"))
|
||||||
cls += " fc-day--public-holiday";
|
cls += " fc-day--public-holiday";
|
||||||
if (dayEvts.some((e) => e.type === "HELPER_OFF"))
|
|
||||||
cls += " fc-day--off-carole";
|
|
||||||
if (dayEvts.some((e) => e.type === "HELPER_EXTRA"))
|
|
||||||
cls += " fc-day--extra-off-carole";
|
|
||||||
if (dayEvts.some((e) => upperCareModes.includes(e.type)))
|
if (dayEvts.some((e) => upperCareModes.includes(e.type)))
|
||||||
cls += " fc-day--has-guard";
|
cls += " fc-day--has-guard";
|
||||||
|
|
||||||
|
const helperIds = (this.helpers || []).map((h) => parseInt(h.id));
|
||||||
|
const dayLeaves = this.leaves.filter((l) => l.leave_date === iso);
|
||||||
|
|
||||||
|
let appliedColorIndex = -1;
|
||||||
|
const helperLeaf = dayLeaves.find((l) =>
|
||||||
|
helperIds.includes(parseInt(l.person_id)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (helperLeaf) {
|
||||||
|
appliedColorIndex =
|
||||||
|
this.helperColorMap[
|
||||||
|
`${helperLeaf.person_id}_${helperLeaf.leave_type}`
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
const helperEvent = dayEvts.find(
|
||||||
|
(e) =>
|
||||||
|
helperIds.includes(parseInt(e.person_id)) ||
|
||||||
|
e.type === "HELPER_OFF" ||
|
||||||
|
e.type === "HELPER_EXTRA",
|
||||||
|
);
|
||||||
|
if (helperEvent) {
|
||||||
|
const mappedType =
|
||||||
|
helperEvent.type === "HELPER_OFF"
|
||||||
|
? "OFF"
|
||||||
|
: helperEvent.type === "HELPER_EXTRA"
|
||||||
|
? "EXTRA"
|
||||||
|
: helperEvent.type;
|
||||||
|
appliedColorIndex =
|
||||||
|
this.helperColorMap[`${helperEvent.person_id}_${mappedType}`] ??
|
||||||
|
this.helperColorMap[
|
||||||
|
`${helperEvent.person_id}_${helperEvent.type}`
|
||||||
|
] ??
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appliedColorIndex !== -1 && appliedColorIndex !== undefined) {
|
||||||
|
cls += ` fc-bg-palette-${appliedColorIndex}`;
|
||||||
|
}
|
||||||
|
|
||||||
let content = `<div style="position:relative; height:100%; min-height:55px;"><span class="fc-day-number">${d}</span>`;
|
let content = `<div style="position:relative; height:100%; min-height:55px;"><span class="fc-day-number">${d}</span>`;
|
||||||
|
|
||||||
let iconsHtml = `<div style="position:absolute; top:2px; right:2px; display:flex; gap:2px;">`;
|
let iconsHtml = `<div style="position:absolute; top:2px; right:2px; display:flex; gap:2px;">`;
|
||||||
@@ -1708,7 +1836,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
content += sickHtml + `</div>`;
|
content += sickHtml + `</div>`;
|
||||||
|
|
||||||
const dayLeaves = this.leaves.filter((l) => l.leave_date === iso);
|
|
||||||
if (dayLeaves.length) {
|
if (dayLeaves.length) {
|
||||||
content += `<div style="position:absolute; bottom:2px; left:2px; font-size:10px; font-weight:bold;">`;
|
content += `<div style="position:absolute; bottom:2px; left:2px; font-size:10px; font-weight:bold;">`;
|
||||||
this.parents.forEach((parent) => {
|
this.parents.forEach((parent) => {
|
||||||
@@ -1748,10 +1875,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
// 2. Boucler sur chaque enfant concerné pour un calcul individuel
|
// 2. Boucler sur chaque enfant concerné pour un calcul individuel
|
||||||
nounouKids.forEach((kid) => {
|
nounouKids.forEach((kid) => {
|
||||||
let workingDays = 0;
|
let workingDays = 0;
|
||||||
let off = 0;
|
let absencesNounou = 0;
|
||||||
let extra = 0;
|
|
||||||
let sick = 0;
|
let sick = 0;
|
||||||
|
|
||||||
|
const helperIds = this.helpers.map((h) => parseInt(h.id));
|
||||||
|
|
||||||
for (let d = 1; d <= daysInMonth; d++) {
|
for (let d = 1; d <= daysInMonth; d++) {
|
||||||
const dateObj = new Date(year, month, d);
|
const dateObj = new Date(year, month, d);
|
||||||
const dayOfWeek = dateObj.getDay();
|
const dayOfWeek = dateObj.getDay();
|
||||||
@@ -1768,12 +1896,20 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
workingDays += 1;
|
workingDays += 1;
|
||||||
|
|
||||||
const dayEvents = this.events.filter((e) => e.date === iso);
|
const dayEvents = this.events.filter((e) => e.date === iso);
|
||||||
|
const dayLeaves = this.leaves.filter((l) => l.leave_date === iso);
|
||||||
|
|
||||||
dayEvents.forEach((e) => {
|
dayEvents.forEach((e) => {
|
||||||
const dur = parseFloat(e.duration) || 1;
|
const dur = parseFloat(e.duration) || 1;
|
||||||
|
const rawType = String(e.type).toUpperCase();
|
||||||
|
|
||||||
if (e.type === "HELPER_OFF") off += dur;
|
// Si c'est un vieil événement historisé OFF/EXTRA
|
||||||
if (e.type === "HELPER_EXTRA") extra += dur;
|
if (
|
||||||
|
rawType.includes("OFF") ||
|
||||||
|
rawType.includes("EXTRA") ||
|
||||||
|
helperIds.includes(parseInt(e.person_id))
|
||||||
|
) {
|
||||||
|
absencesNounou += dur;
|
||||||
|
}
|
||||||
|
|
||||||
// On vérifie que la maladie concerne BIEN cet enfant précis !
|
// On vérifie que la maladie concerne BIEN cet enfant précis !
|
||||||
if (
|
if (
|
||||||
@@ -1783,23 +1919,43 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
sick += dur;
|
sick += dur;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prise en compte des nouveaux congés propres aux intervenants
|
||||||
|
dayLeaves.forEach((l) => {
|
||||||
|
const dur = parseFloat(l.duration) || 1;
|
||||||
|
if (helperIds.includes(parseInt(l.person_id))) {
|
||||||
|
absencesNounou += dur;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcul final strict : Jours ouvrés - Maladie (de l'enfant) - Extra - Off
|
// Récupération dynamique du nom de l'intervenant avec i18n
|
||||||
const presence = Math.max(0, workingDays - sick - extra - off);
|
const fallbackHelper = window.I18N?.fc_role_helper || "Intervenant";
|
||||||
|
const helperName =
|
||||||
|
this.helpers && this.helpers.length > 0
|
||||||
|
? this.helpers.map((h) => h.name).join(" & ")
|
||||||
|
: fallbackHelper;
|
||||||
|
|
||||||
|
// Calcul final strict : Jours ouvrés - Maladie (de l'enfant) - Absences Nounou
|
||||||
|
const presence = Math.max(0, workingDays - sick - absencesNounou);
|
||||||
|
|
||||||
|
// Textes traduits
|
||||||
|
const trPresence = window.I18N?.fc_presence || "Présence";
|
||||||
|
const trWorking = window.I18N?.fc_working_days || "Ouvrés";
|
||||||
|
const trAbs = window.I18N?.fc_absences || "Abs.";
|
||||||
|
const trSick = window.I18N?.fc_menu_sick || "Maladie";
|
||||||
|
|
||||||
// Rendu HTML individuel
|
// Rendu HTML individuel
|
||||||
html += `
|
html += `
|
||||||
<div style="margin-top: 10px;">
|
<div style="margin-top: 10px;">
|
||||||
<div style="font-size: 0.8rem; font-weight: bold; color: var(--text-muted); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.05em;">
|
<div style="font-size: 0.8rem; font-weight: bold; color: var(--text-muted); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.05em;">
|
||||||
👧👦 Présence ${kid.name} (Nounou)
|
👧👦 ${trPresence} ${kid.name} (${helperName})
|
||||||
</div>
|
</div>
|
||||||
<div class="fc-month-summary-inline" style="display:flex; justify-content:space-around; gap:10px; font-size:0.75rem; background: var(--bg-panel); padding: 8px; border-radius: 8px; border: 1px solid var(--border-light);">
|
<div class="fc-month-summary-inline" style="display:flex; justify-content:space-around; gap:10px; font-size:0.75rem; background: var(--bg-panel); padding: 8px; border-radius: 8px; border: 1px solid var(--border-light);">
|
||||||
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>Ouvrés</span> <strong style="color:var(--text-main); font-size:0.95rem;">${workingDays} j</strong></div>
|
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>${trWorking}</span> <strong style="color:var(--text-main); font-size:0.95rem;">${workingDays} j</strong></div>
|
||||||
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>Off</span> <strong style="color:var(--text-main); font-size:0.95rem;">${parseFloat(off.toFixed(1))} j</strong></div>
|
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>${trAbs} ${helperName}</span> <strong style="color:var(--text-main); font-size:0.95rem;">${parseFloat(absencesNounou.toFixed(1))} j</strong></div>
|
||||||
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>Extra</span> <strong style="color:var(--text-main); font-size:0.95rem;">${parseFloat(extra.toFixed(1))} j</strong></div>
|
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>${trSick}</span> <strong style="color:var(--danger); font-size:0.95rem;">${parseFloat(sick.toFixed(1))} j</strong></div>
|
||||||
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>Maladie</span> <strong style="color:var(--danger); font-size:0.95rem;">${parseFloat(sick.toFixed(1))} j</strong></div>
|
<div class="fc-summ-pill pf-presence-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>${trPresence}</span> <strong style="color:var(--primary); font-size:0.95rem;">${parseFloat(presence.toFixed(1))} j</strong></div>
|
||||||
<div class="fc-summ-pill" style="display:flex; flex-direction:column; align-items:center; flex:1;"><span>Présence</span> <strong style="color:var(--primary); font-size:0.95rem;">${parseFloat(presence.toFixed(1))} j</strong></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -2355,10 +2511,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const hLeaves =
|
const hLeaves =
|
||||||
this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || [];
|
this.leaveMatrix[h.id] || this.leaveMatrix[Number(h.id)] || [];
|
||||||
if (hLeaves.length > 0) {
|
if (hLeaves.length > 0) {
|
||||||
const hColor = h.color || "var(--warning)";
|
|
||||||
html += `<div class="fc-menu-section">${buildHeader(h.name, "clear-leaves-person", null, h.id)}<div class="fc-menu-grid">`;
|
html += `<div class="fc-menu-section">${buildHeader(h.name, "clear-leaves-person", null, h.id)}<div class="fc-menu-grid">`;
|
||||||
hLeaves.forEach((lt) => {
|
hLeaves.forEach((lt) => {
|
||||||
const lType = typeof lt === "object" ? lt.type : lt;
|
const lType = typeof lt === "object" ? lt.type : lt;
|
||||||
|
const pIdx = this.helperColorMap[`${h.id}_${lType}`] ?? 0;
|
||||||
|
const hColor = `var(--fc-palette-text-${pIdx})`;
|
||||||
html += `<button class="fc-menu-btn" style="${getActiveStyleL(lType, h.id, hColor)}" data-action="add-leave" data-pid="${h.id}" data-type="${lType}">${lType}</button>`;
|
html += `<button class="fc-menu-btn" style="${getActiveStyleL(lType, h.id, hColor)}" data-action="add-leave" data-pid="${h.id}" data-type="${lType}">${lType}</button>`;
|
||||||
});
|
});
|
||||||
html += `</div></div>`;
|
html += `</div></div>`;
|
||||||
|
|||||||
Reference in new issue
Block a user