Ajout des commentaires dans le code
This commit is contained in:
@@ -1,7 +1,23 @@
|
||||
/**
|
||||
* Vue annuelle d'un agent (`PTA.modules.annualOverview`), écran annual.php.
|
||||
*
|
||||
* Affiche les douze mois de l'année civile et permet de valider TOUTE l'année en
|
||||
* une opération.
|
||||
*
|
||||
* PARTICULARITÉ — ce module ne calcule presque rien. Le calendrier arrive du
|
||||
* serveur entièrement préparé (classes CSS, libellés, infobulles, totaux) :
|
||||
* voir AnnualOverviewModel. Le rôle du JavaScript se limite à assembler le HTML
|
||||
* et à gérer les interactions. C'est ce qui garantit un rendu identique à
|
||||
* l'écran, à l'impression et en plein écran.
|
||||
*
|
||||
* Chaque jour est cliquable et ouvre l'écran de saisie sur la bonne semaine et
|
||||
* le bon lieu.
|
||||
*/
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
const PTA = window.PTA;
|
||||
// core.js absent : la page reste lisible, simplement non interactive.
|
||||
if (!PTA) return;
|
||||
const { readJsonResponse, apiErrorMessage, escapeHtml, formatDate } = PTA.utils;
|
||||
const el = (id) => document.getElementById(id);
|
||||
@@ -10,6 +26,7 @@
|
||||
const escapeAttr = escapeHtml;
|
||||
let current = null;
|
||||
|
||||
/** Message dans le bandeau de la page. */
|
||||
function show(text, type = 'info') {
|
||||
const box = el('annual-message');
|
||||
if (!box) return;
|
||||
@@ -17,17 +34,29 @@
|
||||
box.textContent = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Horodatage SQL « 2026-02-17 09:30:00 » → date et heure en français.
|
||||
* Le remplacement de l'espace par « T » rend la chaîne conforme à ISO 8601,
|
||||
* seule forme que tous les navigateurs analysent de la même façon.
|
||||
*/
|
||||
function formatGenerated(value) {
|
||||
const date = new Date(String(value).replace(' ', 'T'));
|
||||
return Number.isNaN(date.getTime()) ? value : date.toLocaleString('fr-FR', { dateStyle: 'short', timeStyle: 'short' });
|
||||
}
|
||||
|
||||
/** Libellé du type de contrat. */
|
||||
function formatContract(value) {
|
||||
if (value === 'PERMANENT') return 'Permanent';
|
||||
if (value === 'TEMPORAIRE') return 'Temporaire';
|
||||
return value || 'Non renseigné';
|
||||
}
|
||||
|
||||
/**
|
||||
* Lien profond d'une journée vers l'écran de saisie.
|
||||
* Le lieu retenu est celui du premier créneau du jour, à défaut le
|
||||
* rattachement de l'agent. `notice` rappelle d'où vient l'utilisateur, sans
|
||||
* quoi il arriverait sur une semaine sans savoir pourquoi.
|
||||
*/
|
||||
function buildPlanningUrl(day) {
|
||||
const agentId = Number(current?.agent?.id_agent || 0);
|
||||
const structureId = Number(day.structure_id || current?.agent?.id_structure || 0);
|
||||
@@ -38,6 +67,10 @@
|
||||
return `planning.php?${params.toString()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Une cellule du calendrier. Contenu, classe et infobulle viennent du
|
||||
* serveur ; seule la marque « brouillon » est ajoutée ici.
|
||||
*/
|
||||
function cellHtml(cell, day) {
|
||||
const content = cell.display ? escapeHtml(cell.display) : ' ';
|
||||
const title = cell.title ? ` title="${escapeAttr(cell.title)}"` : '';
|
||||
@@ -45,6 +78,7 @@
|
||||
return `<td class="annual-data-cell ${escapeHtml(cell.class || '')}${draftClass}" data-date="${escapeHtml(day.date)}"${title}>${content}</td>`;
|
||||
}
|
||||
|
||||
/** Tableau d'un mois : une ligne par jour, quatre colonnes AP/PP/AE/PE. */
|
||||
function monthHtml(month) {
|
||||
const rows = month.days.map((day) => {
|
||||
const classes = [
|
||||
@@ -80,6 +114,7 @@
|
||||
</article>`;
|
||||
}
|
||||
|
||||
/** Rappel du ou des quotas couvrant l'année affichée. */
|
||||
function quotaPeriodsHtml(periods) {
|
||||
return periods.map((period) => `
|
||||
<article class="annual-quota-chip">
|
||||
@@ -89,6 +124,7 @@
|
||||
</article>`).join('');
|
||||
}
|
||||
|
||||
/** Rend l'ensemble de la vue et mémorise les données dans `current`. */
|
||||
function render(data) {
|
||||
current = data;
|
||||
const agent = data.agent || {};
|
||||
@@ -123,6 +159,7 @@
|
||||
if (el('annual-validate-year')) el('annual-validate-year').disabled = false;
|
||||
}
|
||||
|
||||
/** Charge la vue annuelle de l'agent et de l'année sélectionnés. */
|
||||
async function load(options = {}) {
|
||||
const agentId = Number(el('annual-agent')?.value || 0);
|
||||
const year = Number(el('annual-year')?.value || 0);
|
||||
@@ -147,6 +184,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** Lien de correction d'une semaine en erreur, ouvert dans un nouvel onglet. */
|
||||
function validationPlanningUrl(planning) {
|
||||
const agentId = Number(current?.agent?.id_agent || el('annual-agent')?.value || 0);
|
||||
const week = `${Number(planning.annee)}-W${String(planning.numero_semaine).padStart(2, '0')}`;
|
||||
@@ -160,6 +198,11 @@
|
||||
return `planning.php?${params.toString()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rend l'échec de validation annuelle : AUCUNE semaine n'a été validée.
|
||||
* Chaque semaine fautive est listée avec ses erreurs et un lien direct pour
|
||||
* la corriger — c'est ce qui rend l'échec exploitable.
|
||||
*/
|
||||
function renderValidationIssues(data) {
|
||||
const container = el('annual-validation-result');
|
||||
if (!container) return;
|
||||
@@ -188,6 +231,7 @@
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/** Rend l'avertissement de quota dépassé, en attente de confirmation. */
|
||||
function renderValidationWarning(data) {
|
||||
const container = el('annual-validation-result');
|
||||
if (!container) return;
|
||||
@@ -198,6 +242,7 @@
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/** Rend le compte rendu d'une validation annuelle réussie. */
|
||||
function renderValidationSuccess(data) {
|
||||
const container = el('annual-validation-result');
|
||||
if (!container) return;
|
||||
@@ -208,6 +253,17 @@
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lance la validation de l'année entière.
|
||||
*
|
||||
* Vérifie d'abord que la vue affichée correspond bien à l'agent et à l'année
|
||||
* sélectionnés : sans ce contrôle, changer le sélecteur sans recharger
|
||||
* validerait une année différente de celle qu'on regarde.
|
||||
*
|
||||
* Trois issues, alignées sur AnnualOverviewController::validateYear() :
|
||||
* 422 erreurs, 409 quota dépassé (rappel avec `forceQuota = true` après
|
||||
* confirmation), 200 validé.
|
||||
*/
|
||||
async function validateWholeYear(forceQuota = false) {
|
||||
const agentId = Number(el('annual-agent')?.value || 0);
|
||||
const year = Number(el('annual-year')?.value || 0);
|
||||
@@ -266,12 +322,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clic sur une ligne du calendrier : suit le lien porté par `data-url`.
|
||||
* Délégation sur le conteneur, le calendrier étant redessiné à chaque
|
||||
* chargement.
|
||||
*/
|
||||
function handleCalendarClick(event) {
|
||||
const row = event.target.closest('tr[data-url]');
|
||||
if (!row) return;
|
||||
window.location.href = row.dataset.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bascule le calendrier en plein écran — utile sur douze mois affichés d'un
|
||||
* coup. L'API Fullscreen peut être refusée (navigateur, iframe, réglages) :
|
||||
* l'échec est signalé sans conséquence pour le reste de la page.
|
||||
*/
|
||||
async function toggleFullscreen() {
|
||||
const target = el('annual-content');
|
||||
if (!target) return;
|
||||
|
||||
Reference in New Issue
Block a user