/**
* PTA détaillé d'un agent (`PTA.modules.pta`), écran pta.php.
*
* Affiche la répartition annuelle des temps d'un agent, ses contraintes
* prioritaires (médicales, temps partiel thérapeutique) et ses souhaits de
* lieux, accompagnés des contrôles réglementaires calculés par PtaModel.
*
* Les contrôles suivent la forme commune {niveau, code, message}. Aucun n'est
* bloquant ici : le PTA est un écran d'analyse, l'arbitrage revient à l'agent de
* planification.
*
* Attention à `quotaLabel()` ci-dessous : les durées arrivent sous forme
* d'OBJET et non de chaîne, piège déjà rencontré.
*/
(() => {
'use strict';
const PTA = window.PTA;
// core.js absent : la page reste lisible, simplement non interactive.
if (!PTA) return;
const { readJsonResponse, apiErrorMessage, escapeHtml, formatDuration, formatDate } = PTA.utils;
let current = null;
const el = (id) => document.getElementById(id);
const selectedAgentId = () => Number(el('pta-agent')?.value || 0);
/** Message dans le bandeau de la page. */
function show(text, type = 'info') {
const box = el('pta-message');
if (!box) return;
box.className = `message message-${type}`;
box.textContent = text;
}
/** Vignette de synthèse : libellé, valeur, précision facultative. */
function card(label, value, detail = '') {
return `${escapeHtml(label)}${escapeHtml(value)}${detail ? `${escapeHtml(detail)}` : ''}`;
}
/**
* QuotaModel::enrich() renvoie les durées sous forme d'objet
* { minutes, heures_decimales, libelle } et non de chaîne. Passer l'objet
* tel quel à une interpolation affiche « [object Object] » — et un objet
* étant toujours truthy, un `||` ne rattrape jamais le coup. On lit donc
* explicitement le libellé, en gardant le nombre de minutes comme repli.
*/
function quotaLabel(enriched, fallbackMinutes) {
return enriched?.libelle || formatDuration(Number(fallbackMinutes || 0));
}
/** Rend la synthèse : catégories de temps, compteurs et contrôles. */
function renderSummary(data) {
current = data;
const agent = data.agent || {};
const quota = data.quota || {};
const counters = data.counters || {};
el('pta-content').hidden = false;
el('pta-agent-name').textContent = `${agent.prenom || ''} ${agent.nom || ''}`.trim();
el('pta-agent-meta').textContent = [
agent.matricule,
agent.poste_libelle || 'Poste non renseigné',
agent.structure_principale_nom || 'Sans lieu principal',
agent.type_contrat === 'PERMANENT' ? 'Contrat permanent' : 'Contrat non permanent',
].filter(Boolean).join(' — ');
el('pta-summary-cards').innerHTML = [
card('Année civile PTA', `${formatDate(quota.date_debut_periode)} → ${formatDate(quota.date_fin_periode)}`),
card('Quotité', `${Number(quota.quotite_travail || 0).toLocaleString('fr-FR')} %`, `Référence : ${formatDuration(Number(quota.quota_reference_minutes || 96420))}`),
card('Quota à réaliser', quotaLabel(quota.quota_cible, quota.quota_cible_minutes)),
card('Déjà affecté', quotaLabel(quota.affectees, quota.minutes_affectees)),
card('Reste à affecter', quotaLabel(quota.restantes, quota.minutes_restantes)),
card('Formation', `${counters.formation_duree || '0 h 00'} / ${counters.formation_cible_duree || '0 h 00'}`),
card('Congés annuels', `${Number(counters.conges_annuels_jours || 0)} / ${Number(counters.conges_annuels_cible || 25)} jours`),
card('Fractionnement', `${Number(counters.jours_fractionnement || 0)} / ${Number(counters.jours_fractionnement_cible || 2)} jours`),
].join('');
el('pta-category-body').innerHTML = (data.categories || []).map((category) => `
';
}
/** Liste les souhaits de lieux ; les interdictions sont présentées en premier. */
function renderWishes(items) {
el('pta-wish-list').innerHTML = items.map((item) => `