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:
@@ -7,6 +7,7 @@ namespace App\Controllers;
|
||||
use App\Core\Access;
|
||||
use App\Core\Controller;
|
||||
use App\Core\Csrf;
|
||||
use App\Core\Security;
|
||||
use App\Models\AgentModel;
|
||||
use App\Models\MotifModel;
|
||||
use App\Models\StructureModel;
|
||||
@@ -23,6 +24,20 @@ final class PageController extends Controller
|
||||
$this->access = new Access($pdo);
|
||||
}
|
||||
|
||||
public function dashboard(): void
|
||||
{
|
||||
$this->access->requirePage('dashboard');
|
||||
$this->renderPage('dashboard', 'Tableau de bord', 'dashboard', [
|
||||
'pageSubtitle' => 'Ce qui attend le Service Enfance : plannings à valider, couverture des lieux et suivi des quotas annuels.',
|
||||
'currentWeek' => $this->weekValue($_GET['week'] ?? null) ?: $this->currentWeek(),
|
||||
'scripts' => ['dashboard.js'],
|
||||
'modules' => ['dashboard'],
|
||||
'pageConfig' => [
|
||||
'week' => $this->weekValue($_GET['week'] ?? null) ?: $this->currentWeek(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function planning(): void
|
||||
{
|
||||
$this->access->requirePage('planning');
|
||||
@@ -32,9 +47,14 @@ final class PageController extends Controller
|
||||
$modules = ['planning'];
|
||||
if (!empty($permissions['can_use_templates'])) {
|
||||
$scripts[] = 'week-templates.js';
|
||||
$scripts[] = 'week-template-editor.js';
|
||||
$modules[] = 'weekTemplates';
|
||||
$modules[] = 'weekTemplateEditor';
|
||||
}
|
||||
$this->renderPage('planning', 'Saisie du planning', 'planning', [
|
||||
'pageSubtitle' => !empty($permissions['can_use_templates'])
|
||||
? 'Composer une semaine type et la dupliquer sur une période, ou saisir une semaine en particulier.'
|
||||
: 'Choisir un lieu, un agent et une semaine, saisir les plages horaires, puis enregistrer le brouillon.',
|
||||
'structures' => $this->loadStructures(),
|
||||
'motifs' => $this->loadMotifs(),
|
||||
'currentWeek' => $this->currentWeek(),
|
||||
@@ -55,6 +75,7 @@ final class PageController extends Controller
|
||||
{
|
||||
$this->access->requirePage('pending');
|
||||
$this->renderPage('pending', 'Plannings à valider', 'pending', [
|
||||
'pageSubtitle' => 'La file des brouillons prêts à être contrôlés. Ouvrir un planning charge l’écran de saisie sur la bonne semaine.',
|
||||
'scripts' => ['pending-validation.js'],
|
||||
'modules' => ['pendingValidation'],
|
||||
]);
|
||||
@@ -65,6 +86,7 @@ final class PageController extends Controller
|
||||
$this->access->requirePage('coverage');
|
||||
$forcedStructure = $this->access->role() === Access::ROLE_RESPONSABLE ? $this->access->structureId() : null;
|
||||
$this->renderPage('coverage', 'Contrôle de couverture', 'coverage', [
|
||||
'pageSubtitle' => 'Les plages où le nombre d’agents planifiés passe sous le minimum attendu du lieu.',
|
||||
'structures' => $this->loadStructures(),
|
||||
'currentWeek' => $this->weekValue($_GET['week'] ?? null) ?: $this->currentWeek(),
|
||||
'scripts' => ['coverage.js'],
|
||||
@@ -81,6 +103,7 @@ final class PageController extends Controller
|
||||
$this->access->requirePage('structures');
|
||||
$forcedStructure = $this->access->role() !== Access::ROLE_SERVICE ? $this->access->structureId() : null;
|
||||
$this->renderPage('structures', 'Planning par lieu', 'structures', [
|
||||
'pageSubtitle' => 'Le planning d’un lieu sur une semaine : les agents rattachés et ceux qui y sont réellement planifiés. Lecture seule.',
|
||||
'structures' => $this->loadStructures(),
|
||||
'currentWeek' => $this->weekValue($_GET['week'] ?? null) ?: $this->currentWeek(),
|
||||
'scripts' => ['structure-overview.js'],
|
||||
@@ -97,6 +120,9 @@ final class PageController extends Controller
|
||||
$this->access->requirePage('agents');
|
||||
$forcedAgent = $this->access->role() === Access::ROLE_AGENT ? $this->access->agentId() : null;
|
||||
$this->renderPage('agents', $forcedAgent ? 'Mon planning' : 'Planning par agent', 'agents', [
|
||||
'pageSubtitle' => $forcedAgent
|
||||
? 'Vos horaires mois par mois, tous lieux d’affectation confondus.'
|
||||
: 'Le planning d’un agent mois par mois, tous lieux d’affectation confondus, avec le suivi de son quota.',
|
||||
'agents' => $this->loadAgents(),
|
||||
'structures' => $this->loadStructuresForAgentEditor(),
|
||||
'motifs' => $this->loadMotifs(),
|
||||
@@ -114,6 +140,7 @@ final class PageController extends Controller
|
||||
{
|
||||
$this->access->requirePage('annual');
|
||||
$this->renderPage('annual', 'Vue annuelle du PTA', 'annual', [
|
||||
'pageSubtitle' => 'L’annualisation d’un agent de janvier à décembre, et la validation de toute l’année en une fois.',
|
||||
'agents' => (new AgentModel($this->pdo))->allActive(),
|
||||
'scripts' => ['annual-overview.js'],
|
||||
'modules' => ['annualOverview'],
|
||||
@@ -128,6 +155,7 @@ final class PageController extends Controller
|
||||
{
|
||||
$this->access->requirePage('pta');
|
||||
$this->renderPage('pta', 'PTA annuel par agent', 'pta', [
|
||||
'pageSubtitle' => 'Le PTA détaillé d’un agent : souhaits de lieux, contraintes et répartition des heures.',
|
||||
'agents' => (new AgentModel($this->pdo))->allActive(),
|
||||
'structures' => (new StructureModel($this->pdo))->allActive(),
|
||||
'scripts' => ['pta.js'],
|
||||
@@ -143,6 +171,7 @@ final class PageController extends Controller
|
||||
{
|
||||
$this->access->requirePage('teams');
|
||||
$this->renderPage('teams', 'Équipes des mercredis et vacances', 'teams', [
|
||||
'pageSubtitle' => 'La composition des équipes sur les mercredis et les périodes de vacances.',
|
||||
'agents' => (new AgentModel($this->pdo))->allActive(),
|
||||
'structures' => (new StructureModel($this->pdo))->allActive(),
|
||||
'scripts' => ['teams.js'],
|
||||
@@ -158,6 +187,7 @@ final class PageController extends Controller
|
||||
{
|
||||
$this->access->requirePage('vacations');
|
||||
$this->renderPage('vacations', 'Vacances scolaires', 'vacations', [
|
||||
'pageSubtitle' => 'Les périodes de vacances qui déterminent le contexte périscolaire ou extrascolaire de chaque journée.',
|
||||
'scripts' => ['vacation-calendar.js'],
|
||||
'modules' => ['vacationCalendar'],
|
||||
]);
|
||||
@@ -167,6 +197,7 @@ final class PageController extends Controller
|
||||
{
|
||||
$this->access->requirePage('administration');
|
||||
$this->renderPage('administration', 'Administration', 'administration', [
|
||||
'pageSubtitle' => 'Les référentiels de PTA : agents, lieux d’affectation, postes et horaires de couverture attendus.',
|
||||
'agents' => (new AgentModel($this->pdo))->allActive(),
|
||||
'structures' => (new StructureModel($this->pdo))->allActive(),
|
||||
'posts' => (new AgentModel($this->pdo))->allPosts(),
|
||||
@@ -175,12 +206,32 @@ final class PageController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guide d'utilisation. Page purement statique : aucun script, aucun appel
|
||||
* API, aucune donnée métier. Elle suit malgré tout la règle des droits en
|
||||
* base — tant que la migration n'est pas jouée, la page est refusée et le
|
||||
* bouton d'accès n'apparaît pas dans la barre de navigation.
|
||||
*/
|
||||
public function faq(): void
|
||||
{
|
||||
$this->access->requirePage('faq');
|
||||
$this->renderPage('faq', 'Guide d’utilisation', 'faq', [
|
||||
'pageSubtitle' => 'Le parcours complet, du paramétrage des lieux à la validation des plannings, et les réponses aux questions les plus fréquentes.',
|
||||
]);
|
||||
}
|
||||
|
||||
private function renderPage(string $view, string $title, string $activePage, array $data = []): void
|
||||
{
|
||||
Security::sendHtmlHeaders();
|
||||
$profile = $this->access->profile();
|
||||
$this->render('pages/' . $view, array_merge([
|
||||
'pageTitle' => $title,
|
||||
// Chaque page explique en une phrase ce qu'on y fait : le bandeau
|
||||
// générique ne disait rien et obligeait à ouvrir l'écran pour
|
||||
// comprendre à quoi il servait.
|
||||
'pageSubtitle' => 'Planification annuelle, équipes, quotas et contrôles métier des accueils de loisirs.',
|
||||
'activePage' => $activePage,
|
||||
'cspNonce' => Security::nonce(),
|
||||
'csrfToken' => Csrf::ensureToken(),
|
||||
'scripts' => [],
|
||||
'modules' => [],
|
||||
|
||||
Reference in New Issue
Block a user