forked from ScoDoc/ScoDoc
Assiduité : signal_assiduites_hebdo : v2 sans mobile
This commit is contained in:
parent
fac36fa11c
commit
f4f6c13d79
@ -67,9 +67,15 @@ async function async_post(path, data, success, errors) {
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
success(responseData);
|
||||
} else {
|
||||
if (response.status == 404) {
|
||||
response.json().then((data) => {
|
||||
if (errors) errors(data);
|
||||
});
|
||||
} else {
|
||||
throw new Error("Network response was not ok.");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (errors) errors(error);
|
||||
@ -615,7 +621,10 @@ function erreurModuleImpl(message) {
|
||||
|
||||
openAlertModal("Sélection du module", content);
|
||||
}
|
||||
if (message == "L'étudiant n'est pas inscrit au module") {
|
||||
if (
|
||||
message == "L'étudiant n'est pas inscrit au module" ||
|
||||
message == "param 'moduleimpl_id': etud non inscrit"
|
||||
) {
|
||||
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>
|
||||
@ -822,7 +831,7 @@ function dateCouranteEstTravaillee() {
|
||||
const nouvelleDate = retourJourTravail(date);
|
||||
$("#date").datepicker("setDate", nouvelleDate);
|
||||
let msg = "Le jour sélectionné";
|
||||
if ((new Date()).format("YYYY-MM-DD") == date.format("YYYY-MM-DD")) {
|
||||
if (new Date().format("YYYY-MM-DD") == date.format("YYYY-MM-DD")) {
|
||||
msg = "Aujourd'hui";
|
||||
}
|
||||
const att = document.createTextNode(
|
||||
|
@ -108,6 +108,11 @@
|
||||
background-color: var(--color-conflit);
|
||||
}
|
||||
|
||||
.conflit_calendar{
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
@ -185,6 +190,9 @@
|
||||
|
||||
<script>
|
||||
|
||||
const readonly = "{{readonly | safe}}" == "True";
|
||||
const non_present = "{{non_present | safe}}" == "True";
|
||||
|
||||
const etuds = [
|
||||
{% for etud in etudiants %}
|
||||
{
|
||||
@ -231,6 +239,8 @@
|
||||
date_fin: fin.toFakeIso(),
|
||||
}
|
||||
|
||||
let cancelEvent = false;
|
||||
|
||||
if (assiduite_id != "") {
|
||||
if (same) {
|
||||
// Suppression
|
||||
@ -243,13 +253,13 @@
|
||||
td.setAttribute("assiduite_id", "");
|
||||
} else {
|
||||
console.error(data.errors["0"].message);
|
||||
cancelEvent = true;
|
||||
erreurModuleImpl(data.errors["0"].message);
|
||||
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error("Erreur lors de la suppression de l'assiduité", error);
|
||||
|
||||
cancelEvent = true;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
@ -262,6 +272,8 @@
|
||||
},
|
||||
(error) => {
|
||||
console.error("Erreur lors de la modification de l'assiduité", error);
|
||||
cancelEvent = true;
|
||||
erreurModuleImpl(error.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -278,7 +290,7 @@
|
||||
} else {
|
||||
console.error(data.errors["0"].message);
|
||||
erreurModuleImpl(data.errors["0"].message);
|
||||
|
||||
cancelEvent = true;
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
@ -288,6 +300,8 @@
|
||||
);
|
||||
}
|
||||
|
||||
return cancelEvent;
|
||||
|
||||
}
|
||||
|
||||
async function recupAssiduitesHebdo(callback) {
|
||||
@ -324,6 +338,14 @@
|
||||
|
||||
function updateTable(assiduites) {
|
||||
|
||||
const img_conflit = `
|
||||
<a
|
||||
class="conflit_calendar"
|
||||
title="Des assiduités existent déjà pour cette période. Cliquez ici pour voir le calendrier de l'assiduité de l'étudiant"
|
||||
data-tooltip
|
||||
target="_blank"
|
||||
>📅</a>`
|
||||
|
||||
// Suppression existant
|
||||
document.querySelectorAll("td.btns").forEach((el) => {
|
||||
el.remove();
|
||||
@ -395,15 +417,18 @@
|
||||
|
||||
|
||||
// Peuplement des boutons en fonction des assiduités
|
||||
boutons = `
|
||||
<input type="checkbox" name="matin-${etudid}" id="matin-${etudid}"
|
||||
class="rbtn present" value="present">
|
||||
let boutons = `
|
||||
<input type="checkbox" name="matin-${etudid}" id="matin-${etudid}"
|
||||
class="rbtn retard" value="retard">
|
||||
<input type="checkbox" name="matin-${etudid}" id="matin-${etudid}"
|
||||
class="rbtn absent" value="absent">
|
||||
`
|
||||
|
||||
if (!non_present) {
|
||||
boutons = `<input type="checkbox" name="matin-${etudid}" id="matin-${etudid}"
|
||||
class="rbtn present" value="present">`+boutons;
|
||||
}
|
||||
|
||||
// matin
|
||||
tdMatin.innerHTML = boutons
|
||||
tdMatin.setAttribute("assiduite_id", "")
|
||||
@ -417,13 +442,15 @@
|
||||
|
||||
if (deb.isSame(morningPeriod.deb, "minutes") && fin.isSame(morningPeriod.fin, "minutes")) {
|
||||
let etat = assi.etat.toLowerCase();
|
||||
tdMatin.querySelector(`[value="${etat}"]`).checked = true;
|
||||
const input = tdMatin.querySelector(`[value="${etat}"]`)
|
||||
if (input) {
|
||||
input.checked = true;
|
||||
}
|
||||
tdMatin.setAttribute("assiduite_id", assi.assiduite_id);
|
||||
} else {
|
||||
tdMatin.innerHTML = ""
|
||||
tdMatin.innerHTML = img_conflit;
|
||||
tdMatin.querySelector(".conflit_calendar").href = `calendrier_assi_etud?etudid=${etudid}`;
|
||||
tdMatin.classList.add("conflit");
|
||||
tdMatin.title = "Des assiduités existent déjà pour cette période"
|
||||
tdMatin.setAttribute("data-tooltip", "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -440,13 +467,15 @@
|
||||
|
||||
if (deb.isSame(afternoonPeriod.deb, "minutes") && fin.isSame(afternoonPeriod.fin, "minutes")) {
|
||||
let etat = assi.etat.toLowerCase();
|
||||
tdApresmidi.querySelector(`[value="${etat}"]`).checked = true;
|
||||
const input = tdApresmidi.querySelector(`[value="${etat}"]`)
|
||||
if (input) {
|
||||
input.checked = true;
|
||||
}
|
||||
tdApresmidi.setAttribute("assiduite_id", assi.assiduite_id);
|
||||
} else {
|
||||
tdApresmidi.innerHTML = ""
|
||||
tdApresmidi.innerHTML = img_conflit;
|
||||
tdApresmidi.querySelector(".conflit_calendar").href = `calendrier_assi_etud?etudid=${etudid}`;
|
||||
tdApresmidi.classList.add("conflit");
|
||||
tdApresmidi.title = "Des assiduités existent déjà pour cette période"
|
||||
tdApresmidi.setAttribute("data-tooltip", "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,16 +483,29 @@
|
||||
}
|
||||
|
||||
document.querySelectorAll("td .rbtn").forEach((el) => {
|
||||
el.addEventListener("click", (e) => {
|
||||
el.addEventListener("click", async (e) => {
|
||||
|
||||
if (readonly) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
let target = e.target;
|
||||
let parent = target.parentElement;
|
||||
|
||||
let isCancelled = await actionButton(target, !target.checked);
|
||||
if (isCancelled) {
|
||||
e.preventDefault();
|
||||
target.checked = !target.checked;
|
||||
return;
|
||||
}
|
||||
|
||||
let inputs = parent.querySelectorAll(".rbtn");
|
||||
inputs.forEach((input) => {
|
||||
if (input != target) {
|
||||
input.checked = false;
|
||||
}
|
||||
});
|
||||
actionButton(target, !target.checked);
|
||||
});
|
||||
});
|
||||
|
||||
@ -507,10 +549,109 @@
|
||||
function allPresent(day, time) {
|
||||
// Version naive : coche tous les boutons de la colonne
|
||||
// TODO - Optimiser avec une seule requête API
|
||||
let inputs = document.querySelectorAll(`td[day="${day}"][time="${time}"] .rbtn[value="present"]`);
|
||||
inputs.forEach((input) => {
|
||||
input.click();
|
||||
let tds = document.querySelectorAll(`td[day="${day}"][time="${time}"]`);
|
||||
const real_time = time == "am" ? "matin" : "apresmidi";
|
||||
const assi = {
|
||||
etat: "present",
|
||||
moduleimpl_id: document.getElementById("moduleimpl_select").value,
|
||||
date_debut: new Date(days[day].date.format('YYYY-MM-DD') + "T" + temps[real_time].debut).toFakeIso(),
|
||||
date_fin: new Date(days[day].date.format('YYYY-MM-DD') + "T" + temps[real_time].fin).toFakeIso(),
|
||||
}
|
||||
|
||||
let toCreate = []; // [{etudid:<int>}]
|
||||
let toEdit = [];// [{etudid:<int>, assiduite_id:<int>}]
|
||||
|
||||
tds.forEach((td) => {
|
||||
// on ne touche pas aux conflits
|
||||
if (td.classList.contains("conflit")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tr = td.parentElement;
|
||||
const etudid = Number(tr.getAttribute("etudid"));
|
||||
|
||||
const assiduite_id = td.getAttribute("assiduite_id");
|
||||
if (assiduite_id == "") {
|
||||
toCreate.push({ etudid: etudid });
|
||||
} else {
|
||||
toEdit.push({ etudid: etudid, assiduite_id: Number(assiduite_id) });
|
||||
}
|
||||
})
|
||||
|
||||
// Création
|
||||
toCreate = toCreate.map((el) => {
|
||||
return {
|
||||
...assi,
|
||||
etudid: el.etudid,
|
||||
}
|
||||
});
|
||||
|
||||
// Modification
|
||||
toEdit = toEdit.map((el) => {
|
||||
return {
|
||||
...assi,
|
||||
etudid: el.etudid,
|
||||
assiduite_id: el.assiduite_id,
|
||||
}
|
||||
});
|
||||
|
||||
// Appel API
|
||||
let counts = {
|
||||
create: toCreate.length,
|
||||
edit: toEdit.length
|
||||
}
|
||||
const promiseCreate = async_post(
|
||||
`../../api/assiduites/create`,
|
||||
toCreate,
|
||||
async (data) => {
|
||||
if (data.errors.length > 0) {
|
||||
console.error(data.errors);
|
||||
data.errors.forEach((err) => {
|
||||
let obj = toCreate[err.indice];
|
||||
let etu = etuds.find((el) => el.id == obj.etudid);
|
||||
|
||||
const text = document.createTextNode(`Erreur pour ${etu.nom} ${etu.prenom} : ${err.message}`);
|
||||
const toast = generateToast(text, "var(--color-error)", 10);
|
||||
pushToast(toast);
|
||||
});
|
||||
}
|
||||
counts.create = data.success.length;
|
||||
},
|
||||
(error) => {
|
||||
console.error("Erreur lors de la création de l'assiduité", error);
|
||||
}
|
||||
);
|
||||
const promiseEdit = async_post(
|
||||
`../../api/assiduites/edit`,
|
||||
toEdit,
|
||||
async (data) => {
|
||||
if (data.errors.length > 0) {
|
||||
console.error(data.errors);
|
||||
data.errors.forEach((err) => {
|
||||
let obj = toEdit[err.indice];
|
||||
let etu = etuds.find((el) => el.id == obj.etudid);
|
||||
|
||||
const text = document.createTextNode(`Erreur pour ${etu.nom} ${etu.prenom} : ${err.message}`);
|
||||
const toast = generateToast(text, "var(--color-error)");
|
||||
pushToast(toast);
|
||||
});
|
||||
}
|
||||
counts.edit = data.success.length;
|
||||
},
|
||||
(error) => {
|
||||
console.error("Erreur lors de l'édition de l'assiduité", error);
|
||||
}
|
||||
);
|
||||
|
||||
// Affiche un loader
|
||||
afficheLoader();
|
||||
|
||||
Promise.all([promiseCreate, promiseEdit]).then(async () => {
|
||||
retirerLoader();
|
||||
await recupAssiduitesHebdo(updateTable);
|
||||
envoiToastTous("present", counts.create + counts.edit);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
@ -654,6 +795,15 @@ document.addEventListener("DOMContentLoaded", ()=>{
|
||||
Le matin <a href="#" id="text-matin" title="Cliquer pour modifier les horaires">9h à 12h</a> et l'après-midi de <a href="#" id="text-apresmidi" title="Cliquer pour modifier les horaires">13h à 17h</a>
|
||||
</h3>
|
||||
|
||||
{% if readonly %}
|
||||
<h4
|
||||
title="Vous n'avez pas les permissions nécessaires afin de modifier les assiduités"
|
||||
data-tooltip
|
||||
>
|
||||
Ouvert en mode <span class="rouge">lecture seule</span>.
|
||||
</h4>
|
||||
|
||||
{% endif %}
|
||||
<table id="table">
|
||||
<thead>
|
||||
<tr class="premier">
|
||||
@ -676,8 +826,9 @@ document.addEventListener("DOMContentLoaded", ()=>{
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% if not readonly and not non_present %}
|
||||
<tr>
|
||||
{# Ne pas afficher si preference "non presences" #}
|
||||
{# Ne pas afficher si preference "non presences" / "readonly" #}
|
||||
<th></th>
|
||||
{% for jour in hebdo_jours %}
|
||||
{% if not jour[0] or jour[1][0] not in ['Samedi', 'Dimanche'] %}
|
||||
@ -689,13 +840,13 @@ document.addEventListener("DOMContentLoaded", ()=>{
|
||||
</th>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
{% endif %}
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for etud in etudiants %}
|
||||
<tr etudid="{{etud.etudid}}" id="row-{{etud.etudid}}">
|
||||
<td class="etudinfo" id="etud-{{etud.etudid}}">{{ etud.nomprenom }}</td>
|
||||
<td class="etudinfo" id="etud-{{etud.etudid}}">{{ etud.nom_prenom() }}</td>
|
||||
{# Sera rempli en JS #}
|
||||
{# Ne pas afficher bouton présent si pref "non présences" #}
|
||||
{# <td>
|
||||
|
@ -2070,8 +2070,6 @@ def signal_assiduites_hebdo():
|
||||
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
|
||||
)
|
||||
|
||||
# TODO vérif perm AbsChange -> readonly
|
||||
|
||||
# Gestion des jours
|
||||
jours: dict[str, list[str]] = {
|
||||
"lun": [
|
||||
@ -2113,12 +2111,19 @@ def signal_assiduites_hebdo():
|
||||
|
||||
return render_template(
|
||||
"assiduites/pages/signal_assiduites_hebdo.j2",
|
||||
title="Assiduité: saisie hebdomadaire",
|
||||
gr=gr_tit,
|
||||
etudiants=etudiants,
|
||||
moduleimpl_select=_module_selector(
|
||||
formsemestre=formsemestre, moduleimpl_id=moduleimpl_id
|
||||
),
|
||||
hebdo_jours=hebdo_jours,
|
||||
readonly=not current_user.has_permission(Permission.AbsChange),
|
||||
non_present=sco_preferences.get_preference(
|
||||
"non_present",
|
||||
formsemestre_id=formsemestre_id,
|
||||
dept_id=g.scodoc_dept_id,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user