pour prod
This commit is contained in:
175
assets/js/core.js
Normal file
175
assets/js/core.js
Normal file
@@ -0,0 +1,175 @@
|
||||
(() => {
|
||||
'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(/<br\s*\/?\s*>/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,
|
||||
},
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user