settings calendar
Deploy HouseHub / deploy (push) Successful in 2s

This commit is contained in:
2026-06-11 17:57:09 +02:00
parent 429a4ccb66
commit 6459c225ac
14 changed files with 2435 additions and 883 deletions
+200 -88
View File
@@ -9,7 +9,7 @@ require __DIR__ . '/includes/db.php';
require_once __DIR__ . '/includes/i18n.php';
// 1. Récupération de toutes les personnes avec leurs modes de garde
$stmtPeople = $pdo->query("SELECT id, name, user_id, role, care_modes FROM pf_people ORDER BY id ASC");
$stmtPeople = $pdo->query("SELECT id, name, user_id, role, care_modes FROM pf_people WHERE is_active = 1 ORDER BY id ASC");
$familyPeople = $stmtPeople->fetchAll(PDO::FETCH_ASSOC);
$parents = [];
@@ -21,6 +21,23 @@ $activeCareModes = [];
foreach ($familyPeople as $p) {
$role = strtolower($p['role'] ?? '');
if ($role === 'parent') {
// --- 🟢 NOUVEAU : Récupération dynamique des types de congés du parent ---
$stmtLT = $pdo->prepare("
SELECT DISTINCT leave_type FROM (
SELECT leave_type FROM pf_leave_balances WHERE person_id = ?
UNION
SELECT leave_type FROM pf_leave_snapshots WHERE person_id = ?
) as t ORDER BY leave_type = 'CP' DESC, leave_type = 'JRA' DESC, leave_type = 'JA' DESC, leave_type ASC
");
$stmtLT->execute([$p['id'], $p['id']]);
$lTypes = $stmtLT->fetchAll(PDO::FETCH_COLUMN);
// Fallback de sécurité si aucun compteur n'est encore paramétré
if (empty($lTypes)) {
$lTypes = ['CP', 'JRA', 'JA'];
}
$p['leave_types'] = $lTypes;
$parents[] = $p;
} elseif ($role === 'enfant') {
// Décodage sécurisé des modes de garde
@@ -28,7 +45,7 @@ foreach ($familyPeople as $p) {
if (!is_array($modes)) $modes = [];
$p['modes'] = $modes;
$kids[] = $p;
foreach ($modes as $m) {
$activeCareModes[$m] = true;
}
@@ -45,10 +62,18 @@ require __DIR__ . '/header.php';
?>
<div class="pf-container" style="max-width:100%; padding:0;">
<div class="fc-header-row">
<h1><?= tr('fc_main_header') ?></h1>
<div class="fc-header-row" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px; margin-bottom: 24px;">
<div style="display: flex; gap: 10px;">
<!-- Bloc Titre + Roue crantée -->
<div style="display: flex; align-items: center; gap: 12px;">
<h1 style="margin: 0;"><?= tr('fc_main_header') ?></h1>
<button id="btnOpenCalendarSettings" class="btn-settings-gear" title="<?= tr('fc_btn_settings') ?>">
⚙️
</button>
</div>
<!-- Boutons d'actions -->
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<button id="btnOpenSnapshotModal" class="pf-btn-icon-text">
<span class="icon">⚖️</span>
<span class="text"><?= tr('fc_btn_correct_balances') ?></span>
@@ -137,103 +162,187 @@ require __DIR__ . '/header.php';
</div>
</div>
<section class="pf-section">
<div class="fc-month-calendar-wrapper">
<!-- 3. MODALE : PARAMÈTRES AVANCÉS DU CALENDRIER -->
<div id="modalCalendarSettings" class="pf-modal">
<div class="pf-modal-content" style="max-width: 750px; width: 95%; padding: 0; overflow: hidden; display: flex; flex-direction: column;">
<!-- HEADER -->
<div class="pf-modal-header" style="padding: 1.2rem 1.5rem; border-bottom: 1px solid var(--border-light); background: var(--bg-panel);">
<h3 class="pf-modal-title" style="display: flex; align-items: center; gap: 8px; margin: 0;">
<span style="color: var(--text-muted); font-size: 1.2rem;">⚙️</span> <?= tr('fc_modal_settings_title') ?>
</h3>
<button type="button" class="pf-modal-close" style="margin-right: 1.5rem;" onclick="closeCalendarSettings()">&times;</button>
</div>
<!-- CORPS SCINDÉ EN DEUX (SIDEBAR / CONTENU) -->
<div style="display: flex; flex-direction: row; height: 60vh; min-height: 400px; background: var(--bg-panel);">
<!-- SIDEBAR GAUCHE -->
<div style="width: 220px; border-right: 1px solid var(--border-light); padding: 1rem 0; display: flex; flex-direction: column; gap: 4px;">
<button type="button" id="tab-btn-foyer" class="fc-sidebar-tab bs-tab-btn active" onclick="switchCalendarTab('foyer')">
<?= tr('fc_tab_foyer') ?>
</button>
<button type="button" id="tab-btn-membres" class="fc-sidebar-tab bs-tab-btn" onclick="switchCalendarTab('membres')">
<?= tr('fc_tab_members') ?>
</button>
</div>
<!-- CONTENU DROITE -->
<div class="pf-modal-body" style="flex: 1; padding: 1.5rem; overflow-y: auto;">
<!-- PANE A : CONFIGURATION GÉNÉRALE DU FOYER -->
<div id="cal-pane-foyer" class="cal-settings-pane">
<div style="display: flex; align-items: center; margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-light); padding-bottom: 0.8rem;">
<h4 style="margin: 0; font-size: 1.1rem; color: var(--text-main);"><?= tr('fc_tab_foyer') ?></h4>
</div>
<form id="formCalFoyer" onsubmit="submitCalFoyer(event)">
<div class="pf-form-group" style="margin-bottom: 1.5rem;">
<label class="pf-label" style="font-weight: 600; margin-bottom: 6px;"><?= tr('fc_zone_label') ?></label>
<select id="setZoneScolaire" name="zone_scolaire" class="pf-input" required style="width: 100%; border-radius: 8px; background-color: var(--bg-page);">
<option value="A">Zone A</option>
<option value="B">Zone B</option>
<option value="C">Zone C</option>
<option value="Autre">Autre / Hors France</option>
</select>
<small class="pf-muted-note" style="margin-top: 4px; display: block;"><?= tr('fc_zone_desc') ?></small>
</div>
<div class="pf-form-group">
<label class="pf-label" style="font-weight: 600; margin-bottom: 6px;"><?= tr('fc_care_modes_label') ?></label>
<div style="background: var(--bg-page); border: 1px solid var(--border-light); border-radius: 8px; padding: 8px;">
<div id="careModesContainer" style="display: flex; flex-wrap: wrap; gap: 6px; min-height: 32px; margin-bottom: 8px;"></div>
<div style="display: flex; gap: 8px;">
<input type="text" id="inputNewCareMode" class="pf-input" placeholder="<?= tr('fc_add_mode_placeholder') ?>" style="flex: 1; background: var(--bg-soft); border: none; border-radius: 6px; padding: 6px 12px;">
<button type="button" class="pf-btn pf-btn-secondary" style="padding: 0 14px; border-radius: 6px;" onclick="addCareModeTag()"></button>
</div>
</div>
<small class="pf-muted-note" style="margin-top: 6px; display: block;"><?= tr('fc_care_modes_desc') ?></small>
</div>
<div style="margin-top: 2rem; display: flex; justify-content: flex-end; gap: 12px;">
<button type="button" class="pf-btn pf-btn-secondary" onclick="closeCalendarSettings()"><?= tr('btn_cancel') ?></button>
<button type="submit" class="pf-btn pf-btn-primary"><?= tr('save') ?></button>
</div>
</form>
</div>
<!-- PANE B : CONFIGURATION DE LA MATRICE COMPTEURS -->
<div id="cal-pane-membres" class="cal-settings-pane" style="display: none;">
<div style="display: flex; align-items: center; margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-light); padding-bottom: 0.8rem;">
<h4 style="margin: 0; font-size: 1.1rem; color: var(--text-main);"><?= tr('fc_tab_members') ?></h4>
</div>
<div style="margin-bottom: 1.5rem;">
<label class="pf-label" style="font-weight: 600; margin-bottom: 6px;"><?= tr('fc_select_member') ?></label>
<select id="selectCalMember" class="pf-input" style="width: 100%; font-weight: 600; border-radius: 8px; background-color: var(--bg-page);" onchange="loadMemberConfigView()"></select>
</div>
<div id="memberConfigZone" style="background: var(--bg-page); padding: 16px; border-radius: 12px; border: 1px solid var(--border-light); min-height: 120px;">
<!-- Injecté à la volée en fonction du membre sélectionné -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="fc-month-calendar-wrapper">
<div class="fc-month-header">
<div class="fc-month-nav-row">
<button id="fc-prev-month" class="fc-nav-button"></button>
<div id="fc-smart-date-selector" style="display:flex; align-items:center; justify-content:center; flex-grow:1; gap:6px;">
<select id="fc-select-month" class="fc-smart-select"></select>
<select id="fc-select-year" class="fc-smart-select"></select>
<span id="fc-multi-month-suffix" style="display:none; font-size:1.3rem; font-weight:800; color:#0f172a; margin-left:4px;"></span>
<div class="fc-month-nav-row">
<button id="fc-prev-month" class="fc-nav-button"></button>
<div id="fc-smart-date-selector" style="display:flex; align-items:center; justify-content:center; flex-grow:1; gap:6px;">
<select id="fc-select-month" class="fc-smart-select"></select>
<select id="fc-select-year" class="fc-smart-select"></select>
<span id="fc-multi-month-suffix" style="display:none; font-size:1.3rem; font-weight:800; color:#0f172a; margin-left:4px;"></span>
</div>
<button id="fc-next-month" class="fc-nav-button"></button>
</div>
<div class="fc-view-controls">
<button id="fc-today-btn" class="fc-today-button" title="<?= tr('fc_today_title') ?>"><?= tr('fc_today_short') ?></button>
<div class="fc-view-divider"></div>
<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="3months"><?= tr('fc_view_3m') ?></button>
</div>
<button id="fc-next-month" class="fc-nav-button"></button>
</div>
<div class="fc-view-controls">
<button id="fc-today-btn" class="fc-today-button" title="<?= tr('fc_today_title') ?>"><?= tr('fc_today_short') ?></button> <div class="fc-view-divider"></div>
<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="3months"><?= tr('fc_view_3m') ?></button>
</div>
</div>
<div class="fc-calendar-container">
<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-calendar" class="fc-month-calendar"></div>
<div id="fc-month-selectionMenu" class="fc-selection-menu" style="display:none;"></div>
</div>
<div id="fc-month-balances" class="fc-month-balances"></div>
</div>
</section>
</div>
<section class="pf-section">
<div class="fc-week-header">
<h2><?= tr('fc_weekly_planning') ?></h2>
<div class="fc-week-nav-controls">
<button id="fc-prev-school-year" class="fc-nav-button"></button>
<span id="fc-current-school-year-label"></span>
<button id="fc-next-school-year" class="fc-nav-button"></button>
<section class="pf-section" style="margin-top: 1.5rem;">
<div class="fc-week-header">
<h2><?= tr('fc_weekly_planning') ?></h2>
<div class="fc-week-nav-controls">
<button id="fc-prev-school-year" class="fc-nav-button"></button>
<span id="fc-current-school-year-label"></span>
<button id="fc-next-school-year" class="fc-nav-button"></button>
</div>
</div>
</div>
<div id="planningTable-wrapper">
<table id="planningTable">
<thead>
<tr>
<th rowspan="3" class="col-month col-sticky-mois"><?= tr('fc_col_month') ?></th>
<th rowspan="3" class="col-month col-sticky-mois"><?= tr('fc_col_week_short') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_mon') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_tue') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_wed') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_thu') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_fri') ?></th>
<div id="planningTable-wrapper">
<table id="planningTable">
<thead>
<tr>
<th rowspan="3" class="col-month col-sticky-mois"><?= tr('fc_col_month') ?></th>
<th rowspan="3" class="col-month col-sticky-mois"><?= tr('fc_col_week_short') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_mon') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_tue') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_wed') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_thu') ?></th>
<th rowspan="3" class="col-day"><?= tr('day_fri') ?></th>
<?php foreach ($activeCareModes as $mode): ?>
<th rowspan="3" class="col-total rotated-text"><span><?= htmlspecialchars($mode) ?></span></th>
<?php endforeach; ?>
<?php foreach ($activeCareModes as $mode): ?>
<th rowspan="3" class="col-total rotated-text"><span><?= htmlspecialchars($mode) ?></span></th>
<?php endforeach; ?>
<?php foreach ($kids as $kid): ?>
<th rowspan="3" class="col-total rotated-text"><span>Maladie <?= htmlspecialchars($kid['name']) ?></span></th>
<?php endforeach; ?>
<?php foreach ($kids as $kid): ?>
<th rowspan="3" class="col-total rotated-text"><span>Maladie <?= htmlspecialchars($kid['name']) ?></span></th>
<?php endforeach; ?>
<?php foreach ($parents as $index => $parent):
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
?>
<th colspan="6" class="<?= $parentClass ?> header-group"><?= htmlspecialchars(strtoupper($parent['name'])) ?></th>
<?php endforeach; ?>
</tr>
<tr>
<?php foreach ($parents as $index => $parent):
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
?>
<th colspan="2" class="<?= $parentClass ?>-sub">CP</th>
<th colspan="2" class="<?= $parentClass ?>-sub">JRA</th>
<th colspan="2" class="<?= $parentClass ?>-sub">JA</th>
<?php endforeach; ?>
</tr>
<tr>
<?php foreach ($parents as $index => $parent):
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
?>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-av"><?= tr('fc_col_av') ?></th>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-use"><?= tr('fc_col_use') ?></th>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-av"><?= tr('fc_col_av') ?></th>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-use"><?= tr('fc_col_use') ?></th>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-av"><?= tr('fc_col_av') ?></th>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-use"><?= tr('fc_col_use') ?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody id="planningBody"></tbody>
</table>
<div id="selectionMenu" class="fc-selection-menu" style="display:none;"></div>
</div>
<!-- 🟢 NOUVEAU : Colspan dynamique selon le nombre de compteurs de chaque parent -->
<?php foreach ($parents as $index => $parent):
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
$colspan = count($parent['leave_types']) * 2;
?>
<th colspan="<?= $colspan ?>" class="<?= $parentClass ?> header-group"><?= htmlspecialchars(strtoupper($parent['name'])) ?></th>
<?php endforeach; ?>
</tr>
<tr>
<!-- 🟢 NOUVEAU : Noms des compteurs dynamiques -->
<?php foreach ($parents as $index => $parent):
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
foreach ($parent['leave_types'] as $lt):
?>
<th colspan="2" class="<?= $parentClass ?>-sub"><?= htmlspecialchars(strtoupper($lt)) ?></th>
<?php endforeach; endforeach; ?>
</tr>
<tr>
<!-- 🟢 NOUVEAU : Sous-colonnes Av./Use dynamiques -->
<?php foreach ($parents as $index => $parent):
$parentClass = ($index % 2 === 0) ? 'col-alex' : 'col-laia';
foreach ($parent['leave_types'] as $lt):
?>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-av"><?= tr('fc_col_av') ?></th>
<th class="<?= $parentClass ?>-sub <?= $parentClass ?>-use"><?= tr('fc_col_use') ?></th>
<?php endforeach; endforeach; ?>
</tr>
</thead>
<tbody id="planningBody"></tbody>
</table>
<div id="selectionMenu" class="fc-selection-menu" style="display:none;"></div>
</div>
</section>
<section class="pf-section pf-section--bottom-panels">
<section class="pf-section pf-section--bottom-panels" style="margin-top: 1.5rem;">
<div class="fc-bottom-grid">
<div class="pf-card">
<div class="pf-card-title fc-summary-header">
<span><?= tr('fc_summary_title') ?></span>
@@ -258,7 +367,6 @@ 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>
<?php foreach ($activeCareModes as $index => $mode):
// Génération d'une couleur pseudo-aléatoire mais fixe par mode
$hue = ($index * 137) % 360;
?>
<div class="pf-legend-item">
@@ -281,11 +389,15 @@ require __DIR__ . '/header.php';
</div>
<script>
// 🟢 OBJET DE CONFIGURATION GLOBAL POUR LE JAVASCRIPT
window.FAMILY_CONFIG = {
parents: <?= json_encode($parents) ?>,
kids: <?= json_encode($kids) ?>,
activeCareModes: <?= json_encode($activeCareModes) ?>
activeCareModes: <?= json_encode($activeCareModes) ?>,
i18n: {
settings_updated: <?= json_encode(tr('fc_settings_updated')) ?>,
empty_matrix: "Aucun compteur de congés défini pour le moment.",
btn_delete: <?= json_encode(tr('btn_delete') ?? 'Supprimer') ?>
}
};
</script>
<script src="/modules/family-calendar/family-calendar.js"></script>