(() => { 'use strict'; const elements = { structureSelect: document.querySelector('#structure'), agentSelect: document.querySelector('#agent'), weekInput: document.querySelector('#week'), weeklyEntryBody: document.querySelector('#weekly-entry-body'), addButton: document.querySelector('#add-entry'), saveButton: document.querySelector('#save-draft'), validateButton: document.querySelector('#validate-planning'), modifyButton: document.querySelector('#modify-planning'), planningBoard: document.querySelector('#planning-board'), emptyState: document.querySelector('#empty-state'), weekLabel: document.querySelector('#week-label'), workTotal: document.querySelector('#work-total'), statusBadge: document.querySelector('#planning-status'), messageBox: document.querySelector('#message'), openAgentPdfButton: document.querySelector('#open-agent-pdf'), openStructurePdfButton: document.querySelector('#open-structure-pdf'), quotaPanel: document.querySelector('#editor-quota'), quotaRate: document.querySelector('#quota-rate'), quotaTarget: document.querySelector('#quota-target'), quotaPeriod: document.querySelector('#quota-period'), quotaUsed: document.querySelector('#quota-used'), quotaUsedDetail: document.querySelector('#quota-used-detail'), quotaRemaining: document.querySelector('#quota-remaining'), }; const state = { entries: [], otherStructureEntries: [], currentStructure: null, planningId: null, planningStatus: null, weekDays: [], quota: null, savedCurrentCountedMinutes: 0, }; const shared = { lastAgentOverviewData: null, }; const dayNames = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi']; function escapeHtml(value) { const div = document.createElement('div'); div.textContent = String(value ?? ''); return div.innerHTML; } function showMessage(text, type = 'info') { if (!elements.messageBox) return; elements.messageBox.className = `message message-${type}`; elements.messageBox.textContent = text; } function clearMessage() { if (!elements.messageBox) return; elements.messageBox.className = 'message'; elements.messageBox.textContent = ''; } async function readJsonResponse(response) { const raw = await response.text(); if (!raw.trim()) { throw new Error(`Le serveur a renvoyé une réponse vide (HTTP ${response.status}).`); } try { return JSON.parse(raw); } catch (error) { const readable = raw .replace(//gi, ' ') .replace(/<[^>]+>/g, ' ') .replace(/ /gi, ' ') .replace(/"/gi, '"') .replace(/'/gi, "'") .replace(/</gi, '<') .replace(/>/gi, '>') .replace(/&/gi, '&') .replace(/\s+/g, ' ') .trim(); throw new Error( `Le serveur PHP n'a pas renvoyé du JSON valide. ${readable.slice(0, 500) || 'Consultez les logs PHP.'}` ); } } function apiErrorMessage(data, fallback) { const base = data?.error || fallback; return data?.details ? `${base} Détail : ${data.details}` : base; } function toIsoDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function parseIsoWeek(value) { const match = /^(\d{4})-W(\d{2})$/.exec(value); if (!match) return []; const year = Number(match[1]); const week = Number(match[2]); const jan4 = new Date(year, 0, 4); const jan4Day = jan4.getDay() || 7; const monday = new Date(jan4); monday.setDate(jan4.getDate() - jan4Day + 1 + (week - 1) * 7); return Array.from({ length: 5 }, (_, index) => { const date = new Date(monday); date.setDate(monday.getDate() + index); return { date: toIsoDate(date), label: dayNames[index], display: date.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit' }), }; }); } function timeToMinutes(time) { const [hours, minutes] = String(time).split(':').map(Number); return hours * 60 + minutes; } function formatDuration(minutes) { const sign = minutes < 0 ? '-' : ''; const absolute = Math.abs(Math.round(minutes)); const hours = Math.floor(absolute / 60); const mins = absolute % 60; return `${sign}${hours} h ${String(mins).padStart(2, '0')}`; } function formatDate(value) { if (!value) return ''; const [year, month, day] = String(value).split('-'); return `${day}/${month}/${year}`; } function motifInfo(id) { const motif = (window.PTA_CONFIG?.motifs || []).find((item) => Number(item.id) === Number(id)); return motif ? { id: Number(motif.id), code: motif.code, label: motif.label, quota: Boolean(motif.quota), } : null; } window.PTA = { config: window.PTA_CONFIG || {}, elements, state, shared, modules: {}, utils: { escapeHtml, showMessage, clearMessage, readJsonResponse, apiErrorMessage, parseIsoWeek, timeToMinutes, formatDuration, formatDate, motifInfo, }, }; })();