V7.10 — Tableau de bord, guide, semaine type et enveloppe de formation

Reprise dans le répertoire de production du travail mené dans le worktree
ux-service-enfance :

- tableau de bord Service Enfance (dashboard.php) et navigation regroupée ;
- guide d'utilisation (faq.php) accessible depuis toute la navigation ;
- éditeur de semaine type mis en avant sur l'écran de saisie ;
- droit à l'enveloppe de formation par agent, en remplacement de la case
  « formation déjà prévue dans la répartition annuelle » ;
- correctif de « [object Object] » sur les cartes de quota du PTA ;
- motif de travail par défaut à la saisie, heures travaillées complètes
  dans les PDF.

Le docker-compose.yml de production est conservé : celui du worktree décrit
une pile de test (conteneurs et volume suffixés « test », ports 9080/9081),
qui aurait fait redémarrer l'application sur un volume MariaDB vide.

Les migrations database/migration_v7_9*.sql sont obligatoires ; le service
db-migrate les applique au déploiement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
PTA
2026-08-17 16:53:04 +02:00
parent 57bd8da5c8
commit 4201894e28
69 changed files with 5228 additions and 246 deletions

View File

@@ -6,9 +6,10 @@
/** @var array $pageConfig */
/** @var array $accessProfile */
/** @var array $permissions */
/** @var string $cspNonce */
?>
</main>
<script>
<script nonce="<?= htmlspecialchars($cspNonce, ENT_QUOTES) ?>">
window.PTA_CONFIG = {
csrfToken: <?= json_encode($csrfToken, JSON_THROW_ON_ERROR) ?>,
access: <?= json_encode($accessProfile, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE) ?>,
@@ -27,10 +28,10 @@ window.PTA_PAGE_CONFIG = <?= json_encode([
'params' => $pageConfig,
], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE) ?>;
</script>
<script src="assets/js/core.js?v=7.7"></script>
<script src="assets/js/core.js?v=7.16"></script>
<?php foreach ($scripts as $script): ?>
<script src="assets/js/<?= htmlspecialchars($script) ?>?v=7.7"></script>
<script src="assets/js/<?= htmlspecialchars($script) ?>?v=7.16"></script>
<?php endforeach; ?>
<script src="assets/js/page-bootstrap.js?v=7.7"></script>
<script src="assets/js/page-bootstrap.js?v=7.16"></script>
</body>
</html>

View File

@@ -1,21 +1,73 @@
<?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', ($accessProfile['role'] ?? '') === 'AGENT' ? 'Mon planning' : 'Par agent'],
'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;
/**
* 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">
@@ -23,15 +75,15 @@ $navigation = [
<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.7">
<link rel="stylesheet" href="assets/style.css?v=7.16">
</head>
<body>
<main class="app-shell">
<header class="page-header">
<div>
<div class="page-header-identity">
<p class="eyebrow">PTA</p>
<h1><?= htmlspecialchars($pageTitle) ?></h1>
<p class="subtitle">Planification annuelle, équipes, quotas et contrôles métier des accueils de loisirs.</p>
<p class="subtitle"><?= htmlspecialchars($pageSubtitle ?? '') ?></p>
</div>
<div class="header-actions">
<?php if ($activePage === 'planning'): ?>
@@ -40,11 +92,11 @@ $navigation = [
<div class="access-profile-badge">
<span><?= htmlspecialchars((string) ($accessProfile['role_label'] ?? '')) ?></span>
<strong><?= htmlspecialchars((string) ($accessProfile['label'] ?? '')) ?></strong>
<?php if (!empty($accessProfile['structure_name']) && ($accessProfile['role'] ?? '') === 'AGENT'): ?>
<?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">Changer de rôle</a>
<a class="button button-ghost switch-role-link" href="role.php?action=reset&amp;csrf_token=<?= htmlspecialchars(urlencode($csrfToken), ENT_QUOTES) ?>">Changer de rôle</a>
</div>
</header>
@@ -52,12 +104,29 @@ $navigation = [
<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" aria-label="Navigation principale">
<?php foreach ($navigation as $key => [$href, $label]): ?>
<?php if (!in_array($key, $allowedPages, true)) continue; ?>
<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>
<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>

View File

@@ -0,0 +1,4 @@
<?php
require dirname(__DIR__) . '/layouts/header.php';
require dirname(__DIR__) . '/partials/dashboard.php';
require dirname(__DIR__) . '/layouts/footer.php';

4
app/Views/pages/faq.php Normal file
View File

@@ -0,0 +1,4 @@
<?php
require dirname(__DIR__) . '/layouts/header.php';
require dirname(__DIR__) . '/partials/faq.php';
require dirname(__DIR__) . '/layouts/footer.php';

View File

@@ -4,6 +4,7 @@
/** @var array $structures */
/** @var string $error */
/** @var array|null $currentProfile */
/** @var string $cspNonce */
?>
<!doctype html>
<html lang="fr">
@@ -11,7 +12,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Choisir votre accès — PTA</title>
<link rel="stylesheet" href="assets/style.css?v=7.4">
<link rel="stylesheet" href="assets/style.css?v=7.16">
</head>
<body class="role-page-body">
<main class="role-page-shell">
@@ -97,7 +98,7 @@
<strong>Version de démonstration :</strong> ce sélecteur organise les droits dans l’application, mais ne remplace pas une authentification nominative. En production, le rôle devra être associé au compte connecté.
</aside>
</main>
<script>
<script nonce="<?= htmlspecialchars($cspNonce, ENT_QUOTES) ?>">
(() => {
const agentContext = document.querySelector('#agent-context');
const responsableContext = document.querySelector('#responsable-context');

View File

@@ -123,8 +123,8 @@
<input id="new-agent-contract-end" name="date_fin_contrat" type="date">
</label>
<label class="check-field admin-field-wide">
<input id="new-agent-training-planned" type="checkbox">
<span>Une formation est déjà prévue dans la répartition annuelle : ne pas ajouter l’enveloppe complémentaire de 14 h</span>
<input id="new-agent-training-right" type="checkbox" checked>
<span>Droit à l’enveloppe de formation de 14 h. Décoché, le motif « Formation » ne pourra pas être affecté à cet agent lors de la saisie des horaires.</span>
</label>
<label class="field admin-field-wide">
<span>Observations utiles à la construction du PTA</span>
@@ -242,7 +242,7 @@
data-date-fin-contrat="<?= htmlspecialchars((string) ($agent['date_fin_contrat'] ?? ''), ENT_QUOTES) ?>"
data-id-poste="<?= (int) ($agent['id_poste'] ?? 0) ?>"
data-type-contrat="<?= htmlspecialchars((string) ($agent['type_contrat'] ?? 'PERMANENT'), ENT_QUOTES) ?>"
data-formation-repartition-annuelle="<?= !empty($agent['formation_repartition_annuelle']) ? '1' : '0' ?>"
data-droit-enveloppe-formation="<?= !isset($agent['droit_enveloppe_formation']) || !empty($agent['droit_enveloppe_formation']) ? '1' : '0' ?>"
data-commentaire-pta="<?= htmlspecialchars((string) ($agent['commentaire_pta'] ?? ''), ENT_QUOTES) ?>"
data-structure-id="<?= (int) ($agent['id_structure'] ?? 0) ?>"
>
@@ -326,8 +326,8 @@
<input id="edit-agent-profile-contract-end" type="date">
</label>
<label class="check-field admin-field-wide">
<input id="edit-agent-profile-training-planned" type="checkbox">
<span>Formation déjà intégrée dans la répartition annuelle</span>
<input id="edit-agent-profile-training-right" type="checkbox">
<span>Droit à l’enveloppe de formation de 14 h</span>
</label>
<label class="field admin-field-wide">
<span>Observations PTA</span>

View File

@@ -0,0 +1,154 @@
<?php
/** @var string $currentWeek */
?>
<section id="dashboard-view" class="app-view page-content dashboard-page">
<section class="card dashboard-context-card">
<div class="section-heading">
<div>
<h2>Semaine de travail</h2>
<p class="section-subtitle" id="dashboard-week-label">Chargement de la semaine en cours…</p>
</div>
<div class="dashboard-context-actions">
<label class="field dashboard-week-field">
<span>Semaine analysée</span>
<input id="dashboard-week" type="week" value="<?= htmlspecialchars($currentWeek) ?>">
</label>
<button id="dashboard-refresh" class="button button-secondary" type="button">Actualiser</button>
</div>
</div>
<p class="dashboard-context-note" id="dashboard-week-context" hidden></p>
</section>
<div id="dashboard-message" class="message" role="status" aria-live="polite"></div>
<div id="dashboard-loading" class="empty-state" hidden>Consolidation des indicateurs…</div>
<div class="dashboard-tiles" aria-live="polite">
<a class="dashboard-tile dashboard-tile-action" id="dashboard-tile-pending" href="pending.php">
<span class="dashboard-tile-label">Plannings à valider</span>
<strong class="dashboard-tile-value" id="dashboard-pending-count">—</strong>
<small class="dashboard-tile-detail" id="dashboard-pending-detail">Brouillons contenant des affectations</small>
<span class="dashboard-tile-cta">Ouvrir la file de validation</span>
</a>
<a class="dashboard-tile dashboard-tile-action" id="dashboard-tile-coverage" href="coverage.php">
<span class="dashboard-tile-label">Manques de couverture</span>
<strong class="dashboard-tile-value" id="dashboard-coverage-count">—</strong>
<small class="dashboard-tile-detail" id="dashboard-coverage-detail">Sur la semaine analysée</small>
<span class="dashboard-tile-cta">Voir le détail des plages</span>
</a>
<a class="dashboard-tile dashboard-tile-action" id="dashboard-tile-quota" href="annual.php">
<span class="dashboard-tile-label">Quotas dépassés</span>
<strong class="dashboard-tile-value" id="dashboard-quota-count">—</strong>
<small class="dashboard-tile-detail" id="dashboard-quota-detail">Agents au-delà de leur quota annuel</small>
<span class="dashboard-tile-cta">Ouvrir la vue annuelle</span>
</a>
<a class="dashboard-tile dashboard-tile-action" id="dashboard-tile-setup" href="administration.php">
<span class="dashboard-tile-label">Lieux à paramétrer</span>
<strong class="dashboard-tile-value" id="dashboard-setup-count">—</strong>
<small class="dashboard-tile-detail" id="dashboard-setup-detail">Sans horaires de couverture attendus</small>
<span class="dashboard-tile-cta">Ouvrir l’administration</span>
</a>
</div>
<div class="dashboard-columns">
<section class="card dashboard-list-card">
<div class="section-heading">
<div>
<h2>À valider en priorité</h2>
<p class="section-subtitle">Les brouillons dont la semaine est la plus ancienne.</p>
</div>
<a class="button button-secondary" href="pending.php">Tout voir</a>
</div>
<div id="dashboard-pending-empty" class="empty-state" hidden>Aucun planning n’attend de validation.</div>
<ul class="dashboard-list" id="dashboard-pending-list"></ul>
</section>
<section class="card dashboard-list-card">
<div class="section-heading">
<div>
<h2>Couverture à renforcer</h2>
<p class="section-subtitle">Les plages les plus déficitaires de la semaine analysée.</p>
</div>
<a class="button button-secondary" id="dashboard-coverage-link" href="coverage.php">Tout voir</a>
</div>
<div id="dashboard-coverage-empty" class="empty-state" hidden>Aucun manque de couverture sur cette semaine.</div>
<ul class="dashboard-list" id="dashboard-coverage-list"></ul>
<div id="dashboard-coverage-unconfigured" class="dashboard-inline-note" hidden></div>
</section>
</div>
<section class="card dashboard-quota-card">
<div class="section-heading">
<div>
<h2>Suivi des quotas annuels</h2>
<p class="section-subtitle" id="dashboard-quota-subtitle">Heures affectées, validées et brouillon comprises, sur l’année civile.</p>
</div>
<a class="button button-secondary" href="annual.php">Vue annuelle détaillée</a>
</div>
<div class="dashboard-quota-summary">
<article class="summary-card">
<span>Agents suivis</span>
<strong id="dashboard-quota-agents">—</strong>
<small>actifs</small>
</article>
<article class="summary-card">
<span>Sans aucune heure</span>
<strong id="dashboard-quota-empty">—</strong>
<small>agent(s) non planifié(s)</small>
</article>
</div>
<div id="dashboard-quota-empty-state" class="empty-state" hidden>Aucun agent actif à suivre.</div>
<div class="dashboard-quota-table-wrap">
<table class="dashboard-quota-table">
<thead>
<tr>
<th>Agent</th>
<th>Lieu de rattachement</th>
<th>Quota annuel</th>
<th>Affecté</th>
<th>Consommation</th>
<th></th>
</tr>
</thead>
<tbody id="dashboard-quota-body"></tbody>
</table>
</div>
</section>
<section class="card dashboard-shortcuts-card">
<div class="section-heading">
<div>
<h2>Actions fréquentes</h2>
<p class="section-subtitle">Les écrans les plus utilisés, accessibles en un clic.</p>
</div>
</div>
<div class="dashboard-shortcuts">
<a class="dashboard-shortcut" href="planning.php">
<strong>Saisir un planning</strong>
<small>Un agent, une semaine, un lieu.</small>
</a>
<a class="dashboard-shortcut" href="structures.php">
<strong>Consulter un lieu</strong>
<small>Qui travaille où cette semaine.</small>
</a>
<a class="dashboard-shortcut" href="teams.php">
<strong>Composer une équipe</strong>
<small>Mercredis et vacances scolaires.</small>
</a>
<a class="dashboard-shortcut" href="vacations.php">
<strong>Mettre à jour les vacances</strong>
<small>Périodes scolaires de référence.</small>
</a>
<a class="dashboard-shortcut" href="pta.php">
<strong>Ouvrir un PTA détaillé</strong>
<small>Souhaits, contraintes et répartition.</small>
</a>
<a class="dashboard-shortcut" href="administration.php">
<strong>Gérer les référentiels</strong>
<small>Agents, lieux, postes, couverture.</small>
</a>
</div>
</section>
</section>

412
app/Views/partials/faq.php Normal file
View File

@@ -0,0 +1,412 @@
<?php
/** @var array $accessProfile */
/** @var array $allowedPages */
$roleActuel = (string) ($accessProfile['role'] ?? '');
/**
* Le guide décrit l'application entière, quel que soit le rôle : un
* responsable de structure doit pouvoir comprendre ce que fait le Service
* Enfance après lui. Chaque section indique donc explicitement qui en a le
* droit, plutôt que de masquer les étapes inaccessibles.
*/
$sommaire = [
'faq-parcours' => 'Le parcours en un coup d’œil',
'faq-roles' => 'Qui fait quoi : les trois rôles',
'faq-lieux' => '1. Ajouter un lieu d’affectation',
'faq-agents' => '2. Ajouter un agent',
'faq-couverture' => '3. Définir les horaires d’ouverture',
'faq-vacances' => '4. Renseigner les vacances scolaires',
'faq-saisie' => '5. Saisir un planning pour un agent',
'faq-validation' => '6. Contrôler et valider un planning',
'faq-equipes' => '7. Composer les équipes',
'faq-suivi' => '8. Suivre l’année et éditer les PDF',
'faq-quota' => 'Comprendre le quota annuel et les motifs',
'faq-questions' => 'Questions fréquentes',
];
?>
<section class="page-content faq-page">
<div class="faq-layout">
<nav class="card faq-summary" aria-label="Sommaire du guide">
<p class="faq-summary-title">Sommaire</p>
<ol class="faq-summary-list">
<?php foreach ($sommaire as $ancre => $libelle): ?>
<li><a href="#<?= htmlspecialchars($ancre) ?>"><?= htmlspecialchars($libelle) ?></a></li>
<?php endforeach; ?>
</ol>
<p class="faq-summary-note">
Vous êtes connecté en tant que
<strong><?= htmlspecialchars((string) ($accessProfile['role_label'] ?? 'rôle non sélectionné')) ?></strong>.
Les étapes réservées à un autre rôle restent décrites ici, mais leurs écrans ne vous sont pas proposés.
</p>
</nav>
<div class="faq-sections">
<article class="card faq-section" id="faq-parcours">
<div class="section-heading">
<div>
<h2>Le parcours en un coup d’œil</h2>
<p class="section-subtitle">PTA sert à répartir, sur toute l’année civile, les heures dues par chaque agent des accueils de loisirs. Le paramétrage se fait une fois, la saisie se répète chaque semaine.</p>
</div>
</div>
<ol class="faq-flow">
<li><span class="faq-flow-step">1</span><strong>Lieux d’affectation</strong><small>Les crèches, écoles et centres où travaillent les agents.</small></li>
<li><span class="faq-flow-step">2</span><strong>Agents</strong><small>Identité, poste, quotité de travail et lieu principal.</small></li>
<li><span class="faq-flow-step">3</span><strong>Horaires d’ouverture</strong><small>Les plages où une présence minimale est obligatoire.</small></li>
<li><span class="faq-flow-step">4</span><strong>Vacances scolaires</strong><small>Elles distinguent le périscolaire de l’extrascolaire.</small></li>
<li><span class="faq-flow-step">5</span><strong>Saisie des plannings</strong><small>Semaine par semaine, agent par agent, en brouillon.</small></li>
<li><span class="faq-flow-step">6</span><strong>Contrôle et validation</strong><small>Le Service Enfance valide et fige la semaine.</small></li>
<li><span class="faq-flow-step">7</span><strong>Équipes</strong><small>Mercredis et vacances, avec contrôle de l’encadrement.</small></li>
<li><span class="faq-flow-step">8</span><strong>Suivi annuel</strong><small>Quotas, couverture, PTA détaillé et PDF.</small></li>
</ol>
<p class="hint">Les étapes 1 à 4 ne se font qu’une fois, puis à la marge (nouvel agent, nouveau lieu, nouvelle année scolaire). Le travail courant, ce sont les étapes 5 et 6.</p>
</article>
<article class="card faq-section" id="faq-roles">
<div class="section-heading">
<div>
<h2>Qui fait quoi : les trois rôles</h2>
<p class="section-subtitle">Votre rôle détermine les onglets visibles et les actions autorisées. Il se choisit à l’ouverture de l’application et se change à tout moment par le bouton « Changer de rôle », en haut à droite.</p>
</div>
</div>
<div class="table-scroll">
<table class="planning-table faq-table">
<thead>
<tr>
<th>Rôle</th>
<th>Ce qu’il voit</th>
<th>Ce qu’il peut faire</th>
</tr>
</thead>
<tbody>
<tr<?= $roleActuel === 'AGENT' ? ' class="faq-row-current"' : '' ?>>
<td><strong>Agent</strong></td>
<td>Son propre planning et celui de son lieu de rattachement.</td>
<td>Lecture seule. Aucune modification, aucune validation.</td>
</tr>
<tr<?= $roleActuel === 'RESPONSABLE_STRUCTURE' ? ' class="faq-row-current"' : '' ?>>
<td><strong>Responsable de structure</strong></td>
<td>Son lieu : la saisie, les agents qui y sont planifiés, la couverture.</td>
<td>Saisir et corriger les horaires et motifs de son lieu, <strong>en brouillon uniquement</strong>.</td>
</tr>
<tr<?= $roleActuel === 'SERVICE_ENFANCE' ? ' class="faq-row-current"' : '' ?>>
<td><strong>Service Enfance</strong></td>
<td>Tous les lieux, tous les agents, tous les écrans.</td>
<td>Paramétrer, saisir, composer les équipes, <strong>valider</strong> et rouvrir les plannings.</td>
</tr>
</tbody>
</table>
</div>
<p class="hint">Un planning validé n’est plus modifiable par un responsable de structure : il faut demander au Service Enfance de le rouvrir, ce qui le repasse en brouillon.</p>
</article>
<article class="card faq-section" id="faq-lieux">
<div class="section-heading">
<div>
<h2>1. Ajouter un lieu d’affectation</h2>
<p class="section-subtitle">Onglet <strong>Administration</strong> — réservé au Service Enfance. Un lieu doit exister avant qu’un agent puisse y être rattaché ou planifié.</p>
</div>
</div>
<ol class="faq-steps">
<li>Ouvrez <strong>Administration</strong>, encadré « Ajouter un lieu d’affectation ».</li>
<li>Saisissez le <strong>code</strong> : un identifiant court et stable, sans espace, par exemple <code>CRECHE_MATUSALEME</code>. Il ne s’affiche que dans les tableaux techniques.</li>
<li>Saisissez le <strong>nom</strong> tel qu’il doit apparaître partout ailleurs, par exemple « Crèche Matusalème ».</li>
<li>Choisissez le <strong>type d’affectation</strong> : <em>Périscolaire</em> (autour du temps scolaire) ou <em>Extrascolaire</em> (mercredis et vacances). Ce choix appartient au lieu, pas à l’agent.</li>
<li>L’<strong>adresse</strong> est facultative et sert uniquement d’information.</li>
<li>Cliquez sur <strong>Ajouter le lieu</strong>. Il devient immédiatement sélectionnable dans tous les écrans.</li>
</ol>
<div class="message message-info faq-callout">
Le type d’affectation reste modifiable après coup dans le tableau « Paramètres des lieux d’affectation », juste en dessous du formulaire : choisissez la nouvelle valeur puis cliquez sur <strong>Enregistrer</strong> sur la ligne concernée.
</div>
</article>
<article class="card faq-section" id="faq-agents">
<div class="section-heading">
<div>
<h2>2. Ajouter un agent</h2>
<p class="section-subtitle">Onglet <strong>Administration</strong> — réservé au Service Enfance. La fiche agent détermine son quota annuel et les motifs qu’on pourra lui affecter.</p>
</div>
</div>
<ol class="faq-steps">
<li><strong>Matricule, nom, prénom</strong> : l’identité de l’agent. Le matricule doit être unique.</li>
<li><strong>Poste PTA</strong> : la fonction occupée. Elle sert notamment à repérer les responsables dans les équipes.</li>
<li><strong>Type de contrat</strong> : <em>Permanent</em> (soumis au PTA) ou <em>Temporaire</em> (hors périmètre PTA, planifiable mais sans annualisation).</li>
<li><strong>Lieu d’affectation principal</strong> : le rattachement par défaut. Ce n’est pas une exclusivité — l’agent pourra être planifié sur d’autres lieux la même semaine.</li>
<li><strong>Quotité de travail</strong>, en pourcentage. C’est elle qui proratise le quota annuel : 100 % = 1 607 h, 80 % = 1 285 h 36, etc.</li>
<li><strong>Dates de contrat</strong> : information RH. Attention, la date de début <em>ne décale pas</em> l’année de référence, qui reste l’année civile complète.</li>
<li><strong>Qualification et diplôme</strong> : le champ « Diplôme » ne s’active que si l’agent est déclaré diplômé. Cette information alimente le contrôle du taux de diplômés dans les équipes.</li>
<li><strong>Droit à l’enveloppe de formation de 14 h</strong> : coché par défaut. Décoché, le motif « Formation » ne sera pas proposé pour cet agent lors de la saisie.</li>
<li><strong>Observations utiles à la construction du PTA</strong> : disponibilités particulières, organisation connue… Ces notes se retrouvent sur l’écran « PTA détaillé ».</li>
<li>Cliquez sur <strong>Ajouter l’agent</strong>.</li>
</ol>
<p class="hint">Pour corriger une fiche existante, utilisez le tableau « Informations des agents » en bas de la page : le bouton <strong>Modifier</strong> ouvre la fiche complète, lieu principal compris.</p>
</article>
<article class="card faq-section" id="faq-couverture">
<div class="section-heading">
<div>
<h2>3. Définir les horaires d’ouverture</h2>
<p class="section-subtitle">Onglet <strong>Administration</strong>, encadré « Horaires de couverture des lieux ». Ces plages décrivent quand le lieu doit être tenu, et par combien d’agents au minimum.</p>
</div>
</div>
<ol class="faq-steps">
<li>Choisissez le <strong>lieu d’affectation</strong> puis cliquez sur <strong>Charger</strong>.</li>
<li>L’éditeur affiche une section par jour, du <strong>lundi au vendredi</strong>.</li>
<li>Sur un jour, cliquez sur <strong>+ Ajouter une plage</strong>, puis renseignez l’heure de début, l’heure de fin et le <strong>nombre minimum d’agents</strong> attendus sur cette plage.</li>
<li>Répétez pour chaque plage d’ouverture réelle : par exemple 07:30–08:30 avec 2 agents, puis 11:30–13:30 avec 4 agents, puis 16:30–18:30 avec 3 agents.</li>
<li>Cliquez sur <strong>Enregistrer les horaires de couverture</strong>.</li>
</ol>
<div class="message message-info faq-callout">
Seules les affectations portant le motif <strong>« Heure de travail »</strong> comptent comme une présence sur ces plages. Une formation, un congé ou une absence ne couvrent pas le lieu — c’est le principe même du contrôle.
</div>
<p class="hint">Tant qu’un lieu n’a aucune plage configurée, il apparaît comme « non configuré » dans l’onglet <strong>Couverture</strong> : l’application ne peut alors rien contrôler pour lui, et le silence ne veut pas dire que tout va bien.</p>
</article>
<article class="card faq-section" id="faq-vacances">
<div class="section-heading">
<div>
<h2>4. Renseigner les vacances scolaires</h2>
<p class="section-subtitle">Onglet <strong>Vacances</strong> — réservé au Service Enfance. Ces périodes déterminent si une journée relève du périscolaire ou de l’extrascolaire.</p>
</div>
</div>
<ol class="faq-steps">
<li>Indiquez l’<strong>année civile</strong> souhaitée et lancez la recherche : PTA interroge l’API publique du ministère de l’Éducation nationale et agrège les deux années scolaires concernées.</li>
<li>Contrôlez les <strong>dates proposées</strong>. Elles restent modifiables : corrigez ce qui doit l’être avant d’enregistrer.</li>
<li><strong>Cochez uniquement</strong> les périodes à conserver, puis enregistrez.</li>
<li>Si une période manque ou doit être adaptée aux besoins du service, utilisez le formulaire <strong>« Ajouter une période manuellement »</strong>.</li>
<li>Le tableau <strong>« Périodes enregistrées »</strong> est la référence réellement utilisée par l’application : c’est lui qui fait foi, pas la proposition de l’API.</li>
</ol>
<p class="hint">Cette étape est à refaire à chaque nouvelle année civile. Sans période enregistrée, PTA considère toutes les journées comme périscolaires.</p>
</article>
<article class="card faq-section" id="faq-saisie">
<div class="section-heading">
<div>
<h2>5. Saisir un planning pour un agent</h2>
<p class="section-subtitle">Onglet <strong>Saisie</strong> — Service Enfance et responsables de structure. Un planning, c’est <strong>un agent × une semaine × un lieu</strong>.</p>
</div>
</div>
<ol class="faq-steps">
<li><strong>Sélection du planning.</strong> Choisissez le lieu, puis l’agent, puis la semaine. Les listes se débloquent dans cet ordre. Un responsable de structure a son lieu déjà imposé.</li>
<li><strong>Lisez le bandeau de quota</strong> qui apparaît : quotité de l’agent, quota de la période, heures déjà affectées (validées et brouillons confondus) et reste à affecter.</li>
<li><strong>Saisissez les affectations.</strong> Le tableau propose une ligne par jour, du lundi au vendredi. Sur chaque jour, renseignez une ou plusieurs plages horaires, chacune avec son propre <strong>motif</strong>. Les heures se saisissent par pas de 15 minutes.</li>
<li>Cliquez sur <strong>Appliquer les horaires renseignés</strong> : les plages basculent dans le planning de la semaine.</li>
<li><strong>Vérifiez le planning global de l’agent</strong>, en dessous. Il montre <em>toutes</em> ses affectations de la semaine, y compris celles posées sur d’autres lieux. Le total des heures décomptées s’affiche à droite.</li>
<li>Pour corriger, cliquez sur un créneau pour le <strong>déplacer ou le dupliquer</strong>, ou faites-le glisser directement vers un autre jour.</li>
<li>Cliquez sur <strong>Enregistrer le brouillon</strong>. Le planning est conservé au statut <strong>BROUILLON</strong> et reste modifiable.</li>
</ol>
<div class="message message-info faq-callout">
Un même agent peut être planifié sur plusieurs lieux la même semaine. En revanche, deux créneaux ne peuvent jamais se chevaucher : une plage déjà posée ailleurs apparaît dans le planning global et bloque toute saisie qui l’empiéterait.
</div>
<h3>Gagner du temps avec les semaines types</h3>
<p>Quand une semaine se répète à l’identique, le Service Enfance peut l’enregistrer puis la rejouer :</p>
<ul class="faq-list">
<li><strong>Enregistrer comme semaine type</strong> : mémorise la semaine affichée sous un nom.</li>
<li><strong>Importer une semaine type</strong> : la rejoue sur la semaine en cours de saisie.</li>
<li><strong>Appliquer sur une période</strong> : la rejoue sur plusieurs semaines d’un coup. Un aperçu annonce les conflits avant d’écrire quoi que ce soit — le mode « Compléter » refuse d’écraser, le mode « Remplacer » supprime les créneaux existants des jours concernés.</li>
</ul>
</article>
<article class="card faq-section" id="faq-validation">
<div class="section-heading">
<div>
<h2>6. Contrôler et valider un planning</h2>
<p class="section-subtitle">Onglets <strong>À valider</strong> et <strong>Saisie</strong> — la validation est réservée au Service Enfance.</p>
</div>
</div>
<ol class="faq-steps">
<li>Ouvrez <strong>À valider</strong> : la file de tous les brouillons contenant des affectations.</li>
<li>Cliquez sur un planning : l’écran de <strong>Saisie</strong> s’ouvre sur le bon agent et la bonne semaine, positionné sur la zone de validation.</li>
<li>Contrôlez les horaires, puis cliquez sur <strong>Valider le planning</strong>.</li>
</ol>
<p>La validation applique quatre contrôles bloquants et une alerte :</p>
<div class="table-scroll">
<table class="planning-table faq-table">
<thead>
<tr>
<th>Niveau</th>
<th>Contrôle</th>
<th>Conséquence</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="faq-level faq-level-error">Erreur</span></td>
<td>Le planning ne contient aucune affectation.</td>
<td rowspan="4">La validation est <strong>refusée</strong>. Corrigez puis recommencez.</td>
</tr>
<tr>
<td><span class="faq-level faq-level-error">Erreur</span></td>
<td>Une affectation est en dehors de la semaine sélectionnée.</td>
</tr>
<tr>
<td><span class="faq-level faq-level-error">Erreur</span></td>
<td>Deux affectations du planning se chevauchent.</td>
</tr>
<tr>
<td><span class="faq-level faq-level-error">Erreur</span></td>
<td>Une affectation chevauche un créneau déjà validé sur un autre lieu.</td>
</tr>
<tr>
<td><span class="faq-level faq-level-warning">Alerte</span></td>
<td>Le quota annuel de l’agent est dépassé.</td>
<td>Une <strong>confirmation explicite</strong> est demandée. Le dépassement est possible, mais il doit être assumé.</td>
</tr>
</tbody>
</table>
</div>
<p class="hint">Une fois validé, le planning est figé : le bouton <strong>Modifier le planning</strong> le rouvre et le repasse en brouillon, ce qui impose une nouvelle validation. Modifier un créneau validé depuis l’onglet « Par agent » produit exactement le même effet, automatiquement.</p>
</article>
<article class="card faq-section" id="faq-equipes">
<div class="section-heading">
<div>
<h2>7. Composer les équipes</h2>
<p class="section-subtitle">Onglet <strong>Équipes</strong> — réservé au Service Enfance. Une équipe couvre une période (mercredis, vacances) sur un lieu, et vérifie que l’encadrement est réglementaire.</p>
</div>
</div>
<p>Une équipe est indépendante des plannings hebdomadaires : elle répond à la question « qui encadre, sur cette période, et est-ce suffisant ? ».</p>
<ol class="faq-steps">
<li><strong>Nommez l’équipe</strong> de façon parlante, par exemple « Vacances d’hiver — Équipe Matusalème ».</li>
<li>Choisissez son <strong>type</strong> : <em>Mercredi périscolaire</em>, <em>Extrascolaire</em> ou <em>Périscolaire semaine</em>. Un même agent peut appartenir à plusieurs types d’équipes dans l’année.</li>
<li>Choisissez le <strong>lieu</strong>, puis les <strong>dates de début et de fin</strong> de la période couverte.</li>
<li>Renseignez l’<strong>effectif d’enfants</strong> attendu, séparé en moins de 6 ans et 6 ans et plus.</li>
<li>Ajustez les <strong>ratios d’encadrement</strong> : par défaut 1 agent pour 8 enfants de moins de 6 ans, et 1 pour 12 au-delà. PTA en déduit le nombre d’agents requis.</li>
<li>Fixez le <strong>minimum d’agents</strong> et le <strong>pourcentage minimum de diplômés</strong> (50 % par défaut).</li>
<li>Créez l’équipe, puis <strong>ajoutez-y les agents</strong> depuis la liste « Équipes enregistrées ».</li>
</ol>
<p>À chaque modification, PTA recalcule ses contrôles :</p>
<ul class="faq-list">
<li><span class="faq-level faq-level-error">Erreur</span> <strong>Encadrement insuffisant</strong> — moins d’agents affectés que requis par les ratios et le minimum.</li>
<li><span class="faq-level faq-level-error">Erreur</span> <strong>Qualification insuffisante</strong> — le taux de diplômés est sous le seuil paramétré.</li>
<li><span class="faq-level faq-level-warning">Alerte</span> <strong>Responsable manquant</strong> — aucun agent de l’équipe n’occupe un poste de responsable.</li>
<li><span class="faq-level faq-level-warning">Alerte</span> <strong>Contrainte prioritaire</strong> — un agent a une préconisation médicale ou un temps partiel thérapeutique actif sur la période.</li>
<li><span class="faq-level faq-level-info">Info</span> <strong>Préférence respectée</strong> — un agent avait exprimé un souhait pour ce lieu dans son PTA détaillé.</li>
</ul>
<p class="hint">L’équipe passe ensuite de <strong>Brouillon</strong> à <strong>À contrôler</strong> puis <strong>Validée</strong>. Les contraintes prioritaires et les souhaits de lieu se saisissent dans l’onglet <strong>PTA détaillé</strong> de chaque agent.</p>
</article>
<article class="card faq-section" id="faq-suivi">
<div class="section-heading">
<div>
<h2>8. Suivre l’année et éditer les PDF</h2>
<p class="section-subtitle">Les écrans de consultation ne modifient rien : ils servent à contrôler, comparer et imprimer.</p>
</div>
</div>
<div class="table-scroll">
<table class="planning-table faq-table">
<thead>
<tr>
<th>Onglet</th>
<th>À quoi il sert</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Tableau de bord</strong></td>
<td>Le point d’entrée du Service Enfance : brouillons les plus anciens à valider, plages de couverture déficitaires et suivi des quotas annuels.</td>
</tr>
<tr>
<td><strong>Couverture</strong></td>
<td>Les plages où le nombre d’agents en « Heure de travail » passe sous le minimum attendu du lieu, et les lieux encore non configurés.</td>
</tr>
<tr>
<td><strong>Par lieu</strong></td>
<td>Le planning d’un lieu sur une semaine : agents rattachés et agents réellement planifiés. Lecture seule.</td>
</tr>
<tr>
<td><strong>Par agent</strong></td>
<td>Le planning d’un agent mois par mois, tous lieux confondus, avec son quota. C’est ici qu’on corrige un créneau isolé ou qu’on duplique une semaine.</td>
</tr>
<tr>
<td><strong>Vue annuelle</strong></td>
<td>L’annualisation d’un agent de janvier à décembre, et la validation de toute l’année en une seule fois.</td>
</tr>
<tr>
<td><strong>PTA détaillé</strong></td>
<td>La fiche annuelle complète : répartition des heures, congés et JNT, contrôles métier, contraintes prioritaires, préférences et interdictions de lieu.</td>
</tr>
</tbody>
</table>
</div>
<h3>Les documents imprimables</h3>
<ul class="faq-list">
<li><strong>PDF de l’agent (7 semaines)</strong>, depuis l’écran de saisie : le planning détaillé sur sept semaines à partir de la semaine affichée.</li>
<li><strong>PDF du lieu</strong>, depuis la vue par lieu : la semaine complète d’un lieu, tous agents confondus.</li>
<li><strong>Récapitulatif horaire et contrat</strong>, depuis la fiche agent : les heures travaillées et le suivi du quota annuel.</li>
</ul>
</article>
<article class="card faq-section" id="faq-quota">
<div class="section-heading">
<div>
<h2>Comprendre le quota annuel et les motifs</h2>
<p class="section-subtitle">C’est la mécanique centrale de l’application : tout le reste sert à la nourrir.</p>
</div>
</div>
<ul class="faq-list">
<li>Le quota suit l’<strong>année civile</strong>, du 1<sup>er</sup> janvier au 31 décembre — jamais l’année scolaire, jamais la date de contrat.</li>
<li>La référence est de <strong>1 607 heures</strong> à 100 %, <strong>proratisée par la quotité</strong> de l’agent.</li>
<li>Les heures « déjà affectées » comptent <strong>les brouillons comme les plannings validés</strong> : le compteur ne ment pas en attendant la validation.</li>
<li>Chaque plage horaire porte un <strong>motif</strong>, et c’est le motif qui décide si les heures sont décomptées du quota.</li>
</ul>
<p>Trois motifs ne sont <strong>pas</strong> décomptés du quota :</p>
<div class="table-scroll">
<table class="planning-table faq-table">
<thead>
<tr>
<th>Motif</th>
<th>Décompté du quota ?</th>
</tr>
</thead>
<tbody>
<tr><td>Heure de travail, ALP matin, Restauration, ALP soir, Mercredi périscolaire, Temps extrascolaire</td><td><strong>Oui</strong></td></tr>
<tr><td>Préparation (périscolaire, extrascolaire, du lundi), Ménage de fond</td><td><strong>Oui</strong></td></tr>
<tr><td>Formation, Journée de fractionnement, Absence</td><td><strong>Oui</strong></td></tr>
<tr><td>Congé annuel</td><td>Non</td></tr>
<tr><td>Autre absence</td><td>Non</td></tr>
<tr><td>Journée non travaillée (JNT)</td><td>Non</td></tr>
</tbody>
</table>
</div>
<p class="hint">Le motif « Formation » n’est proposé que pour les agents disposant du droit à l’enveloppe de formation de 14 h, coché sur leur fiche.</p>
</article>
<article class="card faq-section" id="faq-questions">
<div class="section-heading">
<div>
<h2>Questions fréquentes</h2>
</div>
</div>
<dl class="faq-qa">
<dt>Je ne vois pas l’onglet dont on me parle.</dt>
<dd>Les onglets dépendent du rôle sélectionné. Vérifiez le badge en haut à droite et, si nécessaire, utilisez « Changer de rôle ». Si l’onglet reste absent, votre rôle n’y a pas droit.</dd>
<dt>Impossible de choisir un agent dans l’écran de saisie.</dt>
<dd>Il faut d’abord choisir un lieu d’affectation : la liste des agents en dépend. La semaine ne se débloque qu’une fois l’agent choisi.</dd>
<dt>L’application refuse ma saisie pour cause de chevauchement.</dt>
<dd>L’agent a déjà une affectation sur ce créneau, éventuellement <strong>sur un autre lieu</strong>. Regardez le « Planning global de l’agent » : il affiche toutes ses affectations de la semaine, tous lieux confondus.</dd>
<dt>Le quota est dépassé, que faire ?</dt>
<dd>C’est une alerte, pas une erreur. Vous pouvez confirmer la validation en connaissance de cause, ou retirer des heures. Le dépassement reste visible dans le suivi des quotas.</dd>
<dt>Comment corriger un planning déjà validé ?</dt>
<dd>Seul le Service Enfance peut le rouvrir : bouton <strong>Modifier le planning</strong> dans l’écran de saisie. Le planning repasse en brouillon et devra être validé à nouveau. Toute modification d’un créneau validé depuis « Par agent » déclenche la même bascule.</dd>
<dt>Un agent doit travailler sur deux lieux la même semaine.</dt>
<dd>C’est prévu. Le lieu principal de la fiche agent n’est qu’un rattachement par défaut : saisissez simplement un planning sur chacun des lieux, tant que les horaires ne se chevauchent pas.</dd>
<dt>L’onglet Couverture ne signale rien pour un de mes lieux.</dt>
<dd>Ce lieu n’a probablement aucune plage d’ouverture configurée. Sans plage attendue, l’application n’a rien à comparer. Renseignez-les dans <strong>Administration</strong> → « Horaires de couverture des lieux ».</dd>
<dt>Les vacances scolaires affichées sont fausses.</dt>
<dd>Les dates proposées par l’API restent modifiables avant enregistrement, et le formulaire manuel permet d’ajouter ou de corriger une période. Seul le tableau « Périodes enregistrées » est utilisé par l’application.</dd>
<dt>Mes modifications n’apparaissent pas après enregistrement.</dt>
<dd>Rechargez la page avec <kbd>Ctrl</kbd> + <kbd>F5</kbd>. Si le problème persiste, un message d’erreur rouge s’affiche normalement sous le formulaire concerné : signalez son contenu à l’administrateur de l’application.</dd>
</dl>
</article>
</div>
</div>
</section>

View File

@@ -1,3 +1,10 @@
<?php
// Les rôles sans droit aux semaines types n'ont qu'un seul mode de saisie :
// le sélecteur de méthode disparaît et la numérotation des étapes se resserre.
$usesTemplates = !empty($permissions['can_use_templates']);
$etapeSaisie = $usesTemplates ? 3 : 2;
$etapePlanning = $usesTemplates ? 4 : 3;
?>
<section id="editor-view" class="app-view page-content">
<?php if (($accessProfile['role'] ?? '') === 'RESPONSABLE_STRUCTURE'): ?>
<div class="message message-info role-page-notice">
@@ -33,6 +40,83 @@
</div>
</section>
<?php if ($usesTemplates): ?>
<section class="card editor-mode-card">
<div class="section-heading">
<div>
<h2>2. Choisir la méthode de saisie</h2>
<p class="section-subtitle">Une semaine type se compose une fois puis se duplique sur toute une période. La saisie semaine par semaine reste disponible pour les corrections.</p>
</div>
</div>
<div class="editor-mode-choices" role="tablist" aria-label="Méthode de saisie">
<button id="editor-mode-template" class="editor-mode-choice is-active" type="button"
role="tab" aria-selected="true" aria-controls="template-mode-panel">
<span class="editor-mode-choice-badge">Le plus rapide</span>
<strong>Semaine type</strong>
<small>Composer une semaine de référence, puis la dupliquer sur une période entière.</small>
</button>
<button id="editor-mode-week" class="editor-mode-choice" type="button"
role="tab" aria-selected="false" aria-controls="week-mode-panel">
<strong>Semaine précise</strong>
<small>Saisir ou corriger une seule semaine, jour par jour.</small>
</button>
</div>
</section>
<div id="template-mode-panel" class="editor-mode-panel" role="tabpanel" aria-labelledby="editor-mode-template">
<section class="card template-editor-card">
<div class="section-heading">
<div>
<h2>Éditeur de semaine type</h2>
<p class="section-subtitle">Les plages saisies ici ne sont pas encore planifiées : elles décrivent une semaine de référence, réutilisable autant de fois que nécessaire.</p>
</div>
<div class="totals template-editor-total">
<span>Total de la semaine type</span>
<strong id="template-editor-total">0 h 00</strong>
<small id="template-editor-total-detail">dont 0 h 00 décomptées</small>
</div>
</div>
<div class="template-editor-toolbar">
<label class="field">
<span>Semaine type de l’agent</span>
<select id="template-editor-select" disabled>
<option value="">Nouvelle semaine type</option>
</select>
</label>
<label class="field">
<span>Nom de la semaine type <strong>*</strong></span>
<input id="template-editor-name" type="text" maxlength="120" placeholder="Ex. Semaine scolaire classique" disabled>
</label>
<div class="template-editor-toolbar-actions">
<button id="template-editor-delete" class="button button-danger" type="button" disabled>Supprimer</button>
</div>
</div>
<div id="template-editor-empty" class="empty-state">Choisissez un lieu d’affectation et un agent pour composer sa semaine type.</div>
<div id="template-editor-grid" class="template-editor-grid" hidden></div>
<div id="template-editor-message" class="message" role="status" aria-live="polite"></div>
<div class="template-editor-actions">
<button id="template-editor-save" class="button button-primary" type="button" disabled>
Enregistrer la semaine type
</button>
<button id="template-editor-apply-period" class="button button-success" type="button" disabled>
Dupliquer sur une période…
</button>
<button id="template-editor-apply-week" class="button button-secondary" type="button" disabled>
Appliquer à la semaine sélectionnée…
</button>
</div>
<p class="hint">Enregistrer une semaine type ne modifie aucun planning. Rien n’est planifié tant que vous ne l’avez pas dupliquée sur une période ou appliquée à une semaine.</p>
</section>
</div>
<?php endif; ?>
<div id="week-mode-panel" class="editor-mode-panel"<?= $usesTemplates ? ' hidden' : '' ?>>
<section class="quota-strip" id="editor-quota" hidden>
<article class="quota-card">
<span>Quotité</span>
@@ -57,7 +141,7 @@
<section class="card" id="entry-card" aria-disabled="true">
<div class="section-heading">
<div>
<h2>2. Saisir ou modifier les affectations</h2>
<h2><?= $etapeSaisie ?>. Saisir ou modifier les affectations</h2>
<p class="section-subtitle">Chaque plage horaire possède son propre motif et sa propre règle de décompte du quota annuel.</p>
</div>
</div>
@@ -92,7 +176,7 @@
<section class="card">
<div class="section-heading">
<div>
<h2>3. Planning global de l’agent</h2>
<h2><?= $etapePlanning ?>. Planning global de l’agent</h2>
<p id="week-label" class="section-subtitle">Toutes les affectations de l’agent sur la semaine, quel que soit le lieu d’affectation. Cliquez sur un créneau pour le déplacer ou le dupliquer, ou glissez-le directement vers un autre jour.</p>
</div>
<div class="planning-summary-actions">
@@ -133,6 +217,8 @@
<?php endif; ?>
</div>
</section>
</div><!-- /#week-mode-panel -->
</section>

View File

@@ -10,7 +10,7 @@ $defaultCalendarYear = $currentYear;
<div class="section-heading">
<div>
<h2>Vacances scolaires</h2>
<p class="section-subtitle">Consultez toutes les vacances d’une année civile complète, de janvier à décembre. PTA agrège les deux années scolaires concernées, accepte les périodes publiées pour les élèves ou pour tous les publics, puis vous laisse contrôler et enregistrer vous-même les dates souhaitées.</p>
<p class="section-subtitle">Consultez toutes les vacances d'une année civile complète, de janvier à décembre. PTA agrège les deux années scolaires concernées, accepte les périodes publiées pour les élèves ou pour tous les publics, puis vous laisse contrôler et enregistrer vous-même les dates souhaitées.</p>
</div>
</div>
@@ -21,7 +21,7 @@ $defaultCalendarYear = $currentYear;
<div class="selection-grid vacation-filters">
<label class="field">
<span>Académie</span>
<input id="vacation-academy" type="text" maxlength="100" value="Orléans-Tours" placeholder="Ex. Orléans-Tours" list="vacation-academies" autocomplete="off">
<input id="vacation-academy" type="text" maxlength="100" value="Dijon" placeholder="Ex. Dijon" list="vacation-academies" autocomplete="off">
<datalist id="vacation-academies">
<option value="Aix-Marseille"><option value="Amiens"><option value="Besançon"><option value="Bordeaux">
<option value="Clermont-Ferrand"><option value="Créteil"><option value="Dijon"><option value="Grenoble">
@@ -45,8 +45,8 @@ $defaultCalendarYear = $currentYear;
<div id="vacation-preview-panel" class="vacation-preview-panel" hidden>
<div class="section-heading compact-heading">
<div>
<h3>Dates proposées par l’API</h3>
<p class="section-subtitle">Toutes les périodes de l’année civile sont proposées, y compris celles rattachées à deux années scolaires différentes. Cochez uniquement celles que vous souhaitez conserver ; les dates restent modifiables avant l’enregistrement.</p>
<h3>Dates proposées par l'API</h3>
<p class="section-subtitle">Toutes les périodes de l'année civile sont proposées, y compris celles rattachées à deux années scolaires différentes. Cochez uniquement celles que vous souhaitez conserver ; les dates restent modifiables avant l’enregistrement.</p>
</div>
<label class="vacation-select-all">
<input id="vacation-select-all" type="checkbox">