Files
pta/assets/js/teams.js
Loic Masi 5fbf76868f pour prod
2026-08-07 16:13:43 +02:00

159 lines
9.3 KiB
JavaScript
Raw Permalink 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.
(() => {
'use strict';
const PTA = window.PTA;
if (!PTA) return;
const { readJsonResponse, apiErrorMessage, escapeHtml, formatDate } = PTA.utils;
const el = (id) => document.getElementById(id);
function message(text, type = 'info') {
const box = el('team-list-message');
if (!box) return;
box.className = `message message-${type}`;
box.textContent = text;
}
async function api(url, options = {}) {
const response = await fetch(url, options);
const data = await readJsonResponse(response);
if (!response.ok) throw new Error(apiErrorMessage(data, 'Opération impossible.'));
return data;
}
function controlHtml(control) {
const level = String(control.niveau || 'INFO').toLowerCase();
return `<div class="control-item control-${escapeHtml(level)}"><strong>${escapeHtml(control.niveau)}</strong><span>${escapeHtml(control.message)}</span></div>`;
}
function teamHtml(team) {
const options = el('team-agent-options')?.innerHTML || '';
const members = (team.members || []).map((member) => `
<tr>
<td><strong>${escapeHtml(member.prenom)} ${escapeHtml(member.nom)}</strong><br><small>${escapeHtml(member.poste_libelle || 'Poste non renseigné')}</small></td>
<td>${member.est_diplome ? `Diplômé${member.diplome_libelle ? `${escapeHtml(member.diplome_libelle)}` : ''}` : 'Non diplômé'}</td>
<td>${escapeHtml(member.fonction_equipe)}</td>
<td>${escapeHtml(member.structure_principale_nom || 'Sans lieu principal')}</td>
<td><button type="button" class="button button-danger remove-team-member" data-agent-id="${Number(member.id_agent)}">Retirer</button></td>
</tr>
`).join('') || '<tr><td colspan="5">Aucun agent affecté.</td></tr>';
return `
<article class="card team-card" data-team-id="${Number(team.id_equipe)}">
<div class="section-heading">
<div><h3>${escapeHtml(team.libelle)}</h3><p class="section-subtitle">${escapeHtml(team.structure_nom)}${formatDate(team.date_debut)} au ${formatDate(team.date_fin)}${escapeHtml(team.type_equipe)}</p></div>
<select class="team-status" aria-label="Statut"><option value="BROUILLON" ${team.statut === 'BROUILLON' ? 'selected' : ''}>Brouillon</option><option value="A_CONTROLER" ${team.statut === 'A_CONTROLER' ? 'selected' : ''}>À contrôler</option><option value="VALIDEE" ${team.statut === 'VALIDEE' ? 'selected' : ''}>Validée</option></select>
</div>
<div class="summary-grid compact-summary">
<article class="summary-card"><span>Agents requis</span><strong>${Number(team.agents_requis)}</strong></article>
<article class="summary-card"><span>Agents affectés</span><strong>${Number(team.agents_affectes)}</strong></article>
<article class="summary-card"><span>Diplômés</span><strong>${Number(team.agents_diplomes || 0)}</strong></article>
<article class="summary-card"><span>Enfants</span><strong>${Number(team.nombre_enfants_moins_6) + Number(team.nombre_enfants_6_plus)}</strong></article>
</div>
<div class="control-list">${(team.controls || []).map(controlHtml).join('')}</div>
<form class="team-member-form inline-form">
<label class="field"><span>Agent</span><select class="team-member-agent" required><option value="">Choisir un agent</option>${options}</select></label>
<label class="field"><span>Fonction dans léquipe</span><select class="team-member-function"><option value="RESPONSABLE">Responsable</option><option value="ANIMATION">Animation</option><option value="RESTAURATION_ENTRETIEN">Restauration / entretien</option></select></label>
<label class="field"><span>Commentaire</span><input class="team-member-comment" type="text" maxlength="500"></label>
<button class="button button-primary" type="submit">Ajouter</button>
</form>
<div class="table-scroll"><table class="planning-table"><thead><tr><th>Agent</th><th>Qualification</th><th>Fonction</th><th>Lieu principal</th><th>Action</th></tr></thead><tbody>${members}</tbody></table></div>
</article>`;
}
async function load() {
const start = el('team-filter-start')?.value || '';
const end = el('team-filter-end')?.value || '';
const query = new URLSearchParams();
if (start) query.set('date_debut', start);
if (end) query.set('date_fin', end);
message('Chargement des équipes…');
try {
const data = await api(`api/teams.php?${query.toString()}`);
el('team-list').innerHTML = (data.teams || []).map(teamHtml).join('') || '<div class="empty-state">Aucune équipe sur cette période.</div>';
message(`${(data.teams || []).length} équipe(s) affichée(s).`, 'success');
} catch (error) { message(error.message, 'error'); }
}
async function create(event) {
event.preventDefault();
const box = el('team-create-message');
try {
const data = await api('api/teams.php', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
csrf_token: window.PTA_CONFIG.csrfToken,
structure_id: Number(el('team-structure').value),
type_equipe: el('team-type').value,
libelle: el('team-label').value,
date_debut: el('team-start').value,
date_fin: el('team-end').value,
nombre_enfants_moins_6: Number(el('team-under-six').value),
nombre_enfants_6_plus: Number(el('team-over-six').value),
ratio_moins_6: Number(el('team-ratio-under-six').value),
ratio_6_plus: Number(el('team-ratio-over-six').value),
minimum_agents: Number(el('team-min-agents').value),
pourcentage_diplomes_min: Number(el('team-qualified-rate').value),
commentaire: el('team-comment').value,
}),
});
box.className = 'message message-success'; box.textContent = data.message;
event.currentTarget.reset();
el('team-ratio-under-six').value = '8'; el('team-ratio-over-six').value = '12'; el('team-min-agents').value = '1'; el('team-qualified-rate').value = '50';
await load();
} catch (error) { box.className = 'message message-error'; box.textContent = error.message; }
}
async function handle(event) {
const card = event.target.closest('.team-card');
if (!card) return;
const teamId = Number(card.dataset.teamId);
if (event.type === 'submit' && event.target.matches('.team-member-form')) {
event.preventDefault();
try {
await api('api/team_members.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({
csrf_token: window.PTA_CONFIG.csrfToken, team_id: teamId,
agent_id: Number(card.querySelector('.team-member-agent').value),
fonction_equipe: card.querySelector('.team-member-function').value,
commentaire: card.querySelector('.team-member-comment').value,
}) });
await load();
} catch (error) { message(error.message, 'error'); }
return;
}
const remove = event.target.closest('.remove-team-member');
if (remove) {
if (!window.confirm('Retirer cet agent de léquipe ?')) return;
try {
await api('api/team_members.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({
csrf_token: window.PTA_CONFIG.csrfToken, action: 'REMOVE', team_id: teamId, agent_id: Number(remove.dataset.agentId),
}) });
await load();
} catch (error) { message(error.message, 'error'); }
}
}
async function status(event) {
const select = event.target.closest('.team-status');
if (!select) return;
const card = select.closest('.team-card');
try {
await api('api/team_status.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({
csrf_token: window.PTA_CONFIG.csrfToken, team_id: Number(card.dataset.teamId), statut: select.value,
}) });
await load();
} catch (error) { message(error.message, 'error'); }
}
function init() {
const params = window.PTA_PAGE_CONFIG?.params || {};
if (params.dateDebut) el('team-filter-start').value = params.dateDebut;
if (params.dateFin) el('team-filter-end').value = params.dateFin;
el('team-create-form')?.addEventListener('submit', create);
el('load-teams')?.addEventListener('click', load);
el('team-list')?.addEventListener('submit', handle);
el('team-list')?.addEventListener('click', handle);
el('team-list')?.addEventListener('change', status);
load();
}
PTA.modules.teams = { init, load };
})();