diff --git a/app/static/css/assiduites.css b/app/static/css/assiduites.css index 4fe7ee090..c935f4f83 100644 --- a/app/static/css/assiduites.css +++ b/app/static/css/assiduites.css @@ -36,10 +36,10 @@ .infos { position: relative; - width: fit-content; display: flex; - justify-content: space-evenly; + justify-content: start; align-content: center; + gap: 10px; } #datestr { @@ -48,7 +48,7 @@ border: 1px #444 solid; border-radius: 5px; padding: 5px; - min-width: 100px; + min-width: 250px; display: inline-block; min-height: 20px; } diff --git a/app/static/js/assiduites.js b/app/static/js/assiduites.js index 0c8edc610..a58592cc2 100644 --- a/app/static/js/assiduites.js +++ b/app/static/js/assiduites.js @@ -112,6 +112,7 @@ function validateSelectors(btn) { getAssiduitesFromEtuds(true); document.querySelector(".selectors").disabled = true; + $("#tl_date").datepicker("option", "disabled", true); generateMassAssiduites(); generateAllEtudRow(); btn.remove(); @@ -173,6 +174,7 @@ function uniqueCheckBox(box) { * @param {CallableFunction} errors fonction à effectuer en cas d'échec */ function sync_get(path, success, errors) { + //TODO Optimiser : rendre asynchrone + sans jquery console.log("sync_get " + path); $.ajax({ async: false, @@ -188,16 +190,21 @@ function sync_get(path, success, errors) { * @param {CallableFunction} success fonction à effectuer en cas de succès * @param {CallableFunction} errors fonction à effectuer en cas d'échec */ -function async_get(path, success, errors) { +async function async_get(path, success, errors) { console.log("async_get " + path); - $.ajax({ - async: true, - type: "GET", - url: path, - success: success, - error: errors, - }); + try { + const response = await fetch(path); + if (response.ok) { + const data = await response.json(); + success(data); + } else { + throw new Error("Network response was not ok."); + } + } catch (error) { + errors(error); + } } + /** * Fait une requête POST de façon synchrone * @param {String} path adresse distante @@ -206,6 +213,7 @@ function async_get(path, success, errors) { * @param {CallableFunction} errors fonction à effectuer en cas d'échec */ function sync_post(path, data, success, errors) { + //TODO Optimiser : rendre asynchrone + sans jquery console.log("sync_post " + path); $.ajax({ async: false, @@ -223,17 +231,28 @@ function sync_post(path, data, success, errors) { * @param {CallableFunction} success fonction à effectuer en cas de succès * @param {CallableFunction} errors fonction à effectuer en cas d'échec */ -function async_post(path, data, success, errors) { - console.log("sync_post " + path); - return $.ajax({ - async: true, - type: "POST", - url: path, - data: JSON.stringify(data), - success: success, - error: errors, - }); +async function async_post(path, data, success, errors) { + console.log("async_post " + path); + try { + const response = await fetch(path, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + + if (response.ok) { + const responseData = await response.json(); + success(responseData); + } else { + throw new Error("Network response was not ok."); + } + } catch (error) { + errors(error); + } } + // <<== Gestion des actions de masse ==>> const massActionQueue = new Map(); @@ -583,10 +602,13 @@ function formatDate(date, styles = { dateStyle: "full" }) { */ function updateDate() { const dateInput = document.querySelector("#tl_date"); + let date = $(dateInput).datepicker("getDate"); + + if (date == null) { + date = new Date(Date.fromFRA(dateInput.value)); + } - const date = dateInput.valueAsDate ?? new Date(); let dateStr = ""; - if (!verifyNonWorkDays(date.getDay(), nonWorkDays)) { dateStr = formatDate(date).capitalize(); } else { @@ -606,7 +628,11 @@ function updateDate() { ) ); openAlertModal("Attention", div, "", "#eec660"); - dateInput.value = lastWorkDay.toISOString().split("T")[0]; + $(dateInput).datepicker( + "setDate", + Date.toFRA(lastWorkDay.toIsoUtcString().split("T")[0]) + ); + dateStr = formatDate(lastWorkDay).capitalize(); } document.querySelector("#datestr").textContent = dateStr; @@ -639,15 +665,15 @@ function setupDate(onchange = null) { const input = document.querySelector("#tl_date"); datestr.addEventListener("click", () => { - if (!input.disabled) { + if (!document.querySelector(".selectors").disabled) { try { - input.showPicker(); + document.querySelector(".infos .ui-datepicker-trigger").click(); } catch {} } }); if (onchange != null) { - input.addEventListener("change", onchange); + $(input).change(onchange); } } @@ -726,7 +752,7 @@ function getTimeLineTimes() { //getPeriodValues() -> retourne la position de la timeline [a,b] avec a et b des number let values = getPeriodValues(); //On récupère la date - const dateiso = document.querySelector("#tl_date").value; + const dateiso = getDate().format("YYYY-MM-DD"); //On génère des objets temps values = values.map((el) => { @@ -757,9 +783,10 @@ function isConflictSameAsPeriod(conflict, period = undefined) { * @returns {Date} la date sélectionnée */ function getDate() { - const date = new Date(document.querySelector("#tl_date").value); - date.setHours(0, 0, 0, 0); - return date; + const date = + $("#tl_date").datepicker("getDate") ?? + new Date(Date.fromFRA(document.querySelector("#tl_date").value)); + return date.startOf("day"); } /** @@ -768,10 +795,7 @@ function getDate() { */ function getNextDate() { const date = getDate(); - const next = new Date(date.valueOf()); - next.setDate(date.getDate() + 1); - next.setHours(0, 0, 0, 0); - return next; + return date.clone().add(1, "days"); } /** * Retourne un objet date représentant le jour précédent @@ -779,10 +803,7 @@ function getNextDate() { */ function getPrevDate() { const date = getDate(); - const next = new Date(date.valueOf()); - next.setDate(date.getDate() - 1); - next.setHours(0, 0, 0, 0); - return next; + return date.clone().add(-1, "days"); } /** @@ -790,31 +811,6 @@ function getPrevDate() { * @param {Date} date * @returns {string} la date iso avec le timezone */ -function toIsoString(date) { - var tzo = -date.getTimezoneOffset(), - dif = tzo >= 0 ? "+" : "-", - pad = function (num) { - return (num < 10 ? "0" : "") + num; - }; - - return ( - date.getFullYear() + - "-" + - pad(date.getMonth() + 1) + - "-" + - pad(date.getDate()) + - "T" + - pad(date.getHours()) + - ":" + - pad(date.getMinutes()) + - ":" + - pad(date.getSeconds()) + - dif + - pad(Math.floor(Math.abs(tzo) / 60)) + - ":" + - pad(Math.abs(tzo) % 60) - ); -} /** * Transforme un temps numérique en une date @@ -823,7 +819,7 @@ function toIsoString(date) { */ function numberTimeToDate(nb) { time = toTime(nb).replace("h", ":"); - date = document.querySelector("#tl_date").value; + date = getDate().format("YYYY-MM-DD"); datetime = `${date}T${time}`; @@ -843,8 +839,8 @@ function numberTimeToDate(nb) { function getAssiduitesFromEtuds(clear, deb, fin) { const etudIds = Object.keys(etuds).join(","); - const date_debut = deb ? deb : toIsoString(getPrevDate()); - const date_fin = fin ? fin : toIsoString(getNextDate()); + const date_debut = deb ? deb : getPrevDate().toIsoUtcString(); + const date_fin = fin ? fin : getNextDate().toIsoUtcString(); if (clear) { assiduites = {}; @@ -1137,8 +1133,8 @@ function getAssiduiteValue(field) { * @param {String | Number} etudid identifiant de l'étudiant */ function actualizeEtudAssiduite(etudid) { - const date_debut = toIsoString(getPrevDate()); - const date_fin = toIsoString(getNextDate()); + const date_debut = getPrevDate().toIsoUtcString(); + const date_fin = getNextDate().toIsoUtcString(); const url_api = getUrl() + diff --git a/app/static/js/date_utils.js b/app/static/js/date_utils.js index 486de19ee..4a1d21d98 100644 --- a/app/static/js/date_utils.js +++ b/app/static/js/date_utils.js @@ -1,3 +1,53 @@ +/** + * Transforme une date du format français (DD/MM/YYYY) au format iso (YYYY-MM-DD) + * Exemple d'utilisation : + * new Date(Date.fromFRA("30/06/2024")) -> new Date("2024-06-30") + * @param {string} dateFra + * @returns {string} dateIso + */ +Date.fromFRA = function (dateFra) { + if (dateFra == "") return ""; + // Expression régulière pour valider le format de date ISO (YYYY-MM-DD) + const regexDateFra = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/; + + // Vérification du format de la date ISO + if (!regexDateFra.test(dateFra)) { + throw new Error( + `La date (format français) passée en paramètre [${dateFra}] n'est pas valide.` + ); + } + + // Conversion du format français (DD/MM/YYYY) au format ISO (YYYY-MM-DD) + return `${dateFra.substring(6, 10)}-${dateFra.substring( + 3, + 5 + )}-${dateFra.substring(0, 2)}`; +}; +/** + * Transforme une date du format iso (YYYY-MM-DD) au format français (DD/MM/YYYY) + * Exemple d'utilisation : + * Date.toFRA("2024-06-30") -> "30/06/2024" + * @param {string} dateIso + * @returns {string} dateFra + */ +Date.toFRA = function (dateIso) { + if (dateIso == "") return ""; + // Expression régulière pour valider le format de date ISO (YYYY-MM-DD) + const regexDateIso = /^\d{4}-(0\d|1[0-2])-([0-2]\d|3[01])$/; + + // Vérification du format de la date ISO + if (!regexDateIso.test(dateIso)) { + throw new Error( + `La date ISO passée en paramètre [${dateIso}] n'est pas valide.` + ); + } + + // Conversion du format ISO (YYYY-MM-DD) en format français (DD/MM/YYYY) + return `${dateIso.substring(8, 10)}/${dateIso.substring( + 5, + 7 + )}/${dateIso.substring(0, 4)}`; +}; Object.defineProperty(Date.prototype, "isValid", { value: function () { return !Number.isNaN(this.getTime()); @@ -175,6 +225,7 @@ Object.defineProperty(Date.prototype, "clone", { Object.defineProperty(Date.prototype, "format", { value: function (formatString) { + let iso = this.toIsoUtcString(); switch (formatString) { case "DD/MM/Y HH:mm": return this.toLocaleString("fr-FR", { @@ -196,10 +247,11 @@ Object.defineProperty(Date.prototype, "format", { }); case "YYYY-MM-DDTHH:mm": - let iso = this.toIsoUtcString(); // slice : YYYY-MM-DDTHH // slice + 3 : YYYY-MM-DDTHH:mm return iso.slice(0, iso.indexOf(":") + 3); + case "YYYY-MM-DD": + return iso.slice(0, iso.indexOf("T")); default: return this.toIsoUtcString(); } diff --git a/app/templates/assiduites/pages/bilan_etud.j2 b/app/templates/assiduites/pages/bilan_etud.j2 index 304adf221..a1c3d0df4 100644 --- a/app/templates/assiduites/pages/bilan_etud.j2 +++ b/app/templates/assiduites/pages/bilan_etud.j2 @@ -12,10 +12,10 @@