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>
122 lines
5.3 KiB
PHP
122 lines
5.3 KiB
PHP
<?php
|
||
/** @var string $csrfToken */
|
||
/** @var array $agents */
|
||
/** @var array $structures */
|
||
/** @var string $error */
|
||
/** @var array|null $currentProfile */
|
||
/** @var string $cspNonce */
|
||
?>
|
||
<!doctype html>
|
||
<html lang="fr">
|
||
<head>
|
||
<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.10">
|
||
</head>
|
||
<body class="role-page-body">
|
||
<main class="role-page-shell">
|
||
<section class="role-intro">
|
||
<p class="eyebrow">PTA</p>
|
||
<h1>Quel est votre rôle ?</h1>
|
||
<p>Votre choix détermine les pages visibles et les actions autorisées pendant cette session.</p>
|
||
<?php if ($currentProfile): ?>
|
||
<div class="role-current-profile">
|
||
Profil actuel : <strong><?= htmlspecialchars((string) $currentProfile['role_label']) ?></strong>
|
||
— <?= htmlspecialchars((string) $currentProfile['label']) ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if ($error !== ''): ?>
|
||
<div class="message message-error"><?= htmlspecialchars($error) ?></div>
|
||
<?php endif; ?>
|
||
</section>
|
||
|
||
<form method="post" class="role-selection-form" id="role-selection-form">
|
||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
|
||
|
||
<div class="role-choice-grid">
|
||
<label class="role-choice-card">
|
||
<input type="radio" name="role" value="AGENT" required>
|
||
<span class="role-choice-content">
|
||
<strong>Agent</strong>
|
||
<small>Lecture de mon planning et du planning de mon lieu de rattachement.</small>
|
||
</span>
|
||
</label>
|
||
|
||
<label class="role-choice-card">
|
||
<input type="radio" name="role" value="RESPONSABLE_STRUCTURE" required>
|
||
<span class="role-choice-content">
|
||
<strong>Responsable de structure</strong>
|
||
<small>Saisie et modification des horaires et motifs de mon lieu, uniquement en brouillon.</small>
|
||
</span>
|
||
</label>
|
||
|
||
<label class="role-choice-card">
|
||
<input type="radio" name="role" value="SERVICE_ENFANCE" required>
|
||
<span class="role-choice-content">
|
||
<strong>Service Enfance</strong>
|
||
<small>Contrôle complet, prévisionnel N+1, administration et validation des plannings.</small>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div id="agent-context" class="role-context-card" hidden>
|
||
<label class="field">
|
||
<span>Je suis l’agent</span>
|
||
<select name="agent_id" id="role-agent-select">
|
||
<option value="">Choisir mon identité</option>
|
||
<?php foreach ($agents as $agent): ?>
|
||
<option value="<?= (int) $agent['id_agent'] ?>">
|
||
<?= htmlspecialchars($agent['prenom'] . ' ' . $agent['nom'] . ' (' . $agent['matricule'] . ')') ?>
|
||
<?= !empty($agent['structure_nom']) ? ' — ' . htmlspecialchars((string) $agent['structure_nom']) : '' ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<div id="responsable-context" class="role-context-card" hidden>
|
||
<label class="field">
|
||
<span>Je suis responsable du lieu</span>
|
||
<select name="structure_id" id="role-structure-select">
|
||
<option value="">Choisir le lieu d’affectation</option>
|
||
<?php foreach ($structures as $structure): ?>
|
||
<option value="<?= (int) $structure['id_structure'] ?>">
|
||
<?= htmlspecialchars((string) $structure['nom']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="role-form-actions">
|
||
<button type="submit" class="button button-primary">Accéder à PTA</button>
|
||
</div>
|
||
</form>
|
||
|
||
<aside class="role-security-note">
|
||
<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 nonce="<?= htmlspecialchars($cspNonce, ENT_QUOTES) ?>">
|
||
(() => {
|
||
const agentContext = document.querySelector('#agent-context');
|
||
const responsableContext = document.querySelector('#responsable-context');
|
||
const agentSelect = document.querySelector('#role-agent-select');
|
||
const structureSelect = document.querySelector('#role-structure-select');
|
||
|
||
function refresh() {
|
||
const role = document.querySelector('input[name="role"]:checked')?.value || '';
|
||
agentContext.hidden = role !== 'AGENT';
|
||
responsableContext.hidden = role !== 'RESPONSABLE_STRUCTURE';
|
||
agentSelect.required = role === 'AGENT';
|
||
structureSelect.required = role === 'RESPONSABLE_STRUCTURE';
|
||
}
|
||
|
||
document.querySelectorAll('input[name="role"]').forEach((input) => input.addEventListener('change', refresh));
|
||
refresh();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|