ScoDoc/app/templates/assiduites/signal_assiduites_diff.j2

372 lines
11 KiB
Plaintext
Raw Normal View History

2023-06-01 17:32:50 +02:00
<h2>Signalement différé des assiduités {{gr |safe}}</h2>
<h3>{{sem | safe }}</h3>
<button onclick="getAndVerify()">Valider les assiduités</button>
<div id="studentTable">
<div class="thead">
<div class="tr">
<div class="th sticky">Noms</div>
<button id="addColumn" class="floating-button">+</button>
</div>
</div>
<div class="tbody">
{% for etud in etudiants %}
<div class="tr" etudid="{{etud.etudid}}">
<div class="td sticky">{{etud.nomprenom}}</div>
</div>
{% endfor %}
</div>
</div>
{% include "assiduites/alert.j2" %}
{% include "assiduites/prompt.j2" %}
<style>
button {
margin: 10px 0;
}
.err-assi {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 15px;
}
.table-container {
overflow: auto;
position: relative;
max-width: 100%;
margin: 0 auto;
box-shadow: 0 0 1rem 0 rgba(0, 0, 0, .2);
}
.table {
border-collapse: collapse;
}
.thead .tr {
display: flex;
align-items: center;
}
.thead .tr .th {
height: 125px;
display: flex;
justify-content: center;
align-items: center;
font-size: larger;
}
.th.sticky {
z-index: 5;
}
.th,
.td {
padding: 10px;
text-align: center;
width: 200px;
border: 1px solid #ddd;
display: inline-block;
}
.tr {
display: flex;
justify-content: flex-start;
align-items: center;
width: max-content;
}
.sticky {
position: sticky;
left: 0;
background-color: #fafafa;
border-right: 1px solid #ddd;
}
.mini-form {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.mini-form input,
.mini-form select {
display: block;
margin: 5px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ddd;
}
#addColumn {
font-size: 24px;
width: 50px;
height: 50px;
border-radius: 50%;
right: -60px;
top: calc(50% - 50px /2);
background-color: #007BFF;
color: white;
border: none;
outline: none;
cursor: pointer;
transition: background-color 0.3s;
}
#addColumn:hover {
background-color: #0056b3;
}
.th {
background-color: #007BFF;
color: white;
}
.tbody .tr:nth-child(even) {
background-color: #f2f2f2;
}
.tbody .tr:hover {
background-color: #ddd;
}
.etat {
display: grid;
grid-template-columns: 33% 33% 33%;
grid-template-rows: 50% 50%;
font-size: small;
}
#moduleimpl_select {
max-width: 175px;
}
</style>
<script>
let verified = false;
const etatDef = "{{etat_def}}";
moment.tz.setDefault("Etc/UTC");
function createColumn() {
let table = document.getElementById("studentTable");
let th = document.createElement("div");
th.classList.add("th");
const col_id = `${document.querySelectorAll("[col]").length + 1}`;
th.setAttribute("col", col_id);
th.innerHTML = `
<div class="mini-form">
<input type="datetime-local" id="dateStart">
<input type="datetime-local" id="dateEnd">
{{moduleimpl_select|safe}}
</div>
`;
table
.querySelector(".thead .tr")
.insertBefore(th, document.querySelector("#addColumn"));
const last = [...document.querySelectorAll("#dateStart")].pop();
defaultDate(last);
let rows = table.querySelector(".tbody").querySelectorAll(".tr");
for (let i = 0; i < rows.length; i++) {
let td = document.createElement("div");
td.setAttribute("colid", col_id)
td.classList.add("td", "etat");
const etudid = rows[i].getAttribute("etudid");
td.innerHTML = `
<input type="radio" name="etat_${col_id}_${etudid}" value="present">
<input type="radio" name="etat_${col_id}_${etudid}" value="retard">
<input type="radio" name="etat_${col_id}_${etudid}" value="absent">
<span>Present</span>
<span>Retard</span>
<span>Absent</span>
`;
rows[i].appendChild(td);
if (etatDef != "" && etatDef != "aucun") {
const inp = td.querySelector(`[value='${etatDef}']`).checked = true;
}
}
}
function defaultDate(element) {
const num = element.parentElement.parentElement.getAttribute("col") - 1;
const last = [...document.querySelectorAll(`[col='${num}'] #dateEnd`)].pop();
let date = undefined;
if (last == undefined) {
date = moment().tz("Europe/Paris").format("YYYY-MM-DDTHH:mm");
} else {
date = last.value;
}
element.value = date;
element.addEventListener(
"focusout",
() => {
const el = element.parentElement.querySelector("#dateEnd");
const el2 = element.parentElement.querySelector("#dateStart");
el.value = moment(el2.valueAsDate)
.add(2, "hours")
.format("YYYY-MM-DDTHH:mm");
},
{ once: true }
);
}
function getEtatCol(colId) {
const etats = {};
const tds = [...document.querySelectorAll(`.td[colid='${colId}']`)]
tds.forEach((td) => {
const tr = td.parentElement
const etudid = tr.getAttribute("etudid");
let inputs = [...td.querySelectorAll("input")]
etatInput = inputs.filter((e) => e.checked).pop()
if (etatInput == undefined) {
etats[etudid] = "";
} else {
etats[etudid] = etatInput.value;
}
})
return etats;
}
function _createAssiduites(inputDeb, inputFin, moduleSelect, etudid, etat, colId) {
if (moduleSelect == "") {
return {
"date_debut": inputDeb,
"date_fin": inputFin,
"etudid": etudid,
"etat": etat,
"colid": colId,
}
} else {
return {
"date_debut": inputDeb,
"date_fin": inputFin,
"etudid": etudid,
"moduleimpl_id": moduleSelect,
"etat": etat,
"colid": colId,
}
}
}
function getAndVerify() {
const assiduites = [];
const cols = [...document.querySelectorAll("[col]")];
const errors = [];
cols.forEach((col) => {
const col_id = col.getAttribute("col");
const etats = getEtatCol(col_id);
const inputDeb = col.querySelector("#dateStart").value;
const inputFin = col.querySelector("#dateEnd").value;
const moduleSelect = col.querySelector("#moduleimpl_select").value;
if (inputDeb == "" || inputFin == "") {
errors.push(`La colonne n°${col_id} n'est pas valide`);
return;
}
// TODO Mettre une erreur lorsque moduleimpl forcé (pref)
// TODO Mettre une erreur lorsque assiduité forcé (pref)
Object.keys(etats).forEach((key) => {
const etat = etats[key];
if (etat != "") {
assiduites.push(_createAssiduites(inputDeb, inputFin, moduleSelect, key, etat, col_id))
}
})
});
if (errors.length > 0) {
const texte = document.createElement("div");
errors.map((err) => document.createTextNode(err)).forEach((err) => {
texte.appendChild(err);
texte.appendChild(document.createElement('br'));
})
openAlertModal("Erreur(s) détéctée(s)", texte)
} else {
createAllAssiduites(assiduites);
}
}
function createAllAssiduites(createQueue) {
if (createQueue.length < 0)
return;
const path = getUrl() + `/api/assiduites/create`;
sync_post(
path,
createQueue,
(data, status) => {
verified = true;
const { success, errors } = data;
const indexes = [...Object.keys(errors)];
if (indexes.length > 0) {
const incriminated = indexes.map((i) => {
return createQueue[Number.parseInt(i)];
})
const error_message = document.createElement('div');
for (let i = 0; i < incriminated.length; i++) {
const err = errors[indexes[i]];
const crimi = incriminated[i];
const nom = document.querySelector(`[etudid='${crimi.etudid}']`).firstElementChild.textContent.trim();
const col = crimi.colid;
const div = document.createElement('div');
div.classList.add("err-assi")
const span = document.createElement("span");
span.setAttribute("title", err);
span.textContent = ""
const span2 = document.createElement("span");
span2.textContent = `L'assiduité (Colonne n°${col}) de ${nom} n'a pas pu être enregistrée`;
div.appendChild(span2);
div.appendChild(span);
error_message.appendChild(div);
}
openAlertModal("Certaines assiduités non pas été enregistrées", error_message)
} else {
openAlertModal("Tous les assiduités ont bien été enregistrée", document.createTextNode(""), null, "#09AD2A")
}
},
(data, status) => {
//error
console.error(data, status);
}
);
}
document.getElementById("addColumn").addEventListener("click", () => {
createColumn();
});
const onConfirmRefresh = function (event) {
if (!verified)
return event.returnValue = "Attention, certaines données n'ont pas été enregistrées";
}
window.addEventListener("beforeunload", onConfirmRefresh, { capture: true });
createColumn();
</script>