579 lines
28 KiB
JavaScript
579 lines
28 KiB
JavaScript
/**
|
||
* Écran d'administration des référentiels (`PTA.modules.administration`) :
|
||
* agents, lieux d'affectation, postes et horaires de couverture.
|
||
*
|
||
* PRINCIPE DE MISE À JOUR — la page ne se recharge JAMAIS après une création ou
|
||
* une modification. Les nouveaux éléments sont insérés à la main dans TOUS les
|
||
* sélecteurs et tableaux concernés, d'où les fonctions `add*Everywhere()`. Un
|
||
* lieu créé ici doit apparaître immédiatement dans les listes de l'écran de
|
||
* saisie, de la vue par lieu, du formulaire agent et des règles de couverture.
|
||
*
|
||
* CONSÉQUENCE POUR LA MAINTENANCE : ajouter un sélecteur de lieu ou d'agent
|
||
* ailleurs dans l'application impose de l'inscrire dans `addStructureEverywhere()`
|
||
* ou `addAgentEverywhere()`, faute de quoi il restera périmé jusqu'au prochain
|
||
* rechargement complet de la page.
|
||
*
|
||
* Cet écran charge aussi le module `coverage`, les règles de couverture étant
|
||
* un référentiel de lieu.
|
||
*/
|
||
(() => {
|
||
'use strict';
|
||
|
||
const PTA = window.PTA;
|
||
if (!PTA) throw new Error('PTA core doit être chargé avant administration.js');
|
||
|
||
const { structureSelect } = PTA.elements;
|
||
const {
|
||
escapeHtml,
|
||
readJsonResponse,
|
||
apiErrorMessage,
|
||
formatDuration,
|
||
} = PTA.utils;
|
||
|
||
const typeLabel = (type) => type === 'EXTRASCOLAIRE' ? 'Extrascolaire' : 'Périscolaire';
|
||
|
||
/**
|
||
* Enregistre le lieu de rattachement principal d'un agent depuis sa ligne de
|
||
* tableau. Un lieu vide est valide : il détache l'agent, qui reste
|
||
* planifiable ponctuellement ailleurs.
|
||
*/
|
||
async function saveAgentStructure(button) {
|
||
const row = button.closest('tr[data-agent-id]');
|
||
const select = row?.querySelector('.agent-structure-select');
|
||
const message = document.querySelector('#assignment-message');
|
||
if (!row || !select || !message) return;
|
||
|
||
button.disabled = true;
|
||
message.className = 'message';
|
||
message.textContent = '';
|
||
|
||
try {
|
||
const response = await fetch('api/agent_assignments.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
agent_id: Number(row.dataset.agentId),
|
||
structure_id: select.value ? Number(select.value) : null,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de modifier le lieu principal de l’agent.'));
|
||
|
||
message.className = 'message message-success';
|
||
message.textContent = data.message;
|
||
|
||
if (structureSelect?.value) await PTA.modules.planning?.loadAgents?.();
|
||
if (document.querySelector('#overview-structure')?.value) await PTA.modules.structureOverview?.load?.();
|
||
if (document.querySelector('#overview-agent')?.value) await PTA.modules.agentOverview?.load?.();
|
||
} catch (error) {
|
||
message.className = 'message message-error';
|
||
message.textContent = error.message;
|
||
} finally {
|
||
button.disabled = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Enregistre le type d'un lieu, puis répercute le nouveau libellé dans TOUS
|
||
* les sélecteurs de la page — le type fait partie du texte affiché.
|
||
*/
|
||
async function saveStructureType(button) {
|
||
const row = button.closest('tr[data-structure-id]');
|
||
const select = row?.querySelector('.structure-type-select');
|
||
const message = document.querySelector('#structure-settings-message');
|
||
if (!row || !select || !message) return;
|
||
|
||
button.disabled = true;
|
||
message.className = 'message';
|
||
message.textContent = '';
|
||
|
||
try {
|
||
const response = await fetch('api/update_structure.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
structure_id: Number(row.dataset.structureId),
|
||
type_affectation: select.value,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de modifier le type du lieu.'));
|
||
|
||
updateStructureLabels(Number(row.dataset.structureId), select.value);
|
||
message.className = 'message message-success';
|
||
message.textContent = data.message;
|
||
|
||
if (structureSelect?.value) await PTA.modules.planning?.loadAgents?.();
|
||
if (document.querySelector('#overview-structure')?.value === String(row.dataset.structureId)) {
|
||
await PTA.modules.structureOverview?.load?.();
|
||
}
|
||
if (document.querySelector('#overview-agent')?.value) await PTA.modules.agentOverview?.load?.();
|
||
} catch (error) {
|
||
message.className = 'message message-error';
|
||
message.textContent = error.message;
|
||
} finally {
|
||
button.disabled = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Ajoute une option à un `<select>`, ou met à jour son libellé si elle
|
||
* existe déjà. Idempotent : appelable sans risque de doublon.
|
||
*/
|
||
function addOptionIfMissing(select, value, label, selected = false) {
|
||
if (!select) return;
|
||
let option = Array.from(select.options).find((item) => item.value === String(value));
|
||
if (!option) {
|
||
option = document.createElement('option');
|
||
option.value = String(value);
|
||
select.appendChild(option);
|
||
}
|
||
option.textContent = label;
|
||
if (selected) option.selected = true;
|
||
}
|
||
|
||
/** Libellé unifié d'un lieu : « Nom — Type », identique partout. */
|
||
function structureOptionLabel(structure) {
|
||
return `${structure.nom} — ${typeLabel(structure.type_affectation)}`;
|
||
}
|
||
|
||
/**
|
||
* Insère un lieu nouvellement créé dans TOUS les sélecteurs de la page.
|
||
*
|
||
* La liste des sélecteurs est écrite en dur : tout nouvel écran ou modale
|
||
* proposant un choix de lieu doit y être ajouté, sinon il ne verra pas les
|
||
* lieux créés dans la session courante.
|
||
*/
|
||
function addStructureEverywhere(structure) {
|
||
const id = Number(structure.id_structure);
|
||
const label = structureOptionLabel(structure);
|
||
|
||
[
|
||
document.querySelector('#structure'),
|
||
document.querySelector('#overview-structure'),
|
||
document.querySelector('#new-agent-structure'),
|
||
document.querySelector('#edit-agent-entry-structure'),
|
||
document.querySelector('#edit-agent-profile-structure'),
|
||
document.querySelector('#coverage-structure-filter'),
|
||
document.querySelector('#coverage-rules-structure'),
|
||
].forEach((select) => addOptionIfMissing(select, id, label));
|
||
|
||
document.querySelectorAll('.agent-structure-select').forEach((select) => {
|
||
addOptionIfMissing(select, id, label);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Met à jour le libellé d'un lieu dans tous les `<select>` de la page après
|
||
* un changement de type. Parcourt l'ensemble des sélecteurs plutôt qu'une
|
||
* liste nommée : le libellé peut apparaître n'importe où.
|
||
*/
|
||
function updateStructureLabels(structureId, type) {
|
||
const source = document.querySelector(`#structure-settings-body tr[data-structure-id="${Number(structureId)}"]`);
|
||
const structureName = source?.querySelector('td strong')?.textContent?.trim();
|
||
if (!structureName) return;
|
||
const label = `${structureName} — ${typeLabel(type)}`;
|
||
|
||
document.querySelectorAll('select').forEach((select) => {
|
||
const option = Array.from(select.options).find((item) => item.value === String(structureId));
|
||
if (option && (
|
||
select.matches('#structure, #overview-structure, #new-agent-structure, #edit-agent-entry-structure, #edit-agent-profile-structure, #coverage-structure-filter, #coverage-rules-structure, .agent-structure-select')
|
||
)) {
|
||
option.textContent = label;
|
||
}
|
||
});
|
||
}
|
||
|
||
/** Options de lieu, reconstruites depuis les lieux actuellement affichés. */
|
||
function structureOptionsHtml(selectedStructureId = null) {
|
||
const source = document.querySelector('#new-agent-structure');
|
||
if (!source) return '<option value="">Sans lieu principal</option>';
|
||
|
||
const options = ['<option value="">Sans lieu principal</option>'];
|
||
Array.from(source.options).forEach((option) => {
|
||
if (!option.value) return;
|
||
const selected = Number(option.value) === Number(selectedStructureId) ? ' selected' : '';
|
||
options.push(`<option value="${Number(option.value)}"${selected}>${escapeHtml(option.textContent.trim())}</option>`);
|
||
});
|
||
return options.join('');
|
||
}
|
||
|
||
/** Ajoute la ligne d'un lieu au tableau de paramétrage, sans doublon. */
|
||
function addStructureSettingsRow(structure) {
|
||
const body = document.querySelector('#structure-settings-body');
|
||
if (!body || body.querySelector(`tr[data-structure-id="${Number(structure.id_structure)}"]`)) return;
|
||
|
||
const row = document.createElement('tr');
|
||
row.dataset.structureId = String(Number(structure.id_structure));
|
||
row.innerHTML = `
|
||
<td><strong>${escapeHtml(structure.nom)}</strong></td>
|
||
<td>${escapeHtml(structure.code)}</td>
|
||
<td>
|
||
<select class="structure-type-select" aria-label="Type d’affectation de ${escapeHtml(structure.nom)}">
|
||
<option value="PERISCOLAIRE" ${structure.type_affectation === 'PERISCOLAIRE' ? 'selected' : ''}>Périscolaire</option>
|
||
<option value="EXTRASCOLAIRE" ${structure.type_affectation === 'EXTRASCOLAIRE' ? 'selected' : ''}>Extrascolaire</option>
|
||
</select>
|
||
</td>
|
||
<td><button type="button" class="button button-secondary save-structure-type">Enregistrer</button></td>
|
||
`;
|
||
body.appendChild(row);
|
||
}
|
||
|
||
/** « Diplômé — Libellé », « Diplômé » ou « Non diplômé ». */
|
||
function qualificationLabel(agent) {
|
||
if (!Number(agent.est_diplome)) return 'Non diplômé';
|
||
return agent.diplome_libelle ? `Diplômé — ${agent.diplome_libelle}` : 'Diplômé';
|
||
}
|
||
|
||
/**
|
||
* « 2026-02-17 » → « 17/02/2026 », « Non renseignée » si vide.
|
||
* Découpage de chaîne plutôt que `new Date()`, qui décalerait la date.
|
||
*/
|
||
function formatContractDate(value) {
|
||
if (!value) return 'Non renseignée';
|
||
const [year, month, day] = String(value).split('-');
|
||
return year && month && day ? `${day}/${month}/${year}` : value;
|
||
}
|
||
|
||
/**
|
||
* Cellules d'une ligne d'agent.
|
||
* Toutes les valeurs passent par escapeHtml() : elles viennent de la base et
|
||
* sont insérées en HTML brut.
|
||
*/
|
||
function agentRowHtml(agent) {
|
||
const structureLabel = agent.structure_nom || agent.structure_principale_nom || 'Sans lieu principal';
|
||
return `
|
||
<td><strong class="agent-row-name">${escapeHtml(agent.prenom)} ${escapeHtml(agent.nom)}</strong></td>
|
||
<td>${escapeHtml(agent.matricule)}</td>
|
||
<td class="agent-row-post">${escapeHtml(agent.poste_libelle || 'Non renseigné')}</td>
|
||
<td class="agent-row-qualification">${escapeHtml(qualificationLabel(agent))}</td>
|
||
<td class="agent-row-phone">${escapeHtml(agent.telephone || 'Non renseigné')}</td>
|
||
<td class="agent-row-contract-start">${escapeHtml(formatContractDate(agent.date_debut_contrat))}</td>
|
||
<td class="agent-row-structure">${escapeHtml(structureLabel)}</td>
|
||
<td><button type="button" class="button button-secondary edit-agent-profile">Modifier</button></td>
|
||
`;
|
||
}
|
||
|
||
/**
|
||
* Recopie la fiche de l'agent dans les `data-*` de sa ligne.
|
||
*
|
||
* Ces attributs sont la SOURCE de la modale d'édition : elle s'ouvre
|
||
* uniquement à partir d'eux, sans nouvel appel réseau. Ajouter un champ
|
||
* modifiable impose donc de l'ajouter ici ET dans
|
||
* `openAgentProfileModal()`, sinon il s'ouvrira vide et sera écrasé à
|
||
* l'enregistrement.
|
||
*
|
||
* Les noms sont en camelCase, conversion automatique des `data-*` par le DOM
|
||
* (`data-date-debut-contrat` → `dataset.dateDebutContrat`).
|
||
*/
|
||
function setAgentRowData(row, agent) {
|
||
row.dataset.agentId = String(Number(agent.id_agent));
|
||
row.dataset.email = agent.email || '';
|
||
row.dataset.telephone = agent.telephone || '';
|
||
row.dataset.adresse = agent.adresse || '';
|
||
row.dataset.estDiplome = Number(agent.est_diplome) ? '1' : '0';
|
||
row.dataset.diplomeLibelle = agent.diplome_libelle || '';
|
||
row.dataset.dateDebutContrat = agent.date_debut_contrat || '';
|
||
row.dataset.dateFinContrat = agent.date_fin_contrat || '';
|
||
row.dataset.idPoste = agent.id_poste ? String(Number(agent.id_poste)) : '';
|
||
row.dataset.typeContrat = agent.type_contrat || 'PERMANENT';
|
||
row.dataset.droitEnveloppeFormation = Number(agent.droit_enveloppe_formation ?? 1) ? '1' : '0';
|
||
row.dataset.commentairePta = agent.commentaire_pta || '';
|
||
row.dataset.structureId = agent.id_structure ? String(Number(agent.id_structure)) : '';
|
||
}
|
||
|
||
/** Insère un agent nouvellement créé dans les sélecteurs et le tableau. */
|
||
function addAgentEverywhere(agent) {
|
||
const overviewAgent = document.querySelector('#overview-agent');
|
||
addOptionIfMissing(
|
||
overviewAgent,
|
||
Number(agent.id_agent),
|
||
`${agent.prenom} ${agent.nom} (${agent.matricule})`
|
||
);
|
||
|
||
const body = document.querySelector('#agent-assignment-body');
|
||
if (body && !body.querySelector(`tr[data-agent-id="${Number(agent.id_agent)}"]`)) {
|
||
const row = document.createElement('tr');
|
||
setAgentRowData(row, agent);
|
||
row.innerHTML = agentRowHtml(agent);
|
||
body.appendChild(row);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Le libellé du diplôme n'a de sens que si l'agent est diplômé : le champ
|
||
* est désactivé et VIDÉ sinon, pour ne pas enregistrer une valeur résiduelle.
|
||
*/
|
||
function toggleDiplomaField(select, input) {
|
||
if (!select || !input) return;
|
||
const qualified = select.value === '1';
|
||
input.disabled = !qualified;
|
||
if (!qualified) input.value = '';
|
||
}
|
||
|
||
/**
|
||
* Ouvre la modale d'édition d'un agent, préremplie depuis les `data-*` de sa
|
||
* ligne (voir `setAgentRowData()`).
|
||
*/
|
||
function openAgentProfileModal(row) {
|
||
const modal = document.querySelector('#agent-profile-modal');
|
||
if (!modal || !row) return;
|
||
|
||
document.querySelector('#edit-agent-profile-id').value = row.dataset.agentId || '';
|
||
document.querySelector('#agent-profile-modal-subtitle').textContent = row.querySelector('.agent-row-name')?.textContent?.trim() || '';
|
||
document.querySelector('#edit-agent-profile-email').value = row.dataset.email || '';
|
||
document.querySelector('#edit-agent-profile-phone').value = row.dataset.telephone || '';
|
||
document.querySelector('#edit-agent-profile-address').value = row.dataset.adresse || '';
|
||
document.querySelector('#edit-agent-profile-qualified').value = row.dataset.estDiplome === '1' ? '1' : '0';
|
||
document.querySelector('#edit-agent-profile-diploma').value = row.dataset.diplomeLibelle || '';
|
||
document.querySelector('#edit-agent-profile-contract-start').value = row.dataset.dateDebutContrat || '';
|
||
document.querySelector('#edit-agent-profile-contract-end').value = row.dataset.dateFinContrat || '';
|
||
document.querySelector('#edit-agent-profile-post').value = row.dataset.idPoste || '';
|
||
document.querySelector('#edit-agent-profile-contract-type').value = row.dataset.typeContrat || 'PERMANENT';
|
||
document.querySelector('#edit-agent-profile-training-right').checked = row.dataset.droitEnveloppeFormation !== '0';
|
||
document.querySelector('#edit-agent-profile-pta-comment').value = row.dataset.commentairePta || '';
|
||
document.querySelector('#edit-agent-profile-structure').value = row.dataset.structureId || '';
|
||
toggleDiplomaField(document.querySelector('#edit-agent-profile-qualified'), document.querySelector('#edit-agent-profile-diploma'));
|
||
|
||
const message = document.querySelector('#agent-profile-message');
|
||
if (message) {
|
||
message.className = 'message';
|
||
message.textContent = '';
|
||
}
|
||
modal.hidden = false;
|
||
}
|
||
|
||
/** Ferme la modale d'édition d'un agent. */
|
||
function closeAgentProfileModal() {
|
||
const modal = document.querySelector('#agent-profile-modal');
|
||
if (modal) modal.hidden = true;
|
||
}
|
||
|
||
/**
|
||
* Enregistre la fiche d'un agent, puis met à jour sa ligne et ses `data-*`
|
||
* avec la fiche renvoyée par le serveur — et non avec les valeurs saisies :
|
||
* le serveur peut avoir normalisé ou refusé certains champs.
|
||
*/
|
||
async function saveAgentProfile(event) {
|
||
event.preventDefault();
|
||
const form = event.currentTarget;
|
||
const message = document.querySelector('#agent-profile-message');
|
||
const submit = form.querySelector('button[type="submit"]');
|
||
const agentId = Number(document.querySelector('#edit-agent-profile-id').value);
|
||
if (!agentId || !message || !submit) return;
|
||
|
||
submit.disabled = true;
|
||
message.className = 'message';
|
||
message.textContent = '';
|
||
|
||
try {
|
||
const structureValue = document.querySelector('#edit-agent-profile-structure').value;
|
||
const response = await fetch('api/update_agent.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
agent_id: agentId,
|
||
email: document.querySelector('#edit-agent-profile-email').value,
|
||
telephone: document.querySelector('#edit-agent-profile-phone').value,
|
||
adresse: document.querySelector('#edit-agent-profile-address').value,
|
||
est_diplome: document.querySelector('#edit-agent-profile-qualified').value === '1',
|
||
diplome_libelle: document.querySelector('#edit-agent-profile-diploma').value,
|
||
date_debut_contrat: document.querySelector('#edit-agent-profile-contract-start').value,
|
||
date_fin_contrat: document.querySelector('#edit-agent-profile-contract-end').value,
|
||
id_poste: Number(document.querySelector('#edit-agent-profile-post').value),
|
||
type_contrat: document.querySelector('#edit-agent-profile-contract-type').value,
|
||
droit_enveloppe_formation: document.querySelector('#edit-agent-profile-training-right').checked,
|
||
commentaire_pta: document.querySelector('#edit-agent-profile-pta-comment').value,
|
||
structure_id: structureValue ? Number(structureValue) : null,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de modifier les informations de l’agent.'));
|
||
|
||
const row = document.querySelector(`#agent-assignment-body tr[data-agent-id="${agentId}"]`);
|
||
if (row) {
|
||
setAgentRowData(row, data.agent);
|
||
row.innerHTML = agentRowHtml({
|
||
...data.agent,
|
||
structure_nom: data.agent.structure_principale_nom,
|
||
});
|
||
}
|
||
|
||
message.className = 'message message-success';
|
||
message.textContent = data.message;
|
||
|
||
if (structureSelect?.value) await PTA.modules.planning?.loadAgents?.();
|
||
if (document.querySelector('#overview-structure')?.value) await PTA.modules.structureOverview?.load?.();
|
||
if (document.querySelector('#overview-agent')?.value === String(agentId)) await PTA.modules.agentOverview?.load?.();
|
||
|
||
setTimeout(closeAgentProfileModal, 500);
|
||
} catch (error) {
|
||
message.className = 'message message-error';
|
||
message.textContent = error.message;
|
||
} finally {
|
||
submit.disabled = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crée un lieu d'affectation, puis le diffuse dans toute la page.
|
||
* Un code déjà pris ressort en 409 et le message le dit explicitement.
|
||
*/
|
||
async function createStructure(event) {
|
||
event.preventDefault();
|
||
const form = event.currentTarget;
|
||
const message = document.querySelector('#create-structure-message');
|
||
const submit = form.querySelector('button[type="submit"]');
|
||
if (!message || !submit) return;
|
||
|
||
message.className = 'message';
|
||
message.textContent = '';
|
||
submit.disabled = true;
|
||
|
||
try {
|
||
const response = await fetch('api/create_structure.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
code: document.querySelector('#new-structure-code').value,
|
||
nom: document.querySelector('#new-structure-name').value,
|
||
adresse: document.querySelector('#new-structure-address').value,
|
||
type_affectation: document.querySelector('#new-structure-type').value,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de créer le lieu d’affectation.'));
|
||
|
||
addStructureEverywhere(data.structure);
|
||
addStructureSettingsRow(data.structure);
|
||
form.reset();
|
||
document.querySelector('#new-structure-type').value = 'PERISCOLAIRE';
|
||
message.className = 'message message-success';
|
||
message.textContent = data.message;
|
||
PTA.modules.coverage?.refresh?.({ silent: true });
|
||
} catch (error) {
|
||
message.className = 'message message-error';
|
||
message.textContent = error.message;
|
||
} finally {
|
||
submit.disabled = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crée un agent, puis le diffuse dans toute la page.
|
||
* Le serveur ouvre au passage son quota annuel et son PTA ; un matricule
|
||
* déjà pris ressort en 409.
|
||
*/
|
||
async function createAgent(event) {
|
||
event.preventDefault();
|
||
const form = event.currentTarget;
|
||
const message = document.querySelector('#create-agent-message');
|
||
const submit = form.querySelector('button[type="submit"]');
|
||
if (!message || !submit) return;
|
||
|
||
message.className = 'message';
|
||
message.textContent = '';
|
||
submit.disabled = true;
|
||
|
||
try {
|
||
const response = await fetch('api/create_agent.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
matricule: document.querySelector('#new-agent-matricule').value,
|
||
nom: document.querySelector('#new-agent-name').value,
|
||
prenom: document.querySelector('#new-agent-firstname').value,
|
||
email: document.querySelector('#new-agent-email').value,
|
||
telephone: document.querySelector('#new-agent-phone').value,
|
||
adresse: document.querySelector('#new-agent-address').value,
|
||
est_diplome: document.querySelector('#new-agent-qualified').value === '1',
|
||
diplome_libelle: document.querySelector('#new-agent-diploma').value,
|
||
structure_id: Number(document.querySelector('#new-agent-structure').value),
|
||
quotite_travail: Number(document.querySelector('#new-agent-rate').value),
|
||
date_debut_contrat: document.querySelector('#new-agent-contract-start').value,
|
||
date_fin_contrat: document.querySelector('#new-agent-contract-end').value,
|
||
id_poste: Number(document.querySelector('#new-agent-post').value),
|
||
type_contrat: document.querySelector('#new-agent-contract-type').value,
|
||
droit_enveloppe_formation: document.querySelector('#new-agent-training-right').checked,
|
||
commentaire_pta: document.querySelector('#new-agent-pta-comment').value,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de créer l’agent.'));
|
||
|
||
addAgentEverywhere(data.agent);
|
||
const createdStructureId = String(data.agent.id_structure);
|
||
form.reset();
|
||
document.querySelector('#new-agent-rate').value = '100';
|
||
document.querySelector('#new-agent-contract-type').value = 'PERMANENT';
|
||
document.querySelector('#new-agent-qualified').value = '0';
|
||
toggleDiplomaField(document.querySelector('#new-agent-qualified'), document.querySelector('#new-agent-diploma'));
|
||
|
||
message.className = 'message message-success';
|
||
message.textContent = `${data.message} Quota annuel : ${formatDuration(Number(data.agent.quota_cible_minutes))}, suivi du 1er janvier au 31 décembre.`;
|
||
|
||
if (structureSelect?.value === createdStructureId) {
|
||
await PTA.modules.planning?.loadAgents?.();
|
||
}
|
||
if (document.querySelector('#overview-structure')?.value === createdStructureId) {
|
||
await PTA.modules.structureOverview?.load?.();
|
||
}
|
||
} catch (error) {
|
||
message.className = 'message message-error';
|
||
message.textContent = error.message;
|
||
} finally {
|
||
submit.disabled = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Point d'entrée appelé par page-bootstrap.js.
|
||
* Les tableaux sont écoutés par DÉLÉGATION : leurs lignes sont ajoutées
|
||
* dynamiquement et n'existent pas au moment où les écouteurs sont posés.
|
||
*/
|
||
function init() {
|
||
document.querySelector('#agent-assignment-body')?.addEventListener('click', (event) => {
|
||
const button = event.target.closest('.edit-agent-profile');
|
||
if (button) openAgentProfileModal(button.closest('tr[data-agent-id]'));
|
||
});
|
||
|
||
document.querySelector('#structure-settings-body')?.addEventListener('click', (event) => {
|
||
const button = event.target.closest('.save-structure-type');
|
||
if (button) saveStructureType(button);
|
||
});
|
||
|
||
document.querySelector('#new-agent-qualified')?.addEventListener('change', (event) => {
|
||
toggleDiplomaField(event.currentTarget, document.querySelector('#new-agent-diploma'));
|
||
});
|
||
document.querySelector('#edit-agent-profile-qualified')?.addEventListener('change', (event) => {
|
||
toggleDiplomaField(event.currentTarget, document.querySelector('#edit-agent-profile-diploma'));
|
||
});
|
||
|
||
document.querySelector('#close-agent-profile-modal')?.addEventListener('click', closeAgentProfileModal);
|
||
document.querySelector('#cancel-agent-profile')?.addEventListener('click', closeAgentProfileModal);
|
||
document.querySelector('#agent-profile-modal')?.addEventListener('click', (event) => {
|
||
if (event.target.id === 'agent-profile-modal') closeAgentProfileModal();
|
||
});
|
||
document.querySelector('#agent-profile-form')?.addEventListener('submit', saveAgentProfile);
|
||
|
||
document.querySelector('#create-structure-form')?.addEventListener('submit', createStructure);
|
||
document.querySelector('#create-agent-form')?.addEventListener('submit', createAgent);
|
||
|
||
toggleDiplomaField(document.querySelector('#new-agent-qualified'), document.querySelector('#new-agent-diploma'));
|
||
}
|
||
|
||
PTA.modules.administration = {
|
||
init,
|
||
saveAgentStructure,
|
||
saveStructureType,
|
||
addStructureEverywhere,
|
||
addAgentEverywhere,
|
||
openAgentProfileModal,
|
||
};
|
||
})();
|