2024-03-11 11:39:06 +01:00
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* Ensemble des fonctions liées à la gestion des assiduités
|
|
|
|
|
* Créé par : HARTMANN Matthias (Iziram)
|
|
|
|
|
*
|
|
|
|
|
*/
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
/**
|
|
|
|
|
* <== OUTILS ==>
|
|
|
|
|
*/
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Ajout d'une fonction `capitalize` sur tous les strings
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* "alice".capitalize() -> "Alice"
|
2023-04-17 15:44:55 +02:00
|
|
|
|
*/
|
|
|
|
|
Object.defineProperty(String.prototype, "capitalize", {
|
|
|
|
|
value: function () {
|
|
|
|
|
return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
|
|
|
|
|
},
|
|
|
|
|
enumerable: false,
|
|
|
|
|
});
|
2023-11-03 16:55:26 +01:00
|
|
|
|
|
2023-06-22 16:25:13 +02:00
|
|
|
|
/**
|
|
|
|
|
* Fait une requête GET de façon asynchrone
|
|
|
|
|
* @param {String} path adresse distante
|
|
|
|
|
* @param {CallableFunction} success fonction à effectuer en cas de succès
|
|
|
|
|
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
|
|
|
|
*/
|
2023-11-15 14:11:47 +01:00
|
|
|
|
async function async_get(path, success, errors) {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const response = fetch(path);
|
|
|
|
|
response
|
|
|
|
|
.then((response) => {
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
response.json().then((data) => {
|
|
|
|
|
success(data, "success");
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error("Network response was not ok.");
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
console.error(error);
|
|
|
|
|
if (errors) errors(error);
|
|
|
|
|
});
|
2023-11-17 13:50:49 +01:00
|
|
|
|
|
|
|
|
|
return response;
|
2023-06-22 16:25:13 +02:00
|
|
|
|
}
|
2023-06-12 17:54:30 +02:00
|
|
|
|
/**
|
|
|
|
|
* Fait une requête POST de façon asynchrone
|
|
|
|
|
* @param {String} path adresse distante
|
|
|
|
|
* @param {object} data données à envoyer (objet js)
|
|
|
|
|
* @param {CallableFunction} success fonction à effectuer en cas de succès
|
|
|
|
|
* @param {CallableFunction} errors fonction à effectuer en cas d'échec
|
|
|
|
|
*/
|
2023-11-15 14:11:47 +01:00
|
|
|
|
async function async_post(path, data, success, errors) {
|
2023-11-17 13:50:49 +01:00
|
|
|
|
let response;
|
2023-11-15 14:11:47 +01:00
|
|
|
|
try {
|
2023-11-17 13:50:49 +01:00
|
|
|
|
response = await fetch(path, {
|
2023-11-15 14:11:47 +01:00
|
|
|
|
method: "POST",
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify(data),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
const responseData = await response.json();
|
|
|
|
|
success(responseData);
|
|
|
|
|
} else {
|
2024-05-29 15:59:19 +02:00
|
|
|
|
if (response.status == 404) {
|
|
|
|
|
response.json().then((data) => {
|
|
|
|
|
if (errors) errors(data);
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error("Network response was not ok.");
|
|
|
|
|
}
|
2023-11-15 14:11:47 +01:00
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2023-11-15 17:34:13 +01:00
|
|
|
|
console.error(error);
|
|
|
|
|
if (errors) errors(error);
|
2023-11-15 14:11:47 +01:00
|
|
|
|
}
|
2023-11-17 13:50:49 +01:00
|
|
|
|
|
|
|
|
|
return response;
|
2023-06-12 17:54:30 +02:00
|
|
|
|
}
|
2023-11-15 14:11:47 +01:00
|
|
|
|
|
2023-04-17 15:44:55 +02:00
|
|
|
|
/**
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* Récupère les étudiants en fonction des groupes sélectionnés
|
|
|
|
|
* @param {Array} groupIds - Les identifiants des groupes pour lesquels récupérer les étudiants.
|
|
|
|
|
* @returns {Promise<Object>} Un objet contenant les étudiants, indexés par leur identifiant.
|
2023-04-17 15:44:55 +02:00
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function recupEtuds(groupIds) {
|
|
|
|
|
const etuds = new Map();
|
|
|
|
|
if (groupIds == null || groupIds.length == 0) return etuds;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// Créer un tableau de promesses pour chaque requête GET asynchrone.
|
|
|
|
|
let requests = groupIds.map((groupId) =>
|
|
|
|
|
fetch(`../../api/group/${groupId}/etudiants`)
|
|
|
|
|
.then((response) => {
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error("Network response was not ok");
|
2023-06-13 16:25:45 +02:00
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return response.json();
|
|
|
|
|
})
|
|
|
|
|
.then((data) => {
|
|
|
|
|
data.forEach((etud) => {
|
|
|
|
|
etuds.set(etud.id, etud);
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch((error) =>
|
|
|
|
|
console.error(
|
|
|
|
|
"There has been a problem with your fetch operation:",
|
|
|
|
|
error
|
|
|
|
|
)
|
2023-10-24 10:49:29 +02:00
|
|
|
|
)
|
2024-01-21 22:11:07 +01:00
|
|
|
|
);
|
2024-01-21 22:02:10 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// Attendre que toutes les promesses dans le tableau `requests` soient résolues.
|
|
|
|
|
await Promise.all(requests);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return etuds;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
|
|
|
|
/**
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* Récupère l'assiduité des étudiants pour une date donnée
|
|
|
|
|
* @param {Map} etuds
|
2023-04-17 15:44:55 +02:00
|
|
|
|
* @param {Date} date
|
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function recupAssiduites(etuds, date) {
|
|
|
|
|
const etudIds = [...etuds.keys()].join(",");
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const date_debut = date.add(-1, "days").format("YYYY-MM-DDTHH:mm");
|
|
|
|
|
const date_fin = date.add(2, "days").format("YYYY-MM-DDTHH:mm");
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
url =
|
|
|
|
|
`../../api/assiduites/group/query?date_debut=${date_debut}` +
|
|
|
|
|
`&date_fin=${date_fin}&etudids=${etudIds}&with_justifs`;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
await fetch(url)
|
|
|
|
|
.then((res) => {
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
throw new Error("Network response was not ok");
|
2023-10-26 15:52:53 +02:00
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return res.json();
|
2023-04-17 15:44:55 +02:00
|
|
|
|
})
|
2024-03-11 11:39:06 +01:00
|
|
|
|
.then((data) => {
|
|
|
|
|
Object.keys(data).forEach((etudid) => {
|
|
|
|
|
const etud = etuds.get(Number(etudid));
|
|
|
|
|
const assiduites = data[etudid];
|
|
|
|
|
etud.assiduites = assiduites;
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch((error) =>
|
|
|
|
|
console.error(
|
|
|
|
|
"There has been a problem with your fetch operation:",
|
|
|
|
|
error
|
|
|
|
|
)
|
|
|
|
|
);
|
2023-04-20 18:04:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-17 15:44:55 +02:00
|
|
|
|
/**
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* Génération ligne étudiante
|
2023-04-17 15:44:55 +02:00
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function creerLigneEtudiant(etud, index) {
|
|
|
|
|
let currentAssiduite = {
|
|
|
|
|
etat: "",
|
|
|
|
|
type: "creation",
|
|
|
|
|
assiduite_id: -1,
|
|
|
|
|
date_debut: null,
|
|
|
|
|
date_fin: null,
|
|
|
|
|
};
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
/**Retourne une liste d'assiduité en conflit avec la période actuelle
|
|
|
|
|
* @param {Array} assiduites - Les assiduités de l'étudiant
|
|
|
|
|
* @returns {Array} Les assiduités en conflit
|
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function recupConflitsAssiduites(assiduites) {
|
|
|
|
|
const period = getPeriodAsDate();
|
2023-06-13 16:25:45 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return assiduites.filter((assi) => {
|
|
|
|
|
const interval = {
|
|
|
|
|
deb: new Date(Date.removeUTC(assi.date_debut)),
|
|
|
|
|
fin: new Date(Date.removeUTC(assi.date_fin)),
|
|
|
|
|
};
|
2023-06-13 16:25:45 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return (
|
|
|
|
|
period.deb.isBefore(interval.fin) && period.fin.isAfter(interval.deb)
|
2023-06-14 17:53:19 +02:00
|
|
|
|
);
|
2024-03-11 11:39:06 +01:00
|
|
|
|
});
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Pas de conflit en readonly
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const conflits = readOnly ? [] : recupConflitsAssiduites(etud.assiduites);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Si il y a des conflits, on prend le premier pour l'afficher
|
|
|
|
|
// si les dates de début et de fin sont les mêmes, c'est une édition
|
|
|
|
|
// sinon c'est un conflit
|
2024-03-11 11:39:06 +01:00
|
|
|
|
if (conflits.length > 0) {
|
|
|
|
|
currentAssiduite = conflits[0];
|
|
|
|
|
|
|
|
|
|
const conflitsPeriode = {
|
|
|
|
|
deb: new Date(Date.removeUTC(currentAssiduite.date_debut)),
|
|
|
|
|
fin: new Date(Date.removeUTC(currentAssiduite.date_fin)),
|
|
|
|
|
};
|
|
|
|
|
const period = getPeriodAsDate();
|
|
|
|
|
currentAssiduite.type =
|
|
|
|
|
period.deb.isSame(conflitsPeriode.deb) &&
|
|
|
|
|
period.fin.isSame(conflitsPeriode.fin)
|
|
|
|
|
? "edition"
|
|
|
|
|
: "conflit";
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
2023-07-25 19:59:47 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Création de la ligne étudiante en DOM
|
|
|
|
|
/* exemple de ligne étudiante
|
|
|
|
|
<div class="etud_row" id="etud_row_497">
|
|
|
|
|
<div class="index">1</div>
|
|
|
|
|
<div class="name_field"><img src="../../api/etudiant/etudid/497/photo?size=small" alt="Baudin Joseph" class="pdp"><a
|
|
|
|
|
class="name_set" href="bilan_etud?etudid=497">
|
|
|
|
|
<h4 class="nom">Baudin</h4>
|
|
|
|
|
<h5 class="prenom">Joseph</h5>
|
|
|
|
|
</a></div>
|
|
|
|
|
<div class="assiduites_bar">
|
|
|
|
|
<div id="prevDateAssi" class="vide"></div>
|
|
|
|
|
<div class="mini-timeline"><span class="mini_tick" style="left: 47.5%;">13h</span>
|
|
|
|
|
<div class="mini-timeline-block creneau" style="left: 20%; width: 17.5%;"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<fieldset class="btns_field single" etudid="497" type="creation" assiduite_id="-1">
|
2024-09-24 19:23:42 +02:00
|
|
|
|
<input
|
2024-06-11 14:50:30 +02:00
|
|
|
|
type="checkbox"
|
|
|
|
|
value="present"
|
|
|
|
|
name="btn_assiduites_1"
|
2024-09-24 19:23:42 +02:00
|
|
|
|
id="rbtn_present"
|
2024-06-11 14:50:30 +02:00
|
|
|
|
class="rbtn present"
|
|
|
|
|
title="present"
|
|
|
|
|
>
|
2024-09-24 19:23:42 +02:00
|
|
|
|
<input
|
2024-06-11 14:50:30 +02:00
|
|
|
|
type="checkbox"
|
|
|
|
|
value="retard"
|
|
|
|
|
name="btn_assiduites_1"
|
2024-09-24 19:23:42 +02:00
|
|
|
|
id="rbtn_retard"
|
2024-06-11 14:50:30 +02:00
|
|
|
|
class="rbtn retard"
|
|
|
|
|
title="retard"
|
|
|
|
|
>
|
2024-09-24 19:23:42 +02:00
|
|
|
|
<input
|
2024-06-11 14:50:30 +02:00
|
|
|
|
type="checkbox"
|
|
|
|
|
value="absent"
|
|
|
|
|
name="btn_assiduites_1"
|
2024-09-24 19:23:42 +02:00
|
|
|
|
id="rbtn_absent"
|
2024-06-11 14:50:30 +02:00
|
|
|
|
class="rbtn absent"
|
|
|
|
|
title="absent"
|
|
|
|
|
>
|
|
|
|
|
</fieldset>
|
|
|
|
|
</div>
|
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const ligneEtud = document.createElement("div");
|
|
|
|
|
ligneEtud.classList.add("etud_row");
|
|
|
|
|
if (Object.keys(etudsDefDem).includes(etud.id)) {
|
|
|
|
|
ligneEtud.classList.add(etudsDefDem[etud.id] == "D" ? "dem" : "def");
|
|
|
|
|
}
|
|
|
|
|
ligneEtud.id = `etud_row_${etud.id}`;
|
2023-07-25 19:59:47 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
if (currentAssiduite.type === "conflit" && !readOnly)
|
|
|
|
|
ligneEtud.classList.add("conflit");
|
2023-07-25 19:59:47 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// div index avec l'index
|
|
|
|
|
const indexDiv = document.createElement("div");
|
|
|
|
|
indexDiv.classList.add("index");
|
2024-08-23 16:09:46 +02:00
|
|
|
|
indexDiv.id = `etudid-${etud.id}`;
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
indexDiv.textContent = index;
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
ligneEtud.appendChild(indexDiv);
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// div name_field
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const nameField = document.createElement("div");
|
|
|
|
|
nameField.classList.add("name_field");
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-26 09:02:55 +01:00
|
|
|
|
const pdp = document.createElement("img");
|
|
|
|
|
pdp.src = `../../api/etudiant/etudid/${etud.id}/photo?size=small`;
|
|
|
|
|
pdp.alt = `${etud.nom} ${etud.prenom}`;
|
|
|
|
|
pdp.classList.add("pdp");
|
|
|
|
|
nameField.appendChild(pdp);
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const nameSet = document.createElement("a");
|
|
|
|
|
nameSet.classList.add("name_set");
|
2024-08-23 16:09:46 +02:00
|
|
|
|
nameSet.id = `etudid-${etud.id}`;
|
2024-03-11 11:39:06 +01:00
|
|
|
|
nameSet.href = `bilan_etud?etudid=${etud.id}`;
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const nom = document.createElement("h4");
|
|
|
|
|
nom.classList.add("nom");
|
|
|
|
|
nom.textContent = etud.nom;
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const prenom = document.createElement("h5");
|
|
|
|
|
prenom.classList.add("prenom");
|
|
|
|
|
prenom.textContent = etud.prenom;
|
2023-11-08 23:19:58 +01:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
nameSet.appendChild(nom);
|
|
|
|
|
nameSet.appendChild(prenom);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
nameField.appendChild(nameSet);
|
|
|
|
|
ligneEtud.appendChild(nameField);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// div assiduites_bar
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const assiduitesBar = document.createElement("div");
|
|
|
|
|
assiduitesBar.classList.add("assiduites_bar");
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const prevDateAssi = document.createElement("div");
|
|
|
|
|
prevDateAssi.id = "prevDateAssi";
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function recupDerniereAssiduite(assiduites) {
|
|
|
|
|
const period = {
|
|
|
|
|
deb: $("#date").datepicker("getDate").add(-1, "days"),
|
|
|
|
|
fin: $("#date").datepicker("getDate"),
|
|
|
|
|
};
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const lastAssiduite = assiduites
|
|
|
|
|
.filter((assi) => {
|
|
|
|
|
const interval = {
|
|
|
|
|
deb: new Date(Date.removeUTC(assi.date_debut)),
|
|
|
|
|
fin: new Date(Date.removeUTC(assi.date_fin)),
|
|
|
|
|
};
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return (
|
|
|
|
|
period.deb.isBefore(interval.fin) && period.fin.isAfter(interval.deb)
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.sort((a, b) => {
|
|
|
|
|
return (
|
|
|
|
|
new Date(Date.removeUTC(b.date_debut)) -
|
|
|
|
|
new Date(Date.removeUTC(a.date_debut))
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.pop();
|
|
|
|
|
|
|
|
|
|
return lastAssiduite ?? null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lastAssiduite = recupDerniereAssiduite(etud.assiduites);
|
|
|
|
|
prevDateAssi.classList.add(lastAssiduite?.etat.toLowerCase() ?? "vide");
|
|
|
|
|
setupAssiduiteBubble(prevDateAssi, lastAssiduite);
|
|
|
|
|
assiduitesBar.appendChild(prevDateAssi);
|
|
|
|
|
|
|
|
|
|
// div minitimeline
|
|
|
|
|
assiduitesBar.appendChild(createMiniTimeline(etud.assiduites));
|
|
|
|
|
ligneEtud.appendChild(assiduitesBar);
|
|
|
|
|
|
|
|
|
|
// fieldset btns_field single
|
|
|
|
|
const btnsField = document.createElement("fieldset");
|
|
|
|
|
btnsField.classList.add("btns_field", "single");
|
|
|
|
|
btnsField.setAttribute("etudid", etud.id);
|
|
|
|
|
btnsField.setAttribute("type", currentAssiduite.type);
|
|
|
|
|
btnsField.setAttribute("assiduite_id", currentAssiduite.assiduite_id);
|
|
|
|
|
|
|
|
|
|
// Création des boutons d'assiduités
|
|
|
|
|
if (readOnly) {
|
|
|
|
|
} else if (currentAssiduite.type != "conflit") {
|
2024-04-22 15:05:31 +02:00
|
|
|
|
const etats = ["retard", "absent"];
|
|
|
|
|
|
|
|
|
|
if (!window.nonPresent) {
|
|
|
|
|
etats.splice(0, 0, "present");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
etats.forEach((abs) => {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const btn = document.createElement("input");
|
|
|
|
|
btn.type = "checkbox";
|
|
|
|
|
btn.value = abs;
|
|
|
|
|
btn.name = `btn_assiduites_${index}`;
|
|
|
|
|
btn.id = `rbtn_${abs}`;
|
|
|
|
|
btn.classList.add("rbtn", abs);
|
|
|
|
|
btn.title = abs;
|
|
|
|
|
|
|
|
|
|
btn.checked = abs === currentAssiduite?.etat.toLowerCase();
|
|
|
|
|
|
|
|
|
|
// Une seule checkbox à la fois
|
|
|
|
|
btn.addEventListener("click", () => {
|
|
|
|
|
Array.from(btn.parentElement.children).forEach((chbox) => {
|
|
|
|
|
if (chbox.checked && chbox.value !== btn.value) {
|
|
|
|
|
chbox.checked = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// Action au clic
|
|
|
|
|
btn.addEventListener("click", (e) => {
|
|
|
|
|
actionAssiduite(
|
|
|
|
|
etud,
|
|
|
|
|
btn.value,
|
|
|
|
|
currentAssiduite.type,
|
|
|
|
|
currentAssiduite.type == "edition" ? currentAssiduite : null
|
|
|
|
|
);
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
});
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
btnsField.appendChild(btn);
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
const btn = document.createElement("input");
|
|
|
|
|
btn.type = "checkbox";
|
|
|
|
|
btn.value = "conflit";
|
|
|
|
|
btn.name = `btn_assiduites_${index}`;
|
|
|
|
|
btn.id = `rbtn_conflit`;
|
|
|
|
|
btn.classList.add("rbtn", "conflit");
|
|
|
|
|
btn.title = "conflit";
|
|
|
|
|
|
|
|
|
|
// TODO : Ouvrir solveur
|
|
|
|
|
|
|
|
|
|
const solveur = new ConflitResolver(etud.assiduites, getPeriodAsDate(), {
|
|
|
|
|
deb: $("#date").datepicker("getDate"),
|
|
|
|
|
fin: $("#date").datepicker("getDate").add(1, "days"),
|
|
|
|
|
});
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const update = () => {
|
|
|
|
|
MiseAJourLigneEtud(etud);
|
|
|
|
|
};
|
2023-10-23 14:56:18 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
solveur.callbacks = {
|
|
|
|
|
delete: update,
|
|
|
|
|
edit: update,
|
|
|
|
|
split: update,
|
|
|
|
|
};
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
btn.addEventListener("click", () => {
|
|
|
|
|
solveur.open();
|
|
|
|
|
btn.checked = false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
btnsField.appendChild(btn);
|
|
|
|
|
}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
ligneEtud.appendChild(btnsField);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-08-23 16:09:46 +02:00
|
|
|
|
// Attache les infos de l'étudiant (bulle etud_info)
|
|
|
|
|
try {
|
|
|
|
|
attach_etud_info(nameSet);
|
|
|
|
|
attach_etud_info(indexDiv);
|
|
|
|
|
} catch {}
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return ligneEtud;
|
|
|
|
|
}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
|
|
|
|
/**
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* Génération de toutes les lignes étudiantes
|
2023-04-17 15:44:55 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function creerTousLesEtudiants(etuds) {
|
|
|
|
|
const etudsDiv = document.querySelector(".etud_holder");
|
|
|
|
|
etudsDiv.innerHTML = "";
|
|
|
|
|
const moduleImplId = readOnly ? null : $("#moduleimpl_select").val();
|
|
|
|
|
const inscriptions = await getInscriptionModule(moduleImplId);
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// on trie les étudiants par ordre alphabétique
|
|
|
|
|
// et on garde ceux qui sont inscrits au module
|
|
|
|
|
// puis pour chaque étudiant on crée une ligne
|
2024-03-11 11:39:06 +01:00
|
|
|
|
[...etuds.values()]
|
|
|
|
|
.sort((a, b) => {
|
|
|
|
|
return a.sort_key > b.sort_key ? 1 : -1;
|
|
|
|
|
})
|
|
|
|
|
.filter((etud) => {
|
|
|
|
|
return inscriptions == null || inscriptions.includes(etud.id);
|
|
|
|
|
})
|
|
|
|
|
.forEach((etud, index) => {
|
|
|
|
|
etudsDiv.appendChild(creerLigneEtudiant(etud, index + 1));
|
|
|
|
|
});
|
2024-10-29 16:40:42 +01:00
|
|
|
|
// Récupère l'offset timezone serveur pour la date sélectionnée
|
|
|
|
|
const date_iso = getSelectedDateIso();
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`../../api/assiduite/date_time_offset/${date_iso}`);
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
throw new Error("Network response was not ok");
|
|
|
|
|
}
|
|
|
|
|
const text = await res.text();
|
|
|
|
|
SERVER_TIMEZONE_OFFSET = text;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* Récupère une version lisible du moduleimpl
|
|
|
|
|
* @param {Object} assiduite
|
|
|
|
|
* @returns {String}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function getModuleImpl(assiduite) {
|
2024-05-24 16:51:44 +02:00
|
|
|
|
if (assiduite == null) return "Module non spécifié";
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const id = assiduite.moduleimpl_id;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
if (id == null || id == undefined) {
|
2023-08-11 16:14:29 +02:00
|
|
|
|
if (
|
2023-09-05 09:25:51 +02:00
|
|
|
|
assiduite.hasOwnProperty("external_data") &&
|
2024-03-11 11:39:06 +01:00
|
|
|
|
assiduite.external_data != null &&
|
|
|
|
|
assiduite.external_data.hasOwnProperty("module")
|
2023-08-11 16:14:29 +02:00
|
|
|
|
) {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return assiduite.external_data.module == "Autre"
|
|
|
|
|
? "Autre module (pas dans la liste)"
|
|
|
|
|
: assiduite.external_data.module;
|
2023-07-04 15:04:58 +02:00
|
|
|
|
} else {
|
2024-05-24 16:51:44 +02:00
|
|
|
|
return "Module non spécifié";
|
2023-07-04 15:04:58 +02:00
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (id in moduleimpls) {
|
|
|
|
|
return moduleimpls[id];
|
|
|
|
|
}
|
|
|
|
|
const url_api = `../../api/moduleimpl/${id}`;
|
|
|
|
|
|
|
|
|
|
return await fetch(url_api)
|
|
|
|
|
.then((res) => {
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
throw new Error("Network response was not ok");
|
|
|
|
|
}
|
|
|
|
|
return res.json();
|
|
|
|
|
})
|
|
|
|
|
.then((data) => {
|
2024-04-22 11:24:16 +02:00
|
|
|
|
moduleimpls[id] = `${data.module.code} ${data.module.abbrev || ""}`;
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return moduleimpls[id];
|
|
|
|
|
})
|
|
|
|
|
.catch((_) => {
|
|
|
|
|
moduleimpls[id] = "Pas de module";
|
|
|
|
|
return moduleimpls[id];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Renvoie le moduleimpl_id de l'assiduité
|
|
|
|
|
* ou l'external_data.module si le moduleimpl_id n'est pas défini
|
|
|
|
|
* "" si aucun module n'est défini
|
|
|
|
|
* @param {Object} assiduite
|
|
|
|
|
* @returns {String}
|
|
|
|
|
*/
|
|
|
|
|
function getModuleImplId(assiduite) {
|
|
|
|
|
const id = assiduite.moduleimpl_id;
|
|
|
|
|
if (id == null || id == undefined) {
|
2023-08-11 16:14:29 +02:00
|
|
|
|
if (
|
2023-09-05 09:25:51 +02:00
|
|
|
|
assiduite.hasOwnProperty("external_data") &&
|
2024-03-11 11:39:06 +01:00
|
|
|
|
assiduite.external_data != null &&
|
|
|
|
|
assiduite.external_data.hasOwnProperty("module")
|
2023-08-11 16:14:29 +02:00
|
|
|
|
) {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return assiduite.external_data.module.toLowerCase();
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
2023-07-31 09:41:32 +02:00
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
} else {
|
|
|
|
|
return id + "";
|
2023-07-04 15:04:58 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
/**
|
2024-03-11 11:39:06 +01:00
|
|
|
|
* Récupère les etudid de tous les étudiants inscrits au module
|
|
|
|
|
* @param {String} moduleimpl_id
|
|
|
|
|
* @returns {Array}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
*/
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function getInscriptionModule(moduleimpl_id) {
|
|
|
|
|
if ([null, "", "autre"].includes(moduleimpl_id)) return null;
|
|
|
|
|
if (!inscriptionsModules.has(moduleimpl_id)) {
|
|
|
|
|
const path = `../../api/moduleimpl/${moduleimpl_id}/inscriptions`;
|
|
|
|
|
await fetch(path)
|
|
|
|
|
.then((res) => {
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
throw new Error("Network response was not ok");
|
|
|
|
|
}
|
|
|
|
|
return res.json();
|
|
|
|
|
})
|
|
|
|
|
.then((data) => {
|
|
|
|
|
inscriptionsModules.set(
|
|
|
|
|
moduleimpl_id,
|
|
|
|
|
data.map((i) => i.etudid)
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.catch((_) => {
|
|
|
|
|
inscriptionsModules.set(moduleimpl_id, []);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return inscriptionsModules.get(moduleimpl_id);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Mise à jour de la ligne étudiant
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function MiseAJourLigneEtud(etud) {
|
|
|
|
|
//Récupérer ses assiduités
|
|
|
|
|
function RecupAssiduitesEtudiant(etudid) {
|
|
|
|
|
const date = $("#date").datepicker("getDate");
|
|
|
|
|
const date_debut = date.add(-1, "days").format("YYYY-MM-DDTHH:mm");
|
|
|
|
|
const date_fin = date.add(2, "days").format("YYYY-MM-DDTHH:mm");
|
|
|
|
|
url =
|
|
|
|
|
`../../api/assiduites/${etudid}/query?date_debut=${date_debut}` +
|
|
|
|
|
`&date_fin=${date_fin}&with_justifs`;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return fetch(url)
|
|
|
|
|
.then((res) => {
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
throw new Error("Network response was not ok");
|
|
|
|
|
}
|
|
|
|
|
return res.json();
|
|
|
|
|
})
|
|
|
|
|
.then((data) => {
|
|
|
|
|
etud.assiduites = data;
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
console.error(
|
|
|
|
|
"There has been a problem with your fetch operation:",
|
|
|
|
|
error
|
|
|
|
|
);
|
|
|
|
|
});
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
await RecupAssiduitesEtudiant(etud.id);
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Une fois les assiduités récupérées, on met à jour la ligne étudiant
|
|
|
|
|
// on replace l'ancienne ligne par la nouvellement générée
|
2024-03-11 11:39:06 +01:00
|
|
|
|
|
|
|
|
|
const etudRow = document.getElementById(`etud_row_${etud.id}`);
|
|
|
|
|
if (etudRow == null) return;
|
|
|
|
|
|
|
|
|
|
const ligneEtud = creerLigneEtudiant(
|
|
|
|
|
etud,
|
|
|
|
|
document.querySelector(`#etud_row_${etud.id}`).querySelector(".index")
|
|
|
|
|
.textContent
|
2023-04-17 15:44:55 +02:00
|
|
|
|
);
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
etudRow.replaceWith(ligneEtud);
|
|
|
|
|
}
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Action appelée lors d'un clic sur un bouton d'assiduité
|
|
|
|
|
// Création, édition ou suppression d'une assiduité
|
2024-03-11 11:39:06 +01:00
|
|
|
|
async function actionAssiduite(etud, etat, type, assiduite = null) {
|
|
|
|
|
const modimpl_id = $("#moduleimpl_select").val();
|
2024-04-22 11:24:16 +02:00
|
|
|
|
if (assiduite && assiduite.etat.toLowerCase() === etat) type = "suppression";
|
2024-03-11 11:39:06 +01:00
|
|
|
|
|
2024-10-29 16:40:42 +01:00
|
|
|
|
const { deb, fin } = getPeriodAsISO(); // chaines sans timezone pour l'API
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// génération d'un objet assiduité basique qui sera complété
|
2024-03-11 11:39:06 +01:00
|
|
|
|
let assiduiteObjet = assiduite ?? {
|
|
|
|
|
date_debut: deb,
|
|
|
|
|
date_fin: fin,
|
|
|
|
|
etudid: etud.id,
|
|
|
|
|
};
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
assiduiteObjet.etat = etat;
|
|
|
|
|
assiduiteObjet.moduleimpl_id = modimpl_id;
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// En fonction du type d'action on appelle la bonne route
|
|
|
|
|
// avec les bonnes valeurs
|
2024-03-11 11:39:06 +01:00
|
|
|
|
if (type === "creation") {
|
|
|
|
|
await async_post(
|
|
|
|
|
`../../api/assiduite/${etud.id}/create`,
|
|
|
|
|
[assiduiteObjet],
|
|
|
|
|
(data) => {
|
|
|
|
|
if (data.success.length > 0) {
|
|
|
|
|
MiseAJourLigneEtud(etud);
|
|
|
|
|
envoiToastEtudiant(etat, etud);
|
|
|
|
|
} else {
|
|
|
|
|
console.error(data.errors["0"].message);
|
|
|
|
|
erreurModuleImpl(data.errors["0"].message);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
console.error("Erreur lors de la création de l'assiduité", error);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
);
|
|
|
|
|
} else if (type === "edition") {
|
|
|
|
|
await async_post(
|
|
|
|
|
`../../api/assiduite/${assiduite.assiduite_id}/edit`,
|
|
|
|
|
{
|
|
|
|
|
etat: assiduiteObjet.etat,
|
|
|
|
|
moduleimpl_id: assiduiteObjet.moduleimpl_id,
|
|
|
|
|
},
|
|
|
|
|
(data) => {
|
|
|
|
|
MiseAJourLigneEtud(etud);
|
|
|
|
|
envoiToastEtudiant(etat, etud);
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
console.error("Erreur lors de la modification de l'assiduité", error);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
} else if (type === "suppression") {
|
|
|
|
|
await async_post(
|
|
|
|
|
`../../api/assiduite/delete`,
|
|
|
|
|
[assiduite.assiduite_id],
|
|
|
|
|
(data) => {
|
|
|
|
|
if (data.success.length > 0) {
|
|
|
|
|
MiseAJourLigneEtud(etud);
|
|
|
|
|
envoiToastEtudiant("remove", etud);
|
|
|
|
|
} else {
|
|
|
|
|
console.error(data.errors["0"].message);
|
|
|
|
|
erreurModuleImpl(data.errors["0"].message);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
console.error("Erreur lors de la suppression de l'assiduité", error);
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Fonction pour afficher un message d'erreur si le module n'est pas renseigné
|
|
|
|
|
// ou si l'étudiant n'est pas inscrit au module.
|
|
|
|
|
// On donne le message d'erreur d'une requête api et cela affiche le message correspondant
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function erreurModuleImpl(message) {
|
|
|
|
|
if (message == "Module non renseigné") {
|
|
|
|
|
const HTML = `
|
|
|
|
|
<p>Attention, le module doit obligatoirement être renseigné.</p>
|
|
|
|
|
<p>Cela vient de la configuration du semestre ou plus largement du département.</p>
|
|
|
|
|
<p>Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.</p>
|
|
|
|
|
`;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const content = document.createElement("div");
|
|
|
|
|
content.innerHTML = HTML;
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
openAlertModal("Sélection du module", content);
|
2023-10-23 11:27:42 +02:00
|
|
|
|
}
|
2024-05-29 15:59:19 +02:00
|
|
|
|
if (
|
|
|
|
|
message == "L'étudiant n'est pas inscrit au module" ||
|
|
|
|
|
message == "param 'moduleimpl_id': etud non inscrit"
|
|
|
|
|
) {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const HTML = `
|
|
|
|
|
<p>Attention, l'étudiant n'est pas inscrit à ce module.</p>
|
|
|
|
|
<p>Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.</p>
|
|
|
|
|
`;
|
2023-10-23 11:27:42 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const content = document.createElement("div");
|
|
|
|
|
content.innerHTML = HTML;
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
openAlertModal("Sélection du module", content);
|
|
|
|
|
}
|
2024-10-06 16:05:48 +02:00
|
|
|
|
if (
|
|
|
|
|
message == "La date de début n'est pas un jour travaillé"
|
|
|
|
|
) {
|
|
|
|
|
const HTML = `
|
|
|
|
|
<p>Attention, la date de début n'est pas un jour travaillé.</p>
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const content = document.createElement("div");
|
|
|
|
|
content.innerHTML = HTML;
|
|
|
|
|
|
|
|
|
|
openAlertModal("Date de début", content);
|
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Fonction pour ajouter en lot une assiduité à tous les étudiants
|
|
|
|
|
// Fonctionne uniquement pour créer ou supprimer des assiduités
|
|
|
|
|
// Pas d'édition possible
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function mettreToutLeMonde(etat, el = null) {
|
|
|
|
|
const lignesEtuds = [...document.querySelectorAll("fieldset.btns_field")];
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-09-24 19:23:42 +02:00
|
|
|
|
const { deb, fin } = getPeriodAsDate(true); // tz server
|
2024-10-29 16:40:42 +01:00
|
|
|
|
const period_iso = getPeriodAsISO(); // chaines sans timezone pour l'API
|
|
|
|
|
const deb_iso = period_iso.deb;
|
|
|
|
|
const fin_iso = period_iso.fin;
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const assiduiteObjet = {
|
2024-10-29 16:40:42 +01:00
|
|
|
|
date_debut: deb_iso,
|
|
|
|
|
date_fin: fin_iso,
|
2024-03-11 11:39:06 +01:00
|
|
|
|
etat: etat,
|
|
|
|
|
moduleimpl_id: $("#moduleimpl_select").val(),
|
|
|
|
|
};
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
if (el != null) el.checked = false;
|
|
|
|
|
|
|
|
|
|
// Suppression des assiduités
|
|
|
|
|
if (etat == "vide") {
|
2024-05-25 18:12:44 +02:00
|
|
|
|
if (!confirm("Effacer tout les évènements correspondant à cette plage ?")) {
|
|
|
|
|
return; // annulation
|
|
|
|
|
}
|
2024-06-04 15:21:28 +02:00
|
|
|
|
// On récupère les lignes avec une seule assiduité
|
|
|
|
|
let assiduites_id = lignesEtuds
|
2024-03-11 11:39:06 +01:00
|
|
|
|
.filter((e) => e.getAttribute("type") == "edition")
|
|
|
|
|
.map((e) => Number(e.getAttribute("assiduite_id")));
|
2024-06-04 15:21:28 +02:00
|
|
|
|
|
2024-10-29 16:40:42 +01:00
|
|
|
|
// On récupère les assiduités conflictuelles mais qui sont comprises
|
|
|
|
|
// dans la plage de suppression
|
2024-06-04 15:21:28 +02:00
|
|
|
|
const unDeleted = {};
|
|
|
|
|
lignesEtuds
|
|
|
|
|
.filter((e) => e.getAttribute("type") == "conflit")
|
|
|
|
|
.forEach((e) => {
|
|
|
|
|
const etud = etuds.get(Number(e.getAttribute("etudid")));
|
2024-10-29 16:40:42 +01:00
|
|
|
|
// On récupère les assiduités couvertes par la plage de suppression
|
2024-06-04 15:21:28 +02:00
|
|
|
|
etud.assiduites.forEach((a) => {
|
|
|
|
|
const date_debut = new Date(a.date_debut);
|
|
|
|
|
const date_fin = new Date(a.date_fin);
|
|
|
|
|
// On prend en compte uniquement les assiduités conflictuelles
|
|
|
|
|
// (qui intersectent la plage de suppression)
|
|
|
|
|
if (
|
|
|
|
|
Date.intersect(
|
2024-10-29 16:40:42 +01:00
|
|
|
|
{ deb: deb, fin: fin }, // la plage, en Date avec timezone serveur
|
|
|
|
|
{ deb: date_debut, fin: date_fin } // dates de l'assiduité avec leur timezone
|
2024-06-04 15:21:28 +02:00
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
// Si l'assiduité est couverte par la plage de suppression
|
|
|
|
|
// On l'ajoute à la liste des assiduités à supprimer.
|
|
|
|
|
if (
|
|
|
|
|
date_debut.isBetween(deb, fin, "[]") &&
|
|
|
|
|
date_fin.isBetween(deb, fin, "[]")
|
|
|
|
|
) {
|
|
|
|
|
assiduites_id.push(a.assiduite_id);
|
|
|
|
|
}
|
|
|
|
|
// Sinon on ajoute l'étudiant à la liste des étudiants non gérés
|
|
|
|
|
else {
|
|
|
|
|
unDeleted[a.etudid] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
afficheLoader();
|
|
|
|
|
|
|
|
|
|
async_post(
|
|
|
|
|
`../../api/assiduite/delete`,
|
|
|
|
|
assiduites_id,
|
|
|
|
|
async (data) => {
|
|
|
|
|
retirerLoader();
|
|
|
|
|
if (data.errors.length == 0) {
|
|
|
|
|
await recupAssiduites(etuds, $("#date").datepicker("getDate"));
|
|
|
|
|
creerTousLesEtudiants(etuds);
|
|
|
|
|
} else {
|
|
|
|
|
console.error(data.errors);
|
|
|
|
|
}
|
|
|
|
|
envoiToastTous("remove", assiduites_id.length);
|
2024-06-04 15:21:28 +02:00
|
|
|
|
if (Object.keys(unDeleted).length == 0) return;
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// CAS : des assiduités d'étudiants n'ont pas pu être supprimés
|
2024-06-04 15:21:28 +02:00
|
|
|
|
let unDeletedEtuds = `
|
|
|
|
|
<ul>
|
|
|
|
|
${Object.keys(unDeleted)
|
|
|
|
|
.map((etudid) => {
|
|
|
|
|
const etud = etuds.get(Number(etudid));
|
|
|
|
|
return `<li>${etud.civilite}. ${etud.nom.toUpperCase()} ${
|
|
|
|
|
etud.prenom
|
|
|
|
|
}</li>`;
|
|
|
|
|
})
|
|
|
|
|
.join("")}
|
|
|
|
|
</ul>
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
let html = `
|
|
|
|
|
<p>Les assiduités des étudiants suivants n'ont pas été supprimées car elles ne sont pas incluses dans la plage de suppression :</p>
|
|
|
|
|
${unDeletedEtuds}
|
|
|
|
|
`;
|
|
|
|
|
const div = document.createElement("div");
|
|
|
|
|
div.innerHTML = html;
|
|
|
|
|
openAlertModal("Assiduité non supprimée", div);
|
2024-03-11 11:39:06 +01:00
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
console.error("Erreur lors de la suppression de l'assiduité", error);
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-04-17 15:44:55 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-06-03 08:20:25 +02:00
|
|
|
|
// Création
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const assiduitesACreer = lignesEtuds
|
|
|
|
|
.filter((e) => e.getAttribute("type") == "creation")
|
|
|
|
|
.map((e) => Number(e.getAttribute("etudid")));
|
|
|
|
|
// création
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const promiseCreate = async_post(
|
|
|
|
|
`../../api/assiduites/create`,
|
|
|
|
|
assiduitesACreer.map((etudid) => {
|
|
|
|
|
return { ...assiduiteObjet, etudid };
|
|
|
|
|
}),
|
|
|
|
|
async (data) => {
|
|
|
|
|
if (data.errors.length > 0) {
|
|
|
|
|
console.error(data.errors);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
console.error("Erreur lors de la création de l'assiduité", error);
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
// Affiche un loader
|
|
|
|
|
afficheLoader();
|
2023-04-19 20:58:15 +02:00
|
|
|
|
|
2024-06-03 08:20:25 +02:00
|
|
|
|
Promise.all([promiseCreate]).then(async () => {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
retirerLoader();
|
|
|
|
|
await recupAssiduites(etuds, $("#date").datepicker("getDate"));
|
|
|
|
|
creerTousLesEtudiants(etuds);
|
2024-06-03 08:20:25 +02:00
|
|
|
|
envoiToastTous(etat, assiduitesACreer.length);
|
2023-06-20 15:50:56 +02:00
|
|
|
|
});
|
2023-04-17 15:44:55 +02:00
|
|
|
|
}
|
2023-04-20 18:04:21 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Affichage d'un loader (animation jeu pong)
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function afficheLoader() {
|
|
|
|
|
const loaderDiv = document.createElement("div");
|
|
|
|
|
loaderDiv.id = "loader";
|
|
|
|
|
const span = document.createElement("span");
|
|
|
|
|
span.textContent = "Chargement en cours";
|
|
|
|
|
loaderDiv.appendChild(span);
|
|
|
|
|
const loader = document.createElement("div");
|
|
|
|
|
loader.classList.add("loader");
|
|
|
|
|
loaderDiv.appendChild(loader);
|
|
|
|
|
document.body.appendChild(loaderDiv);
|
2023-04-20 18:04:21 +02:00
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Retrait du loader (animation jeu pong)
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function retirerLoader() {
|
|
|
|
|
document.getElementById("loader").remove();
|
2023-04-20 18:04:21 +02:00
|
|
|
|
}
|
2023-07-25 19:59:47 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Simplification de l'envoie de toast pour un étudiant
|
|
|
|
|
// affiche le nom, le prénom et l'état de l'assiduité avec une couleur spécifique
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function envoiToastEtudiant(etat, etud) {
|
|
|
|
|
let etatAffiche;
|
2023-07-25 19:59:47 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
switch (etat.toUpperCase()) {
|
|
|
|
|
case "PRESENT":
|
|
|
|
|
etatAffiche = "%etud% a été noté(e) <u><strong>présent(e)</strong></u>";
|
|
|
|
|
break;
|
|
|
|
|
case "RETARD":
|
|
|
|
|
etatAffiche = "%etud% a été noté(e) <u><strong>en retard</strong></u>";
|
|
|
|
|
break;
|
|
|
|
|
case "ABSENT":
|
|
|
|
|
etatAffiche = "%etud% a été noté(e) <u><strong>absent(e)</strong></u>";
|
|
|
|
|
break;
|
|
|
|
|
case "REMOVE":
|
|
|
|
|
etatAffiche = "L'assiduité de %etud% a été retirée.";
|
|
|
|
|
}
|
2023-07-26 16:43:49 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const nom_prenom = `${etud.nom.toUpperCase()} ${etud.prenom.capitalize()}`;
|
|
|
|
|
const span = document.createElement("span");
|
|
|
|
|
span.innerHTML = etatAffiche.replace("%etud%", nom_prenom);
|
2023-07-26 16:43:49 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
pushToast(generateToast(span, getToastColorFromEtat(etat.toUpperCase()), 5));
|
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Fonction pour simplifier l'envoie de toast avec le bouton "mettre tout le monde"
|
|
|
|
|
// On donne un etat et un compte et cela affichera le message associé.
|
|
|
|
|
// ex : 12 assiduités ont été supprimées
|
|
|
|
|
// ex : 15 étudiants ont été mis Absent.
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function envoiToastTous(etat, count) {
|
|
|
|
|
const span = document.createElement("span");
|
|
|
|
|
let etatAffiche = etat;
|
|
|
|
|
switch (etat) {
|
|
|
|
|
case "remove":
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
span.innerHTML = `${count} assiduités ont été supprimées.`;
|
|
|
|
|
} else {
|
|
|
|
|
span.innerHTML = `Aucune assiduité n'a été supprimée.`;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "retard":
|
|
|
|
|
etatAffiche = "En retard";
|
|
|
|
|
default:
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
span.innerHTML = `${count} étudiants ont été mis <u><strong>${etatAffiche
|
|
|
|
|
.capitalize()
|
|
|
|
|
.trim()}</strong></u>`;
|
|
|
|
|
} else {
|
|
|
|
|
span.innerHTML = `Aucun étudiant n'a été mis <u><strong>${etatAffiche
|
|
|
|
|
.capitalize()
|
|
|
|
|
.trim()}</strong></u>`;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-07-26 16:43:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
pushToast(generateToast(span, getToastColorFromEtat(etat.toUpperCase()), 5));
|
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Permet de savoir si un jour est travaillé ou pas
|
|
|
|
|
// jour : Date
|
|
|
|
|
// nonWorkdays : Array[str] => ["mar", "sam", "dim"]
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function estJourTravail(jour, nonWorkdays) {
|
|
|
|
|
const d = Intl.DateTimeFormat("fr-FR", {
|
|
|
|
|
timeZone: SCO_TIMEZONE,
|
|
|
|
|
weekday: "short",
|
|
|
|
|
})
|
|
|
|
|
.format(jour)
|
|
|
|
|
.replace(".", "");
|
|
|
|
|
return !nonWorkdays.includes(d);
|
2023-07-26 16:43:49 +02:00
|
|
|
|
}
|
2023-08-09 09:57:47 +02:00
|
|
|
|
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Renvoie le dernier jour travaillé disponible.
|
|
|
|
|
// par défaut va en arrière (dans le passé)
|
|
|
|
|
// si anti == False => va dans le futur
|
2024-05-23 09:40:44 +02:00
|
|
|
|
function retourJourTravail(date, anti = true) {
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const jourMiliSecondes = 86400000; // 24 * 3600 * 1000 | H * s * ms
|
|
|
|
|
let jour = date;
|
|
|
|
|
let compte = 0;
|
2023-08-09 09:57:47 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
while (!estJourTravail(jour, nonWorkDays) && compte++ < 7) {
|
2024-05-23 09:40:44 +02:00
|
|
|
|
let temps = anti
|
|
|
|
|
? jour - jourMiliSecondes
|
|
|
|
|
: jour.valueOf() + jourMiliSecondes;
|
|
|
|
|
jour = new Date(temps);
|
2024-03-11 11:39:06 +01:00
|
|
|
|
}
|
|
|
|
|
return jour;
|
2023-08-09 09:57:47 +02:00
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Vérifie si la date courante est travaillée
|
|
|
|
|
// Si ce n'est pas le cas, on change la date pour le dernier jour travaillé (passé)
|
|
|
|
|
// et on affiche une alerte
|
|
|
|
|
// (utilise le datepicker #date)
|
2024-03-11 11:39:06 +01:00
|
|
|
|
function dateCouranteEstTravaillee() {
|
|
|
|
|
const date = $("#date").datepicker("getDate");
|
2024-06-11 14:50:30 +02:00
|
|
|
|
|
2024-03-11 11:39:06 +01:00
|
|
|
|
if (!estJourTravail(date, nonWorkDays)) {
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// récupération du jour travaillé le plus proche
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const nouvelleDate = retourJourTravail(date);
|
|
|
|
|
$("#date").datepicker("setDate", nouvelleDate);
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Création du message d'alerte
|
2024-05-25 18:12:44 +02:00
|
|
|
|
let msg = "Le jour sélectionné";
|
2024-05-29 15:59:19 +02:00
|
|
|
|
if (new Date().format("YYYY-MM-DD") == date.format("YYYY-MM-DD")) {
|
2024-05-25 18:12:44 +02:00
|
|
|
|
msg = "Aujourd'hui";
|
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
const att = document.createTextNode(
|
2024-05-25 18:12:44 +02:00
|
|
|
|
`${msg} (${Date.toFRA(
|
2024-03-11 11:39:06 +01:00
|
|
|
|
date.format("YYYY-MM-DD")
|
|
|
|
|
)}) n'est pas un jour travaillé.`
|
|
|
|
|
);
|
|
|
|
|
const div = document.createElement("div");
|
|
|
|
|
div.appendChild(att);
|
|
|
|
|
div.appendChild(document.createElement("br"));
|
|
|
|
|
div.appendChild(
|
|
|
|
|
document.createTextNode(
|
|
|
|
|
`Le dernier jour travaillé disponible a été sélectionné : ${Date.toFRA(
|
|
|
|
|
nouvelleDate.format("YYYY-MM-DD")
|
|
|
|
|
)}.`
|
|
|
|
|
)
|
2023-10-23 14:56:18 +02:00
|
|
|
|
);
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Affichage de l'alerte
|
2024-03-11 11:39:06 +01:00
|
|
|
|
openAlertModal("Attention", div, "", "#eec660");
|
|
|
|
|
|
|
|
|
|
return false;
|
2023-10-23 14:56:18 +02:00
|
|
|
|
}
|
2024-03-11 11:39:06 +01:00
|
|
|
|
return true;
|
2023-10-23 14:56:18 +02:00
|
|
|
|
}
|
2024-06-11 14:50:30 +02:00
|
|
|
|
// Fonction pour passer au jour suivant
|
|
|
|
|
// anti : bool => si true, on va dans le passé
|
2024-05-23 09:40:44 +02:00
|
|
|
|
function jourSuivant(anti = false) {
|
|
|
|
|
let date = $("#date").datepicker("getDate");
|
|
|
|
|
|
|
|
|
|
date = anti ? date.add(-1, "days") : date.add(1, "days");
|
|
|
|
|
|
|
|
|
|
const nouvelleDate = retourJourTravail(date, anti);
|
|
|
|
|
|
|
|
|
|
$("#date").datepicker("setDate", nouvelleDate);
|
|
|
|
|
creerTousLesEtudiants(etuds);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-13 16:35:56 +01:00
|
|
|
|
/**
|
|
|
|
|
* Ajout de la visualisation des assiduités de la mini timeline
|
|
|
|
|
* @param {HTMLElement} el l'élément survollé
|
|
|
|
|
* @param {Assiduité} assiduite l'assiduité représentée par l'élément
|
|
|
|
|
*/
|
|
|
|
|
function setupAssiduiteBubble(el, assiduite) {
|
|
|
|
|
function formatDateModal(dateStr) {
|
|
|
|
|
const date = new Date(Date.removeUTC(dateStr));
|
|
|
|
|
return date.format("DD/MM/Y HH:mm");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!assiduite) return;
|
|
|
|
|
|
|
|
|
|
const bubble = document.createElement("div");
|
|
|
|
|
bubble.className = "assiduite-bubble";
|
|
|
|
|
bubble.classList.add(assiduite.etat.toLowerCase());
|
|
|
|
|
|
2024-03-15 15:56:33 +01:00
|
|
|
|
// Ajout d'un lien pour plus d'informations
|
|
|
|
|
const infos = document.createElement("a");
|
2024-03-25 15:19:59 +01:00
|
|
|
|
infos.className = "";
|
2024-03-15 15:56:33 +01:00
|
|
|
|
infos.textContent = `ℹ️`;
|
2024-06-03 15:50:35 +02:00
|
|
|
|
infos.title = "Détails / Modifier";
|
2024-03-15 15:56:33 +01:00
|
|
|
|
infos.target = "_blank";
|
2024-06-03 15:50:35 +02:00
|
|
|
|
infos.href = `edit_assiduite_etud/${assiduite.assiduite_id}`;
|
2024-03-25 15:19:59 +01:00
|
|
|
|
|
|
|
|
|
const actionsDiv = document.createElement("div");
|
|
|
|
|
actionsDiv.className = "assiduite-actions";
|
|
|
|
|
actionsDiv.appendChild(infos);
|
|
|
|
|
bubble.appendChild(actionsDiv);
|
2024-03-15 15:56:33 +01:00
|
|
|
|
|
2024-05-24 16:51:44 +02:00
|
|
|
|
const stateDiv = document.createElement("div");
|
|
|
|
|
stateDiv.className = "assiduite-state";
|
|
|
|
|
stateDiv.textContent = `État: ${assiduite.etat.capitalize()}`;
|
|
|
|
|
bubble.appendChild(stateDiv);
|
|
|
|
|
|
2024-03-13 16:35:56 +01:00
|
|
|
|
const idDiv = document.createElement("div");
|
|
|
|
|
idDiv.className = "assiduite-id";
|
|
|
|
|
getModuleImpl(assiduite).then((modImpl) => {
|
|
|
|
|
idDiv.textContent = `${modImpl}`;
|
|
|
|
|
});
|
|
|
|
|
bubble.appendChild(idDiv);
|
|
|
|
|
|
2024-05-24 16:51:44 +02:00
|
|
|
|
// Affichage des dates
|
|
|
|
|
// si les jours sont les mêmes, on affiche "jour hh:mm - hh:mm"
|
|
|
|
|
// sinon on affiche "jour hh:mm - jour hh:mm"
|
|
|
|
|
const periodDiv = document.createElement("div");
|
|
|
|
|
periodDiv.className = "assiduite-period";
|
|
|
|
|
const dateDeb = new Date(Date.removeUTC(assiduite.date_debut));
|
|
|
|
|
const dateFin = new Date(Date.removeUTC(assiduite.date_fin));
|
|
|
|
|
if (dateDeb.isSame(dateFin, "day")) {
|
|
|
|
|
const jour = dateDeb.format("DD/MM/YYYY");
|
|
|
|
|
const deb = dateDeb.format("HH:mm");
|
|
|
|
|
const fin = dateFin.format("HH:mm");
|
|
|
|
|
periodDiv.textContent = `${jour} de ${deb} à ${fin}`;
|
|
|
|
|
} else {
|
|
|
|
|
const jourDeb = dateDeb.format("DD/MM/YYYY");
|
|
|
|
|
const jourFin = dateFin.format("DD/MM/YYYY");
|
|
|
|
|
periodDiv.textContent = `du ${jourDeb} au ${jourFin}`;
|
|
|
|
|
}
|
2024-03-13 16:35:56 +01:00
|
|
|
|
|
2024-05-24 16:51:44 +02:00
|
|
|
|
bubble.appendChild(periodDiv);
|
2024-03-13 16:35:56 +01:00
|
|
|
|
|
|
|
|
|
const motifDiv = document.createElement("div");
|
2024-05-24 16:51:44 +02:00
|
|
|
|
motifDiv.className = "assiduite-why";
|
2024-03-13 16:35:56 +01:00
|
|
|
|
const motif = ["", null, undefined].includes(assiduite.desc)
|
2024-05-24 16:51:44 +02:00
|
|
|
|
? "Non spécifié"
|
2024-03-13 16:35:56 +01:00
|
|
|
|
: assiduite.desc.capitalize();
|
2024-05-24 16:51:44 +02:00
|
|
|
|
motifDiv.textContent = `Motif: ${motif}`;
|
2024-03-13 16:35:56 +01:00
|
|
|
|
bubble.appendChild(motifDiv);
|
|
|
|
|
|
|
|
|
|
const userIdDiv = document.createElement("div");
|
|
|
|
|
userIdDiv.className = "assiduite-user_id";
|
|
|
|
|
userIdDiv.textContent = `saisie le ${formatDateModal(
|
|
|
|
|
assiduite.entry_date,
|
|
|
|
|
" à "
|
|
|
|
|
)}`;
|
|
|
|
|
|
|
|
|
|
if (assiduite.user_id != null) {
|
|
|
|
|
userIdDiv.textContent += `\npar ${assiduite.user_nom_complet}`;
|
|
|
|
|
}
|
|
|
|
|
bubble.appendChild(userIdDiv);
|
|
|
|
|
|
|
|
|
|
el.appendChild(bubble);
|
|
|
|
|
}
|
2024-03-22 15:41:39 +01:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Permet d'afficher ou non les photos des étudiants
|
|
|
|
|
* @param {boolean} checked
|
|
|
|
|
*/
|
|
|
|
|
function afficherPDP(checked) {
|
|
|
|
|
if (checked) {
|
|
|
|
|
gtrcontent.setAttribute("data-pdp", "true");
|
|
|
|
|
} else {
|
|
|
|
|
gtrcontent.removeAttribute("data-pdp");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// On sauvegarde le choix dans le localStorage
|
|
|
|
|
localStorage.setItem("scodoc-etud-pdp", `${checked}`);
|
|
|
|
|
pdp.checked = checked;
|
|
|
|
|
}
|