La liste des motifs d'une nouvelle plage s'ouvrait sur un placeholder vide « Choisir un motif », alors que le temps de travail est le cas très majoritaire : elle propose désormais « Heure de travail » (code TRAVAIL), avec repli sur le premier motif décomptant le quota si le référentiel ne contient pas ce code. Côté PDF, seul le code générique TRAVAIL était traité comme du temps travaillé. Les motifs ALP matin, ALP soir, restauration, mercredi périscolaire, extrascolaire, préparations et ménage de fond tombaient donc : - dans un total invisible du bilan annuel (ligne « Heures travaillées » à 0 h 00 alors que les heures étaient bien décomptées plus bas) ; - dans la couleur grise « Autre absence » des plannings agent et lieu. La classification est centralisée dans App\Core\MotifCategories, réutilisée par PtaModel (qui portait déjà la même liste) et par les deux services PDF. Un motif inconnu du référentiel est rattaché au temps de travail dès lors qu'il décompte le quota, pour qu'aucun total ne puisse disparaître d'un document. La ligne « Heures travaillées » détaille en outre les motifs regroupés, et le total décompté suit maintenant le drapeau compte_dans_quota comme QuotaModel : il additionnait auparavant les congés, hors quota, en contradiction avec sa propre note de bas de tableau. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
117 lines
5.1 KiB
PHP
117 lines
5.1 KiB
PHP
<?php
|
||
/** @var string $pageTitle */
|
||
/** @var string $pageSubtitle */
|
||
/** @var string $activePage */
|
||
/** @var array $allowedPages */
|
||
/** @var array $accessProfile */
|
||
/** @var string $csrfToken */
|
||
|
||
$isAgent = ($accessProfile['role'] ?? '') === 'AGENT';
|
||
|
||
$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'],
|
||
'administration' => ['administration.php', 'Administration'],
|
||
];
|
||
|
||
/**
|
||
* 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'],
|
||
'Paramétrer' => ['vacations', 'administration'],
|
||
];
|
||
|
||
$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;
|
||
?>
|
||
<!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.10">
|
||
</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>
|
||
<a class="button button-ghost switch-role-link" href="role.php?action=reset&csrf_token=<?= htmlspecialchars(urlencode($csrfToken), ENT_QUOTES) ?>">Changer de rôle</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; ?>
|
||
</nav>
|