536 lines
26 KiB
JavaScript
536 lines
26 KiB
JavaScript
(() => {
|
||
'use strict';
|
||
|
||
const PTA = window.PTA;
|
||
if (!PTA) throw new Error('PTA core doit être chargé avant agent-overview.js');
|
||
|
||
const permissions = window.PTA_CONFIG?.permissions || {};
|
||
const accessProfile = window.PTA_CONFIG?.access || {};
|
||
const canEditDraft = Boolean(permissions.can_edit_draft);
|
||
const canEditCrossStructure = Boolean(permissions.can_edit_cross_structure);
|
||
const canCopyFullWeek = Boolean(permissions.can_copy_full_week);
|
||
|
||
const { shared } = PTA;
|
||
const {
|
||
escapeHtml,
|
||
readJsonResponse,
|
||
apiErrorMessage,
|
||
formatDate,
|
||
timeToMinutes,
|
||
formatDuration,
|
||
} = PTA.utils;
|
||
|
||
let draggedEntry = null;
|
||
let suppressClickUntil = 0;
|
||
let activeSourceWeek = '';
|
||
|
||
const typeLabel = (type) => type === 'EXTRASCOLAIRE' ? 'Extrascolaire' : 'Périscolaire';
|
||
|
||
function setMessage(element, text = '', type = 'info') {
|
||
if (!element) return;
|
||
element.className = text ? `message message-${type}` : 'message';
|
||
element.textContent = text;
|
||
}
|
||
|
||
function canEditEntry(entry) {
|
||
if (!canEditDraft) return false;
|
||
if (canEditCrossStructure) return true;
|
||
return Number(entry.id_structure) === Number(accessProfile.structure_id || 0);
|
||
}
|
||
|
||
function entryBadge(entry) {
|
||
const editable = canEditEntry(entry);
|
||
const interactionAttributes = editable
|
||
? `draggable="true" tabindex="0" role="button" data-editable="1" title="Glissez vers un autre jour pour déplacer. Ctrl/⌘ + glisser pour dupliquer."`
|
||
: 'data-editable="0"';
|
||
return `
|
||
<article class="overview-entry agent-month-entry${editable ? ' planning-entry-interactive' : ''} motif-${escapeHtml(String(entry.motif_code || 'autre').toLowerCase())}"
|
||
${interactionAttributes} data-entry-id="${Number(entry.id_creneau)}">
|
||
${editable ? '<span class="entry-drag-hint" aria-hidden="true">⋮⋮</span>' : ''}
|
||
<div class="agent-month-entry-content">
|
||
<strong>${escapeHtml(entry.heure_debut)}–${escapeHtml(entry.heure_fin)}</strong>
|
||
<span>${escapeHtml(entry.motif_libelle)}</span>
|
||
<small>📍 ${escapeHtml(entry.structure_nom)} · ${typeLabel(entry.structure_type_affectation)}</small>
|
||
${entry.statut === 'BROUILLON' ? '<em>Brouillon</em>' : ''}
|
||
</div>
|
||
<div class="agent-month-entry-actions">
|
||
${editable
|
||
? `<button type="button" class="button button-secondary overview-entry-edit" data-entry-id="${Number(entry.id_creneau)}">Modifier</button>`
|
||
: '<span class="entry-locked">Lecture seule</span>'}
|
||
</div>
|
||
</article>
|
||
`;
|
||
}
|
||
|
||
function countedMinutes(entries) {
|
||
return entries.reduce((sum, entry) => {
|
||
if (!Number(entry.compte_dans_quota)) return sum;
|
||
return sum + (timeToMinutes(entry.heure_fin) - timeToMinutes(entry.heure_debut));
|
||
}, 0);
|
||
}
|
||
|
||
function render(data) {
|
||
const container = document.querySelector('#agent-overview-content');
|
||
const empty = document.querySelector('#agent-overview-empty');
|
||
if (!container || !empty) return;
|
||
|
||
shared.lastAgentOverviewData = data;
|
||
empty.hidden = true;
|
||
container.hidden = false;
|
||
|
||
const monthMinutes = countedMinutes(data.entries || []);
|
||
const weekBlocks = (data.weeks || []).map((week) => {
|
||
const days = week.days.map((day) => {
|
||
const entries = (data.entries || []).filter((entry) => entry.date_jour === day.date);
|
||
return `
|
||
<article class="agent-month-day-card${day.in_month ? '' : ' is-outside-month'}" data-date="${escapeHtml(day.date)}">
|
||
<header class="agent-month-day-header">
|
||
<strong>${escapeHtml(day.label)}</strong>
|
||
<span>${escapeHtml(day.display)}</span>
|
||
</header>
|
||
<div class="agent-month-day-body">
|
||
${entries.length ? entries.map(entryBadge).join('') : '<p class="day-empty">Aucune affectation</p>'}
|
||
</div>
|
||
</article>
|
||
`;
|
||
}).join('');
|
||
|
||
return `
|
||
<section class="agent-month-week" data-week="${escapeHtml(week.value)}">
|
||
<header class="agent-month-week-header">
|
||
<div>
|
||
<strong>Semaine ${Number(week.number)}</strong>
|
||
<span>du ${formatDate(week.date_debut)} au ${formatDate(week.date_fin)}</span>
|
||
</div>
|
||
${canCopyFullWeek ? `<button type="button" class="button button-secondary agent-copy-week" data-source-week="${escapeHtml(week.value)}">Dupliquer cette semaine</button>` : ''}
|
||
</header>
|
||
<div class="agent-month-week-grid">${days}</div>
|
||
</section>
|
||
`;
|
||
}).join('');
|
||
|
||
container.innerHTML = `
|
||
<div class="overview-title-row agent-month-title-row">
|
||
<div>
|
||
<h3>${escapeHtml(data.agent.prenom)} ${escapeHtml(data.agent.nom)}</h3>
|
||
<p>${escapeHtml(data.agent.matricule)}${data.agent.structure_principale_nom ? ` · lieu principal : ${escapeHtml(data.agent.structure_principale_nom)} (${typeLabel(data.agent.structure_principale_type_affectation)})` : ''} · ${escapeHtml(data.month.label)}</p>
|
||
<p class="agent-contact-summary">${Number(data.agent.est_diplome) ? `🎓 Diplômé${data.agent.diplome_libelle ? ` — ${escapeHtml(data.agent.diplome_libelle)}` : ''}` : 'Non diplômé'}${data.agent.telephone ? ` · 📞 ${escapeHtml(data.agent.telephone)}` : ''}${data.agent.adresse ? ` · 📍 ${escapeHtml(data.agent.adresse)}` : ''}${data.agent.date_debut_contrat ? ` · Contrat depuis le ${escapeHtml(formatDate(data.agent.date_debut_contrat))}` : ' · ⚠ Date de début de contrat non renseignée'}</p>
|
||
</div>
|
||
<div class="agent-overview-actions">
|
||
<button type="button" class="button button-secondary button-pdf agent-hours-contract-pdf">Contrat horaire PDF</button>
|
||
<button type="button" class="button button-primary button-pdf agent-time-summary-pdf">Bilan des heures PDF</button>
|
||
</div>
|
||
</div>
|
||
<div class="quota-strip overview-quota-strip">
|
||
<article class="quota-card"><span>Quotité</span><strong>${Number(data.quota.quotite_travail).toLocaleString('fr-FR')} %</strong></article>
|
||
<article class="quota-card"><span>Quota de la période</span><strong>${escapeHtml(data.quota.quota_cible.libelle)}</strong><small>${escapeHtml(data.quota.periode_libelle || '')}</small></article>
|
||
<article class="quota-card"><span>Décompté sur le mois affiché</span><strong>${escapeHtml(formatDuration(monthMinutes))}</strong><small>Travail + motifs comptant dans le quota</small></article>
|
||
<article class="quota-card quota-card-emphasis"><span>Reste à affecter</span><strong class="${data.quota.minutes_restantes < 0 ? 'quota-negative' : ''}">${escapeHtml(data.quota.restantes.libelle)}</strong><small>Calcul sur l’année civile du 1er janvier au 31 décembre.</small></article>
|
||
</div>
|
||
<p class="agent-month-help">${canEditDraft
|
||
? (canCopyFullWeek
|
||
? 'Glissez un créneau modifiable vers un autre jour pour le déplacer. Maintenez <strong>Ctrl</strong> (ou <strong>⌘</strong> sur Mac) pour le dupliquer. La duplication complète d’une semaine est réservée au Service Enfance.'
|
||
: 'Vous pouvez modifier les créneaux de votre lieu. Les créneaux saisis sur un autre lieu restent en lecture seule et toute modification est enregistrée en brouillon.')
|
||
: 'Cette vue est en lecture seule. Vous pouvez consulter votre planning et télécharger les documents disponibles.'}</p>
|
||
<div class="agent-month-planner">${weekBlocks}</div>
|
||
`;
|
||
|
||
bindMonthInteractions();
|
||
}
|
||
|
||
function findEntry(entryId) {
|
||
return shared.lastAgentOverviewData?.entries?.find((item) => Number(item.id_creneau) === Number(entryId)) || null;
|
||
}
|
||
|
||
async function persistEntryMove(entryId, targetDate, duplicate) {
|
||
const response = await fetch('api/move_or_duplicate_entry.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
entry_id: Number(entryId),
|
||
target_date: targetDate,
|
||
action: duplicate ? 'duplicate' : 'move',
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de déplacer ce créneau.'));
|
||
return data;
|
||
}
|
||
|
||
function clearDropTargets() {
|
||
document.querySelectorAll('#agent-overview-content .agent-month-day-card').forEach((card) => {
|
||
card.classList.remove('is-drop-target', 'is-copy-target');
|
||
});
|
||
}
|
||
|
||
function bindMonthInteractions() {
|
||
const container = document.querySelector('#agent-overview-content');
|
||
if (!container) return;
|
||
|
||
container.querySelectorAll('.agent-month-entry[data-editable="1"]').forEach((item) => {
|
||
item.addEventListener('dragstart', (event) => {
|
||
draggedEntry = findEntry(Number(item.dataset.entryId));
|
||
item.classList.add('is-dragging');
|
||
event.dataTransfer.effectAllowed = 'copyMove';
|
||
event.dataTransfer.setData('text/plain', item.dataset.entryId || '');
|
||
});
|
||
item.addEventListener('dragend', () => {
|
||
item.classList.remove('is-dragging');
|
||
draggedEntry = null;
|
||
suppressClickUntil = Date.now() + 250;
|
||
clearDropTargets();
|
||
});
|
||
item.addEventListener('keydown', (event) => {
|
||
if (event.key === 'Enter' || event.key === ' ') {
|
||
event.preventDefault();
|
||
openModal(Number(item.dataset.entryId));
|
||
}
|
||
});
|
||
item.addEventListener('click', (event) => {
|
||
if (Date.now() < suppressClickUntil || event.target.closest('button')) return;
|
||
openModal(Number(item.dataset.entryId));
|
||
});
|
||
});
|
||
|
||
if (!canEditDraft) return;
|
||
container.querySelectorAll('.agent-month-day-card').forEach((card) => {
|
||
card.addEventListener('dragover', (event) => {
|
||
if (!draggedEntry) return;
|
||
event.preventDefault();
|
||
const duplicate = event.ctrlKey || event.metaKey;
|
||
event.dataTransfer.dropEffect = duplicate ? 'copy' : 'move';
|
||
clearDropTargets();
|
||
card.classList.add('is-drop-target');
|
||
if (duplicate) card.classList.add('is-copy-target');
|
||
});
|
||
card.addEventListener('dragleave', (event) => {
|
||
if (!card.contains(event.relatedTarget)) card.classList.remove('is-drop-target', 'is-copy-target');
|
||
});
|
||
card.addEventListener('drop', async (event) => {
|
||
if (!draggedEntry) return;
|
||
event.preventDefault();
|
||
const entry = draggedEntry;
|
||
const targetDate = card.dataset.date || '';
|
||
const duplicate = event.ctrlKey || event.metaKey;
|
||
clearDropTargets();
|
||
try {
|
||
const result = await persistEntryMove(entry.id_creneau, targetDate, duplicate);
|
||
await load();
|
||
setMessage(document.querySelector('#agent-overview-message'), result.message || (duplicate ? 'Créneau dupliqué.' : 'Créneau déplacé.'), 'success');
|
||
} catch (error) {
|
||
setMessage(document.querySelector('#agent-overview-message'), error.message, 'error');
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function openHoursContractPdf() {
|
||
const data = shared.lastAgentOverviewData;
|
||
const agentId = data?.agent?.id_agent || document.querySelector('#overview-agent')?.value;
|
||
const date = data?.month?.date_debut;
|
||
if (!agentId || !date) return;
|
||
const params = new URLSearchParams({ agent_id: String(agentId), date: String(date) });
|
||
window.open(`api/agent_hours_contract_pdf.php?${params.toString()}`, '_blank', 'noopener');
|
||
}
|
||
|
||
function openTimeSummaryPdf() {
|
||
const data = shared.lastAgentOverviewData;
|
||
const agentId = data?.agent?.id_agent || document.querySelector('#overview-agent')?.value;
|
||
const date = data?.month?.date_debut;
|
||
if (!agentId || !date) return;
|
||
const params = new URLSearchParams({ agent_id: String(agentId), date: String(date) });
|
||
window.open(`api/agent_time_summary_pdf.php?${params.toString()}`, '_blank', 'noopener');
|
||
}
|
||
|
||
function closeModal() {
|
||
const modal = document.querySelector('#agent-entry-modal');
|
||
const form = document.querySelector('#agent-entry-edit-form');
|
||
const message = document.querySelector('#agent-entry-edit-message');
|
||
if (!modal) return;
|
||
modal.hidden = true;
|
||
document.body.classList.remove('modal-open');
|
||
form?.reset();
|
||
setMessage(message);
|
||
}
|
||
|
||
function openModal(entryId) {
|
||
const entry = findEntry(entryId);
|
||
if (!entry || !canEditEntry(entry)) return;
|
||
const modal = document.querySelector('#agent-entry-modal');
|
||
if (!entry || !modal) return;
|
||
|
||
document.querySelector('#edit-agent-entry-id').value = String(Number(entry.id_creneau));
|
||
document.querySelector('#edit-agent-entry-date').value = entry.date_jour;
|
||
document.querySelector('#edit-agent-entry-structure').value = String(Number(entry.id_structure));
|
||
document.querySelector('#edit-agent-entry-motif').value = String(Number(entry.id_motif));
|
||
document.querySelector('#edit-agent-entry-start').value = entry.heure_debut;
|
||
document.querySelector('#edit-agent-entry-end').value = entry.heure_fin;
|
||
setMessage(document.querySelector('#agent-entry-edit-message'));
|
||
modal.hidden = false;
|
||
document.body.classList.add('modal-open');
|
||
document.querySelector('#edit-agent-entry-motif')?.focus();
|
||
}
|
||
|
||
async function deleteEntry(entryId) {
|
||
const entry = findEntry(entryId);
|
||
if (!entry || !canEditEntry(entry)) return;
|
||
if (!entry) return;
|
||
|
||
const details = `${entry.motif_libelle} · ${entry.heure_debut}–${entry.heure_fin} · ${entry.structure_nom}`;
|
||
if (!window.confirm(`Supprimer définitivement ce créneau ?\n\n${details}\n${formatDate(entry.date_jour)}`)) return;
|
||
|
||
const button = document.querySelector('#delete-agent-entry-edit');
|
||
const message = document.querySelector('#agent-entry-edit-message');
|
||
if (button) button.disabled = true;
|
||
setMessage(message, 'Suppression du créneau en cours…', 'info');
|
||
|
||
try {
|
||
const response = await fetch('api/delete_agent_entry.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
entry_id: Number(entryId),
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de supprimer ce créneau.'));
|
||
|
||
await load();
|
||
closeModal();
|
||
setMessage(document.querySelector('#agent-overview-message'), data.message || 'Créneau supprimé.', 'success');
|
||
|
||
// La suppression peut modifier la file de validation et créer un trou de couverture.
|
||
PTA.modules.pendingValidation?.refresh?.({ silent: true });
|
||
PTA.modules.coverage?.refresh?.({ silent: true });
|
||
} catch (error) {
|
||
setMessage(message, error.message, 'error');
|
||
} finally {
|
||
if (button) button.disabled = false;
|
||
}
|
||
}
|
||
|
||
async function saveEntry(event) {
|
||
event.preventDefault();
|
||
if (!canEditDraft) return;
|
||
const submit = document.querySelector('#save-agent-entry-edit');
|
||
const message = document.querySelector('#agent-entry-edit-message');
|
||
if (!submit || !message) return;
|
||
|
||
submit.disabled = true;
|
||
setMessage(message);
|
||
|
||
try {
|
||
const response = await fetch('api/update_agent_entry.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
entry_id: Number(document.querySelector('#edit-agent-entry-id').value),
|
||
structure_id: Number(document.querySelector('#edit-agent-entry-structure').value),
|
||
motif_id: Number(document.querySelector('#edit-agent-entry-motif').value),
|
||
date: document.querySelector('#edit-agent-entry-date').value,
|
||
start: document.querySelector('#edit-agent-entry-start').value,
|
||
end: document.querySelector('#edit-agent-entry-end').value,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de modifier ce créneau.'));
|
||
|
||
setMessage(message, data.message || 'Créneau modifié.', 'success');
|
||
await load();
|
||
setTimeout(closeModal, 450);
|
||
} catch (error) {
|
||
setMessage(message, error.message, 'error');
|
||
} finally {
|
||
submit.disabled = false;
|
||
}
|
||
}
|
||
|
||
function isoWeekValueFromDate(date) {
|
||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||
const day = d.getUTCDay() || 7;
|
||
d.setUTCDate(d.getUTCDate() + 4 - day);
|
||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||
const weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
||
return `${d.getUTCFullYear()}-W${String(weekNo).padStart(2, '0')}`;
|
||
}
|
||
|
||
function weekMonday(weekValue) {
|
||
const match = /^(\d{4})-W(\d{2})$/.exec(weekValue);
|
||
if (!match) return null;
|
||
const year = Number(match[1]);
|
||
const week = Number(match[2]);
|
||
const jan4 = new Date(year, 0, 4);
|
||
const day = jan4.getDay() || 7;
|
||
const monday = new Date(jan4);
|
||
monday.setDate(jan4.getDate() - day + 1 + ((week - 1) * 7));
|
||
return monday;
|
||
}
|
||
|
||
function openWeekCopyModal(sourceWeek) {
|
||
if (!canCopyFullWeek) return;
|
||
const modal = document.querySelector('#agent-week-copy-modal');
|
||
const sourceInput = document.querySelector('#agent-week-copy-source');
|
||
const targetInput = document.querySelector('#agent-week-copy-target');
|
||
const summary = document.querySelector('#agent-week-copy-summary');
|
||
if (!modal || !sourceInput || !targetInput) return;
|
||
|
||
activeSourceWeek = sourceWeek;
|
||
sourceInput.value = sourceWeek;
|
||
const monday = weekMonday(sourceWeek);
|
||
if (monday) {
|
||
monday.setDate(monday.getDate() + 7);
|
||
targetInput.value = isoWeekValueFromDate(monday);
|
||
}
|
||
if (summary) summary.textContent = `La semaine ${sourceWeek.replace('-W', ' / S')} sera recopiée avec ses lieux, motifs et horaires.`;
|
||
setMessage(document.querySelector('#agent-week-copy-message'));
|
||
modal.hidden = false;
|
||
document.body.classList.add('modal-open');
|
||
targetInput.focus();
|
||
}
|
||
|
||
function closeWeekCopyModal() {
|
||
const modal = document.querySelector('#agent-week-copy-modal');
|
||
if (!modal) return;
|
||
modal.hidden = true;
|
||
document.body.classList.remove('modal-open');
|
||
activeSourceWeek = '';
|
||
document.querySelector('#agent-week-copy-form')?.reset();
|
||
setMessage(document.querySelector('#agent-week-copy-message'));
|
||
}
|
||
|
||
async function copyWeek(event) {
|
||
event.preventDefault();
|
||
if (!canCopyFullWeek) return;
|
||
const agentId = Number(document.querySelector('#overview-agent')?.value || 0);
|
||
const sourceWeek = document.querySelector('#agent-week-copy-source')?.value || activeSourceWeek;
|
||
const targetWeek = document.querySelector('#agent-week-copy-target')?.value || '';
|
||
const mode = document.querySelector('input[name="agent-week-copy-mode"]:checked')?.value || 'merge';
|
||
const message = document.querySelector('#agent-week-copy-message');
|
||
const submit = document.querySelector('#confirm-agent-week-copy');
|
||
|
||
if (!agentId || !sourceWeek || !targetWeek) {
|
||
setMessage(message, 'Sélectionnez une semaine cible.', 'warning');
|
||
return;
|
||
}
|
||
if (sourceWeek === targetWeek) {
|
||
setMessage(message, 'La semaine cible doit être différente de la semaine source.', 'warning');
|
||
return;
|
||
}
|
||
if (mode === 'replace' && !window.confirm('Les créneaux existants de la semaine cible seront supprimés avant la copie. Continuer ?')) return;
|
||
|
||
if (submit) submit.disabled = true;
|
||
setMessage(message, 'Duplication de la semaine en cours...', 'info');
|
||
try {
|
||
const response = await fetch('api/copy_agent_week.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
csrf_token: window.PTA_CONFIG.csrfToken,
|
||
agent_id: agentId,
|
||
source_week: sourceWeek,
|
||
target_week: targetWeek,
|
||
mode,
|
||
}),
|
||
});
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de dupliquer cette semaine.'));
|
||
setMessage(message, data.message || 'Semaine dupliquée.', 'success');
|
||
await load();
|
||
setMessage(document.querySelector('#agent-overview-message'), data.message || 'Semaine dupliquée.', 'success');
|
||
setTimeout(closeWeekCopyModal, 500);
|
||
} catch (error) {
|
||
setMessage(message, error.message, 'error');
|
||
} finally {
|
||
if (submit) submit.disabled = false;
|
||
}
|
||
}
|
||
|
||
async function load() {
|
||
const agentId = document.querySelector('#overview-agent')?.value;
|
||
const month = document.querySelector('#agent-overview-month')?.value;
|
||
const container = document.querySelector('#agent-overview-content');
|
||
const empty = document.querySelector('#agent-overview-empty');
|
||
if (!container || !empty) return;
|
||
|
||
if (!agentId || !month) {
|
||
empty.hidden = false;
|
||
empty.textContent = 'Choisissez un agent et un mois.';
|
||
container.hidden = true;
|
||
return;
|
||
}
|
||
|
||
setMessage(document.querySelector('#agent-overview-message'));
|
||
empty.hidden = false;
|
||
empty.textContent = 'Chargement du planning mensuel de l’agent…';
|
||
container.hidden = true;
|
||
|
||
try {
|
||
const params = new URLSearchParams({ agent_id: agentId, month });
|
||
const response = await fetch(`api/agent_month_overview.php?${params.toString()}`);
|
||
const data = await readJsonResponse(response);
|
||
if (!response.ok) throw new Error(apiErrorMessage(data, 'Impossible de charger la vue mensuelle de l’agent.'));
|
||
render(data);
|
||
} catch (error) {
|
||
empty.hidden = false;
|
||
empty.textContent = error.message;
|
||
}
|
||
}
|
||
|
||
function init() {
|
||
document.querySelector('#load-agent-overview')?.addEventListener('click', load);
|
||
document.querySelector('#overview-agent')?.addEventListener('change', load);
|
||
document.querySelector('#agent-overview-month')?.addEventListener('change', load);
|
||
|
||
document.querySelector('#agent-overview-content')?.addEventListener('click', (event) => {
|
||
if (event.target.closest('.agent-hours-contract-pdf')) {
|
||
openHoursContractPdf();
|
||
return;
|
||
}
|
||
if (event.target.closest('.agent-time-summary-pdf')) {
|
||
openTimeSummaryPdf();
|
||
return;
|
||
}
|
||
const copyButton = event.target.closest('.agent-copy-week');
|
||
if (copyButton && canCopyFullWeek) {
|
||
openWeekCopyModal(copyButton.dataset.sourceWeek || '');
|
||
return;
|
||
}
|
||
const editButton = event.target.closest('.overview-entry-edit');
|
||
if (editButton && canEditDraft) openModal(Number(editButton.dataset.entryId));
|
||
});
|
||
|
||
if (canEditDraft) {
|
||
document.querySelector('#agent-entry-edit-form')?.addEventListener('submit', saveEntry);
|
||
document.querySelector('#delete-agent-entry-edit')?.addEventListener('click', () => {
|
||
const entryId = Number(document.querySelector('#edit-agent-entry-id')?.value || 0);
|
||
if (entryId) deleteEntry(entryId);
|
||
});
|
||
document.querySelector('#close-agent-entry-modal')?.addEventListener('click', closeModal);
|
||
document.querySelector('#cancel-agent-entry-edit')?.addEventListener('click', closeModal);
|
||
document.querySelector('#agent-entry-modal')?.addEventListener('click', (event) => {
|
||
if (event.target.id === 'agent-entry-modal') closeModal();
|
||
});
|
||
}
|
||
|
||
if (canCopyFullWeek) {
|
||
document.querySelector('#agent-week-copy-form')?.addEventListener('submit', copyWeek);
|
||
document.querySelector('#close-agent-week-copy-modal')?.addEventListener('click', closeWeekCopyModal);
|
||
document.querySelector('#cancel-agent-week-copy')?.addEventListener('click', closeWeekCopyModal);
|
||
document.querySelector('#agent-week-copy-modal')?.addEventListener('click', (event) => {
|
||
if (event.target.id === 'agent-week-copy-modal') closeWeekCopyModal();
|
||
});
|
||
}
|
||
|
||
document.addEventListener('keydown', (event) => {
|
||
if (event.key !== 'Escape') return;
|
||
if (!document.querySelector('#agent-entry-modal')?.hidden) closeModal();
|
||
if (!document.querySelector('#agent-week-copy-modal')?.hidden) closeWeekCopyModal();
|
||
});
|
||
}
|
||
|
||
PTA.modules.agentOverview = { init, load };
|
||
})();
|