Files
pta/assets/js/page-bootstrap.js
2026-08-25 15:12:11 +02:00

163 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Amorçage de page — À CHARGER EN DERNIER, après core.js et tous les modules.
*
* Deux responsabilités :
* 1. appeler `init()` sur chaque module déclaré par le PageController ;
* 2. appliquer les filtres venus de l'URL (structure_id, agent_id, week, month,
* focus…), que PHP a assainis et republiés dans `window.PTA_PAGE_CONFIG`.
*
* Ce second point est ce qui rend les LIENS PROFONDS opérants : le tableau de
* bord, la file de validation et la vue annuelle renvoient tous vers un écran
* pré-positionné sur le bon lieu, le bon agent et la bonne semaine.
*
* Les initialisations sont `async` mais lancées SANS `await` en fin de fichier :
* elles concernent des écrans différents et jamais plus d'une n'agit sur une
* page donnée.
*/
(() => {
'use strict';
const PTA = window.PTA;
// core.js absent ou en erreur : rien à amorcer.
if (!PTA) return;
const page = window.PTA_PAGE_CONFIG || {};
const modules = Array.isArray(page.modules) ? page.modules : [];
const params = page.params || {};
modules.forEach((name) => PTA.modules[name]?.init?.());
/**
* Écran de saisie : positionne lieu, agent et semaine depuis l'URL.
*
* L'ordre des étapes est CONTRAINT : la liste des agents dépend du lieu, et
* la semaine ne peut être chargée qu'une fois l'agent connu — d'où les
* `await` successifs.
*/
async function initialisePlanning() {
const planning = PTA.modules.planning;
if (!planning) return;
const { structureSelect, agentSelect, weekInput, validateButton } = PTA.elements;
// Un lien profond qui désigne une semaine précise (file de validation,
// tableau de bord, vue annuelle) doit ouvrir la saisie semaine par
// semaine, et non l'éditeur de semaine type proposé par défaut.
if (params.week || params.focus) {
PTA.modules.weekTemplateEditor?.setMode?.('week');
}
if (params.structureId && structureSelect) {
structureSelect.value = String(params.structureId);
await planning.loadAgents();
if (params.structureLocked) structureSelect.disabled = true;
}
if (params.agentId && agentSelect) {
agentSelect.value = String(params.agentId);
// Depuis la V7.29, un agent dont le compte d'accès est coupé sort des
// listes d'affectation. Un lien profond qui le désigne (file de
// validation, tableau de bord, vue annuelle) ne trouve alors aucune
// option : sans ce message, l'écran resterait vide sans rien dire.
if (agentSelect.value !== String(params.agentId)) {
PTA.utils.showMessage(
'Cet agent n’est plus proposé à la saisie : son accès a été coupé. Rétablissez-le depuis l’onglet Agents pour reprendre son planning.',
'warning'
);
} else if (weekInput) {
weekInput.disabled = false;
}
}
if (params.week && weekInput) {
weekInput.disabled = !agentSelect?.value;
weekInput.value = params.week;
if (agentSelect?.value) await planning.handleWeekSelection();
}
if (params.notice) PTA.utils.showMessage(params.notice, 'info');
if (params.focus === 'validation') {
window.setTimeout(() => {
document.querySelector('#editor-view .actions-bar')?.scrollIntoView({ behavior: 'smooth', block: 'center' });
validateButton?.focus({ preventScroll: true });
}, 150);
}
}
/** Planning par lieu : pré-sélectionne le lieu et charge la semaine. */
async function initialiseStructureOverview() {
if (!params.structureId) return;
const select = document.querySelector('#overview-structure');
if (select) {
select.value = String(params.structureId);
if (params.structureLocked) select.disabled = true;
}
await PTA.modules.structureOverview?.load?.();
}
/**
* Planning par agent : pré-sélectionne l'agent et le mois.
* Le chargement n'est déclenché que si un agent est désigné ; sans agent, il
* n'y a rien à afficher.
*/
async function initialiseAgentOverview() {
if (params.agentId) {
const select = document.querySelector('#overview-agent');
if (select) {
select.value = String(params.agentId);
if (params.agentLocked) select.disabled = true;
}
}
if (params.month) {
const input = document.querySelector('#agent-overview-month');
if (input) input.value = params.month;
}
if (params.agentId) await PTA.modules.agentOverview?.load?.();
}
/** Contrôle de couverture : pré-sélectionne le lieu et rafraîchit. */
function initialiseCoverage() {
if (!params.structureId) return;
const select = document.querySelector('#coverage-structure-filter');
if (select) {
select.value = String(params.structureId);
if (params.structureLocked) select.disabled = true;
PTA.modules.coverage?.refresh?.();
}
}
/**
* Pastille « À valider » de la barre de navigation.
*
* Elle n'était alimentée que sur la page « À valider » elle-même, donc
* invisible là où elle sert : depuis n'importe quel écran, le service voit
* maintenant si des brouillons attendent. La requête est volontairement
* réduite à un compteur, et son échec est silencieux — une commodité ne
* doit jamais empêcher une page de fonctionner.
*/
async function refreshNavigationCounters() {
const badge = document.querySelector('#pending-validation-tab-badge');
if (!badge) return;
// Les écrans qui chargent déjà ce compteur s'en chargent eux-mêmes.
if (PTA.modules.pendingValidation || PTA.modules.dashboard) return;
if (!PTA.config?.permissions?.can_view_pending) return;
try {
const response = await fetch('api/dashboard_summary.php?scope=badges', {
headers: { Accept: 'application/json' },
});
if (!response.ok) return;
const data = await PTA.utils.readJsonResponse(response);
const count = Number(data?.validation?.count || 0);
badge.textContent = String(count);
badge.hidden = count === 0;
badge.setAttribute('aria-label', `${count} planning${count > 1 ? 's' : ''} en attente de validation`);
} catch (error) {
badge.hidden = true;
}
}
initialisePlanning();
initialiseStructureOverview();
initialiseAgentOverview();
initialiseCoverage();
refreshNavigationCounters();
})();