Files
pta/app/Views/layouts/header.php
2026-08-25 15:12:11 +02:00

165 lines
7.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* En-tête HTML commun à toutes les pages : <head>, bandeau et barre de navigation.
*
* LA NAVIGATION EST DÉFINIE À DEUX ENDROITS, à tenir cohérents :
* - $navigation ci-dessous, qui associe une clé de page à son URL et son libellé ;
* - acces_role_page en base, qui décide des pages RÉELLEMENT autorisées.
* Une page absente de $navigation n'apparaîtra jamais, même autorisée en base ;
* une page absente de la base n'apparaîtra pas non plus, même déclarée ici.
*
* $navigationGroups n'est qu'un regroupement d'affichage : une page oubliée
* dans les groupes reste atteignable via le groupe « Autres » (voir plus bas).
*
* VERSION DES ASSETS : le `?v=` de la feuille de style est à incrémenter après
* toute modification de CSS ou de JS, ICI, dans layouts/footer.php ET dans
* Views/pages/role.php, qui porte son propre <head>. Sans cela, nginx
* (expires 7d) et les navigateurs continuent de servir l'ancienne version.
*/
/** @var string $pageTitle */
/** @var string $pageSubtitle */
/** @var string $activePage */
/** @var array $allowedPages */
/** @var array $accessProfile */
/** @var string $csrfToken */
$isAgent = ($accessProfile['role'] ?? '') === 'AGENT';
// Service Enfance et DSI ouvrent leur session avec un mot de passe (V7.12) :
// eux seuls ont quelque chose à changer. La liste des rôles concernés vit en
// base (v_acces_compte.mot_de_passe_requis) ; elle est recopiée ici pour un
// simple affichage, jamais pour décider d'un droit.
$peutChangerMotDePasse = in_array($accessProfile['role'] ?? '', ['SERVICE_ENFANCE', 'DSI'], true);
$navigation = [
'dashboard' => ['dashboard.php', 'Tableau de bord'],
'planning' => ['planning.php', 'Saisie'],
'pending' => ['pending.php', 'À valider'],
'coverage' => ['coverage.php', 'Couverture'],
'structures' => ['structures.php', 'Par lieu'],
'agents' => ['agents.php', $isAgent ? 'Mon planning' : 'Par agent'],
'annual' => ['annual.php', 'Vue annuelle'],
'pta' => ['pta.php', 'PTA détaillé'],
'teams' => ['teams.php', 'Équipes'],
'vacations' => ['vacations.php', 'Vacances'],
'manage_agents' => ['manage_agents.php', 'Agents'],
'manage_structures' => ['manage_structures.php', 'Lieux d’affectation'],
'administration' => ['administration.php', 'Administration'],
'dsi' => ['dsi.php', 'Accès & journaux'],
];
/**
* Les onze onglets du Service Enfance étaient alignés à plat, sans hiérarchie :
* rien ne distinguait une tâche quotidienne d'un référentiel modifié deux fois
* par an. Ils sont désormais regroupés par intention. Les rôles qui n'ont que
* quelques pages gardent une barre simple, sans titres de groupe.
*/
$navigationGroups = [
'Piloter' => ['dashboard', 'pending', 'coverage'],
'Planifier' => ['planning', 'teams'],
'Consulter' => ['agents', 'structures', 'annual', 'pta'],
// « Management » regroupe l'administration des personnes et des lieux : ce
// qu'on crée et corrige au fil de l'eau, à distinguer des paramètres qu'on
// règle une fois pour l'année.
'Management' => ['manage_agents', 'manage_structures'],
'Paramétrer' => ['vacations', 'administration', 'dsi'],
];
$visibleGroups = [];
$grouped = [];
foreach ($navigationGroups as $groupLabel => $keys) {
$visibleKeys = array_values(array_filter(
$keys,
static fn (string $key): bool => in_array($key, $allowedPages, true) && isset($navigation[$key])
));
if ($visibleKeys !== []) {
$visibleGroups[$groupLabel] = $visibleKeys;
$grouped = array_merge($grouped, $visibleKeys);
}
}
// Filet de sécurité : une page autorisée en base mais oubliée dans les groupes
// ci-dessus reste accessible plutôt que de disparaître de la navigation.
$ungrouped = array_values(array_filter(
$allowedPages,
static fn (string $key): bool => isset($navigation[$key]) && !in_array($key, $grouped, true)
));
if ($ungrouped !== []) {
$visibleGroups['Autres'] = $ungrouped;
}
$visiblePageCount = count($grouped) + count($ungrouped);
$showGroupLabels = $visiblePageCount > 4;
/**
* Le guide n'appartient à aucun groupe d'intention : ce n'est pas une étape du
* travail mais un secours permanent. Il est volontairement absent de
* $navigation — il ne doit apparaître qu'une seule fois, ancré à droite de la
* barre, et jamais repêché par le filet « Autres ».
*/
$showHelpTab = in_array('faq', $allowedPages, true);
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= htmlspecialchars($pageTitle) ?> — PTA</title>
<link rel="stylesheet" href="assets/style.css?v=7.29">
</head>
<body>
<main class="app-shell">
<header class="page-header">
<div class="page-header-identity">
<p class="eyebrow">PTA</p>
<h1><?= htmlspecialchars($pageTitle) ?></h1>
<p class="subtitle"><?= htmlspecialchars($pageSubtitle ?? '') ?></p>
</div>
<div class="header-actions">
<?php if ($activePage === 'planning'): ?>
<div id="planning-status" class="status-badge status-neutral">Nouveau planning</div>
<?php endif; ?>
<div class="access-profile-badge">
<span><?= htmlspecialchars((string) ($accessProfile['role_label'] ?? '')) ?></span>
<strong><?= htmlspecialchars((string) ($accessProfile['label'] ?? '')) ?></strong>
<?php if (!empty($accessProfile['structure_name']) && $isAgent): ?>
<small><?= htmlspecialchars((string) $accessProfile['structure_name']) ?></small>
<?php endif; ?>
</div>
<?php if ($peutChangerMotDePasse): ?>
<a class="button button-ghost switch-role-link" href="role.php?action=mot_de_passe">Mot de passe</a>
<?php endif; ?>
<a class="button button-ghost switch-role-link" href="role.php?action=reset&amp;csrf_token=<?= htmlspecialchars(urlencode($csrfToken), ENT_QUOTES) ?>">Se déconnecter</a>
</div>
</header>
<?php if (!empty($_GET['access_denied'])): ?>
<div class="message message-warning role-access-warning">Cette page n'est pas disponible avec votre rôle actuel.</div>
<?php endif; ?>
<nav class="view-tabs<?= $showGroupLabels ? ' view-tabs-grouped' : '' ?>" aria-label="Navigation principale">
<?php foreach ($visibleGroups as $groupLabel => $keys): ?>
<div class="view-tab-group" role="group"<?= $showGroupLabels ? ' aria-label="' . htmlspecialchars($groupLabel, ENT_QUOTES) . '"' : '' ?>>
<?php if ($showGroupLabels): ?>
<span class="view-tab-group-label"><?= htmlspecialchars($groupLabel) ?></span>
<?php endif; ?>
<div class="view-tab-group-items">
<?php foreach ($keys as $key): ?>
<?php [$href, $label] = $navigation[$key]; ?>
<a class="view-tab<?= $activePage === $key ? ' is-active' : '' ?>" href="<?= htmlspecialchars($href) ?>"<?= $activePage === $key ? ' aria-current="page"' : '' ?>>
<?= htmlspecialchars($label) ?>
<?php if ($key === 'pending'): ?><span id="pending-validation-tab-badge" class="nav-count-badge" hidden>0</span><?php endif; ?>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
<?php if ($showHelpTab): ?>
<div class="view-tab-help">
<a class="view-tab view-tab-faq<?= $activePage === 'faq' ? ' is-active' : '' ?>" href="faq.php"<?= $activePage === 'faq' ? ' aria-current="page"' : '' ?>>
<span class="view-tab-faq-mark" aria-hidden="true">?</span>
FAQ
</a>
</div>
<?php endif; ?>
</nav>