forked from ScoDoc/ScoDoc
901 lines
25 KiB
JavaScript
901 lines
25 KiB
JavaScript
/**
|
|
*
|
|
* Ensemble des fonctions liées à la gestion des assiduités
|
|
* Créé par : HARTMANN Matthias (Iziram)
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* <== OUTILS ==>
|
|
*/
|
|
|
|
/**
|
|
* Ajout d'une fonction `capitalize` sur tous les strings
|
|
* "alice".capitalize() -> "Alice"
|
|
*/
|
|
Object.defineProperty(String.prototype, "capitalize", {
|
|
value: function () {
|
|
return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
|
|
},
|
|
enumerable: false,
|
|
});
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
async function async_get(path, success, errors) {
|
|
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);
|
|
});
|
|
|
|
return response;
|
|
}
|
|
/**
|
|
* 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
|
|
*/
|
|
async function async_post(path, data, success, errors) {
|
|
console.log("async_post " + path);
|
|
let response;
|
|
try {
|
|
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) {
|
|
console.error(error);
|
|
if (errors) errors(error);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
async function recupEtuds(groupIds) {
|
|
const etuds = new Map();
|
|
if (groupIds == null || groupIds.length == 0) return etuds;
|
|
|
|
// 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");
|
|
}
|
|
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
|
|
)
|
|
)
|
|
);
|
|
|
|
// Attendre que toutes les promesses dans le tableau `requests` soient résolues.
|
|
await Promise.all(requests);
|
|
|
|
return etuds;
|
|
}
|
|
/**
|
|
* Récupère l'assiduité des étudiants pour une date donnée
|
|
* @param {Map} etuds
|
|
* @param {Date} date
|
|
*/
|
|
async function recupAssiduites(etuds, date) {
|
|
const etudIds = [...etuds.keys()].join(",");
|
|
|
|
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/group/query?date_debut=${date_debut}` +
|
|
`&date_fin=${date_fin}&etudids=${etudIds}&with_justifs`;
|
|
|
|
await fetch(url)
|
|
.then((res) => {
|
|
if (!res.ok) {
|
|
throw new Error("Network response was not ok");
|
|
}
|
|
return res.json();
|
|
})
|
|
.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
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Génération ligne étudiante
|
|
*/
|
|
function creerLigneEtudiant(etud, index) {
|
|
let currentAssiduite = {
|
|
etat: "",
|
|
type: "creation",
|
|
assiduite_id: -1,
|
|
date_debut: null,
|
|
date_fin: null,
|
|
};
|
|
|
|
function recupConflitsAssiduites(assiduites) {
|
|
const period = getPeriodAsDate();
|
|
|
|
return assiduites.filter((assi) => {
|
|
const interval = {
|
|
deb: new Date(Date.removeUTC(assi.date_debut)),
|
|
fin: new Date(Date.removeUTC(assi.date_fin)),
|
|
};
|
|
|
|
return (
|
|
period.deb.isBefore(interval.fin) && period.fin.isAfter(interval.deb)
|
|
);
|
|
});
|
|
}
|
|
|
|
const conflits = readOnly ? [] : recupConflitsAssiduites(etud.assiduites);
|
|
|
|
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";
|
|
}
|
|
|
|
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}`;
|
|
|
|
if (currentAssiduite.type === "conflit" && !readOnly)
|
|
ligneEtud.classList.add("conflit");
|
|
|
|
// div index avec l'index
|
|
const indexDiv = document.createElement("div");
|
|
indexDiv.classList.add("index");
|
|
indexDiv.textContent = index;
|
|
|
|
ligneEtud.appendChild(indexDiv);
|
|
|
|
// div name_field
|
|
|
|
const nameField = document.createElement("div");
|
|
nameField.classList.add("name_field");
|
|
|
|
if ($("#pdp").is(":checked")) {
|
|
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);
|
|
}
|
|
|
|
const nameSet = document.createElement("a");
|
|
nameSet.classList.add("name_set");
|
|
nameSet.href = `bilan_etud?etudid=${etud.id}`;
|
|
|
|
const nom = document.createElement("h4");
|
|
nom.classList.add("nom");
|
|
nom.textContent = etud.nom;
|
|
|
|
const prenom = document.createElement("h5");
|
|
prenom.classList.add("prenom");
|
|
prenom.textContent = etud.prenom;
|
|
|
|
nameSet.appendChild(nom);
|
|
nameSet.appendChild(prenom);
|
|
|
|
nameField.appendChild(nameSet);
|
|
ligneEtud.appendChild(nameField);
|
|
|
|
// div assiduites_bar
|
|
|
|
const assiduitesBar = document.createElement("div");
|
|
assiduitesBar.classList.add("assiduites_bar");
|
|
|
|
const prevDateAssi = document.createElement("div");
|
|
prevDateAssi.id = "prevDateAssi";
|
|
|
|
function recupDerniereAssiduite(assiduites) {
|
|
const period = {
|
|
deb: $("#date").datepicker("getDate").add(-1, "days"),
|
|
fin: $("#date").datepicker("getDate"),
|
|
};
|
|
|
|
const lastAssiduite = assiduites
|
|
.filter((assi) => {
|
|
const interval = {
|
|
deb: new Date(Date.removeUTC(assi.date_debut)),
|
|
fin: new Date(Date.removeUTC(assi.date_fin)),
|
|
};
|
|
|
|
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") {
|
|
["present", "retard", "absent"].forEach((abs) => {
|
|
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;
|
|
}
|
|
});
|
|
});
|
|
|
|
// Action au clic
|
|
btn.addEventListener("click", (e) => {
|
|
actionAssiduite(
|
|
etud,
|
|
btn.value,
|
|
currentAssiduite.type,
|
|
currentAssiduite.type == "edition" ? currentAssiduite : null
|
|
);
|
|
e.preventDefault();
|
|
});
|
|
|
|
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"),
|
|
});
|
|
|
|
const update = () => {
|
|
MiseAJourLigneEtud(etud);
|
|
};
|
|
|
|
solveur.callbacks = {
|
|
delete: update,
|
|
edit: update,
|
|
split: update,
|
|
};
|
|
|
|
btn.addEventListener("click", () => {
|
|
solveur.open();
|
|
btn.checked = false;
|
|
});
|
|
|
|
btnsField.appendChild(btn);
|
|
}
|
|
|
|
ligneEtud.appendChild(btnsField);
|
|
|
|
return ligneEtud;
|
|
}
|
|
|
|
/**
|
|
* Génération de toutes les lignes étudiantes
|
|
*/
|
|
|
|
async function creerTousLesEtudiants(etuds) {
|
|
const etudsDiv = document.querySelector(".etud_holder");
|
|
etudsDiv.innerHTML = "";
|
|
const moduleImplId = readOnly ? null : $("#moduleimpl_select").val();
|
|
const inscriptions = await getInscriptionModule(moduleImplId);
|
|
[...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));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Récupère une version lisible du moduleimpl
|
|
* @param {Object} assiduite
|
|
* @returns {String}
|
|
*/
|
|
async function getModuleImpl(assiduite) {
|
|
if (assiduite == null) return "Pas de module";
|
|
const id = assiduite.moduleimpl_id;
|
|
|
|
if (id == null || id == undefined) {
|
|
if (
|
|
assiduite.hasOwnProperty("external_data") &&
|
|
assiduite.external_data != null &&
|
|
assiduite.external_data.hasOwnProperty("module")
|
|
) {
|
|
return assiduite.external_data.module == "Autre"
|
|
? "Autre module (pas dans la liste)"
|
|
: assiduite.external_data.module;
|
|
} else {
|
|
return "Pas de module";
|
|
}
|
|
}
|
|
|
|
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) => {
|
|
moduleimpls[id] = `${data.module.code} ${data.module.abbrev}`;
|
|
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) {
|
|
if (
|
|
assiduite.hasOwnProperty("external_data") &&
|
|
assiduite.external_data != null &&
|
|
assiduite.external_data.hasOwnProperty("module")
|
|
) {
|
|
return assiduite.external_data.module.toLowerCase();
|
|
} else {
|
|
return "";
|
|
}
|
|
} else {
|
|
return id + "";
|
|
}
|
|
}
|
|
/**
|
|
* Récupère les etudid de tous les étudiants inscrits au module
|
|
* @param {String} moduleimpl_id
|
|
* @returns {Array}
|
|
*/
|
|
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, []);
|
|
});
|
|
}
|
|
|
|
return inscriptionsModules.get(moduleimpl_id);
|
|
}
|
|
|
|
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`;
|
|
|
|
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
|
|
);
|
|
});
|
|
}
|
|
|
|
await RecupAssiduitesEtudiant(etud.id);
|
|
|
|
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
|
|
);
|
|
|
|
etudRow.replaceWith(ligneEtud);
|
|
}
|
|
|
|
async function actionAssiduite(etud, etat, type, assiduite = null) {
|
|
const modimpl_id = $("#moduleimpl_select").val();
|
|
if (
|
|
assiduite &&
|
|
assiduite.etat.toLowerCase() === etat &&
|
|
assiduite.moduleimpl_id == modimpl_id
|
|
)
|
|
type = "suppression";
|
|
|
|
const { deb, fin } = getPeriodAsDate();
|
|
|
|
let assiduiteObjet = assiduite ?? {
|
|
date_debut: deb,
|
|
date_fin: fin,
|
|
etudid: etud.id,
|
|
};
|
|
|
|
assiduiteObjet.etat = etat;
|
|
assiduiteObjet.moduleimpl_id = modimpl_id;
|
|
|
|
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);
|
|
}
|
|
);
|
|
} 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);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
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>
|
|
`;
|
|
|
|
const content = document.createElement("div");
|
|
content.innerHTML = HTML;
|
|
|
|
openAlertModal("Sélection du module", content);
|
|
}
|
|
if (message == "L'étudiant n'est pas inscrit au module") {
|
|
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>
|
|
`;
|
|
|
|
const content = document.createElement("div");
|
|
content.innerHTML = HTML;
|
|
|
|
openAlertModal("Sélection du module", content);
|
|
}
|
|
}
|
|
|
|
function mettreToutLeMonde(etat, el = null) {
|
|
const lignesEtuds = [...document.querySelectorAll("fieldset.btns_field")];
|
|
|
|
const { deb, fin } = getPeriodAsDate();
|
|
const assiduiteObjet = {
|
|
date_debut: deb,
|
|
date_fin: fin,
|
|
etat: etat,
|
|
moduleimpl_id: $("#moduleimpl_select").val(),
|
|
};
|
|
|
|
if (el != null) el.checked = false;
|
|
|
|
// Suppression des assiduités
|
|
if (etat == "vide") {
|
|
const assiduites_id = lignesEtuds
|
|
.filter((e) => e.getAttribute("type") == "edition")
|
|
.map((e) => Number(e.getAttribute("assiduite_id")));
|
|
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);
|
|
},
|
|
(error) => {
|
|
console.error("Erreur lors de la suppression de l'assiduité", error);
|
|
}
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
// Création / édition des assiduités
|
|
const assiduitesACreer = lignesEtuds
|
|
.filter((e) => e.getAttribute("type") == "creation")
|
|
.map((e) => Number(e.getAttribute("etudid")));
|
|
const assiduitesAEditer = lignesEtuds
|
|
.filter((e) => e.getAttribute("type") == "edition")
|
|
.map((e) => Number(e.getAttribute("assiduite_id")));
|
|
|
|
// création
|
|
|
|
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);
|
|
}
|
|
);
|
|
const promiseEdit = async_post(
|
|
`../../api/assiduites/edit`,
|
|
assiduitesAEditer.map((assiduite_id) => {
|
|
return { ...assiduiteObjet, assiduite_id };
|
|
}),
|
|
async (data) => {
|
|
if (data.errors.length > 0) {
|
|
console.error(data.errors);
|
|
}
|
|
},
|
|
(error) => {
|
|
console.error("Erreur lors de l'édition de l'assiduité", error);
|
|
}
|
|
);
|
|
|
|
// Affiche un loader
|
|
afficheLoader();
|
|
|
|
Promise.all([promiseCreate, promiseEdit]).then(async () => {
|
|
retirerLoader();
|
|
await recupAssiduites(etuds, $("#date").datepicker("getDate"));
|
|
creerTousLesEtudiants(etuds);
|
|
envoiToastTous(etat, assiduitesACreer.length + assiduitesAEditer.length);
|
|
});
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
function retirerLoader() {
|
|
document.getElementById("loader").remove();
|
|
}
|
|
|
|
function envoiToastEtudiant(etat, etud) {
|
|
let etatAffiche;
|
|
|
|
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.";
|
|
}
|
|
|
|
const nom_prenom = `${etud.nom.toUpperCase()} ${etud.prenom.capitalize()}`;
|
|
const span = document.createElement("span");
|
|
span.innerHTML = etatAffiche.replace("%etud%", nom_prenom);
|
|
|
|
pushToast(generateToast(span, getToastColorFromEtat(etat.toUpperCase()), 5));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
pushToast(generateToast(span, getToastColorFromEtat(etat.toUpperCase()), 5));
|
|
}
|
|
|
|
function estJourTravail(jour, nonWorkdays) {
|
|
const d = Intl.DateTimeFormat("fr-FR", {
|
|
timeZone: SCO_TIMEZONE,
|
|
weekday: "short",
|
|
})
|
|
.format(jour)
|
|
.replace(".", "");
|
|
return !nonWorkdays.includes(d);
|
|
}
|
|
|
|
function retourJourTravail(date) {
|
|
const jourMiliSecondes = 86400000; // 24 * 3600 * 1000 | H * s * ms
|
|
let jour = date;
|
|
let compte = 0;
|
|
|
|
while (!estJourTravail(jour, nonWorkDays) && compte++ < 7) {
|
|
jour = new Date(jour - jourMiliSecondes);
|
|
}
|
|
return jour;
|
|
}
|
|
|
|
function dateCouranteEstTravaillee() {
|
|
const date = $("#date").datepicker("getDate");
|
|
if (!estJourTravail(date, nonWorkDays)) {
|
|
const nouvelleDate = retourJourTravail(date);
|
|
$("#date").datepicker("setDate", nouvelleDate);
|
|
|
|
const att = document.createTextNode(
|
|
`Le jour sélectionné (${Date.toFRA(
|
|
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")
|
|
)}.`
|
|
)
|
|
);
|
|
openAlertModal("Attention", div, "", "#eec660");
|
|
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 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());
|
|
|
|
const idDiv = document.createElement("div");
|
|
idDiv.className = "assiduite-id";
|
|
getModuleImpl(assiduite).then((modImpl) => {
|
|
idDiv.textContent = `${modImpl}`;
|
|
});
|
|
bubble.appendChild(idDiv);
|
|
|
|
const periodDivDeb = document.createElement("div");
|
|
periodDivDeb.className = "assiduite-period";
|
|
periodDivDeb.textContent = `${formatDateModal(assiduite.date_debut)}`;
|
|
bubble.appendChild(periodDivDeb);
|
|
const periodDivFin = document.createElement("div");
|
|
periodDivFin.className = "assiduite-period";
|
|
periodDivFin.textContent = `${formatDateModal(assiduite.date_fin)}`;
|
|
bubble.appendChild(periodDivFin);
|
|
|
|
const stateDiv = document.createElement("div");
|
|
stateDiv.className = "assiduite-state";
|
|
stateDiv.textContent = `État: ${assiduite.etat.capitalize()}`;
|
|
bubble.appendChild(stateDiv);
|
|
|
|
const motifDiv = document.createElement("div");
|
|
stateDiv.className = "assiduite-why";
|
|
const motif = ["", null, undefined].includes(assiduite.desc)
|
|
? "Pas de motif"
|
|
: assiduite.desc.capitalize();
|
|
stateDiv.textContent = `Motif: ${motif}`;
|
|
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);
|
|
}
|