forked from ScoDoc/ScoDoc
312 lines
9.7 KiB
Django/Jinja
312 lines
9.7 KiB
Django/Jinja
<div class="assiduite-bubble">
|
|
|
|
</div>
|
|
|
|
<script>
|
|
|
|
const mt_start = {{ t_start }};
|
|
const mt_end = {{ t_end }};
|
|
/**
|
|
* Création de la minitiline d'un étudiant
|
|
* @param {Array[Assiduité]} assiduitesArray
|
|
* @returns {HTMLElement} l'élément correspondant à la mini timeline
|
|
*/
|
|
function createMiniTimeline(assiduitesArray, day = null) {
|
|
const array = [...assiduitesArray];
|
|
const dateiso = day == null ? document.getElementById("tl_date").value : day;
|
|
const timeline = document.createElement("div");
|
|
timeline.className = "mini-timeline";
|
|
if (isSingleEtud()) {
|
|
timeline.classList.add("single");
|
|
}
|
|
const timelineDate = moment(dateiso).startOf("day");
|
|
const dayStart = timelineDate.clone().add(mt_start, "hours");
|
|
const dayEnd = timelineDate.clone().add(mt_end, "hours");
|
|
const dayDuration = moment.duration(dayEnd.diff(dayStart)).asMinutes();
|
|
|
|
timeline.appendChild(setMiniTick(timelineDate, dayStart, dayDuration));
|
|
|
|
|
|
|
|
if (day == null) {
|
|
const tlTimes = getTimeLineTimes();
|
|
array.push({
|
|
date_debut: tlTimes.deb.format(),
|
|
date_fin: tlTimes.fin.format(),
|
|
etat: "CRENEAU",
|
|
});
|
|
}
|
|
|
|
array.forEach((assiduité) => {
|
|
const startDate = moment(assiduité.date_debut);
|
|
const endDate = moment(assiduité.date_fin);
|
|
|
|
if (startDate.isBefore(dayStart)) {
|
|
startDate.startOf("day").add(mt_start, "hours");
|
|
}
|
|
|
|
if (endDate.isAfter(dayEnd)) {
|
|
endDate.startOf("day").add(mt_end, "hours");
|
|
}
|
|
|
|
const block = document.createElement("div");
|
|
block.className = "mini-timeline-block";
|
|
const duration = moment.duration(endDate.diff(startDate)).asMinutes();
|
|
const startOffset = moment.duration(startDate.diff(dayStart)).asMinutes();
|
|
const leftPercentage = (startOffset / dayDuration) * 100;
|
|
const widthPercentage = (duration / dayDuration) * 100;
|
|
|
|
block.style.left = `${leftPercentage}%`;
|
|
block.style.width = `${widthPercentage}%`;
|
|
|
|
if (assiduité.etat != "CRENEAU") {
|
|
block.addEventListener("click", () => {
|
|
let deb = startDate.hours() + startDate.minutes() / 60;
|
|
let fin = endDate.hours() + endDate.minutes() / 60;
|
|
deb = Math.max(mt_start, deb);
|
|
fin = Math.min(mt_end, fin);
|
|
|
|
if (day == null) setPeriodValues(deb, fin);
|
|
if (isSingleEtud()) {
|
|
updateSelectedSelect(getCurrentAssiduiteModuleImplId());
|
|
updateJustifyBtn();
|
|
}
|
|
});
|
|
//ajouter affichage assiduites on over
|
|
setupAssiduiteBuble(block, assiduité);
|
|
}
|
|
|
|
const action = (justificatifs) => {
|
|
if (justificatifs.length > 0) {
|
|
let j = "invalid_justified";
|
|
|
|
justificatifs.forEach((ju) => {
|
|
if (ju.etat == "VALIDE") {
|
|
j = "justified";
|
|
}
|
|
});
|
|
|
|
block.classList.add(j);
|
|
}
|
|
};
|
|
|
|
if (assiduité.etudid) {
|
|
getJustificatifFromPeriod(
|
|
{
|
|
deb: new moment.tz(assiduité.date_debut, TIMEZONE),
|
|
fin: new moment.tz(assiduité.date_fin, TIMEZONE),
|
|
},
|
|
assiduité.etudid,
|
|
action
|
|
);
|
|
}
|
|
|
|
switch (assiduité.etat) {
|
|
case "PRESENT":
|
|
block.classList.add("present");
|
|
break;
|
|
case "RETARD":
|
|
block.classList.add("retard");
|
|
break;
|
|
case "ABSENT":
|
|
block.classList.add("absent");
|
|
break;
|
|
case "CRENEAU":
|
|
block.classList.add("creneau");
|
|
break;
|
|
default:
|
|
block.style.backgroundColor = "white";
|
|
}
|
|
|
|
timeline.appendChild(block);
|
|
});
|
|
|
|
return timeline;
|
|
}
|
|
|
|
/**
|
|
* 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 setupAssiduiteBuble(el, assiduite) {
|
|
if (!assiduite) return;
|
|
el.addEventListener("mouseenter", (event) => {
|
|
const bubble = document.querySelector(".assiduite-bubble");
|
|
bubble.className = "assiduite-bubble";
|
|
bubble.classList.add("is-active", assiduite.etat.toLowerCase());
|
|
|
|
bubble.innerHTML = "";
|
|
|
|
const idDiv = document.createElement("div");
|
|
idDiv.className = "assiduite-id";
|
|
idDiv.textContent = `ID: ${assiduite.assiduite_id}`;
|
|
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 userIdDiv = document.createElement("div");
|
|
userIdDiv.className = "assiduite-user_id";
|
|
userIdDiv.textContent = `saisi le ${formatDateModal(
|
|
assiduite.entry_date,
|
|
"à"
|
|
)} \npar ${getUserFromId(assiduite.user_id)}`;
|
|
bubble.appendChild(userIdDiv);
|
|
|
|
bubble.style.left = `${event.clientX - bubble.offsetWidth / 2}px`;
|
|
bubble.style.top = `${event.clientY + 20}px`;
|
|
});
|
|
el.addEventListener("mouseout", () => {
|
|
const bubble = document.querySelector(".assiduite-bubble");
|
|
bubble.classList.remove("is-active");
|
|
});
|
|
}
|
|
|
|
function setMiniTick(timelineDate, dayStart, dayDuration) {
|
|
const endDate = timelineDate.clone().set({ 'hour': 13, 'minute': 0 });
|
|
const duration = moment.duration(endDate.diff(dayStart)).asMinutes();
|
|
const widthPercentage = (duration / dayDuration) * 100;
|
|
const tick = document.createElement('span');
|
|
tick.className = "mini_tick"
|
|
tick.textContent = "13h"
|
|
tick.style.left = `${widthPercentage}%`
|
|
|
|
return tick
|
|
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.assiduite-bubble {
|
|
position: fixed;
|
|
display: none;
|
|
background-color: #f9f9f9;
|
|
border-radius: 5px;
|
|
padding: 8px;
|
|
border: 3px solid #ccc;
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
font-size: 12px;
|
|
line-height: 1.4;
|
|
z-index: 500;
|
|
}
|
|
|
|
.assiduite-bubble.is-active {
|
|
display: block;
|
|
}
|
|
|
|
.assiduite-bubble::before {
|
|
content: "";
|
|
position: absolute;
|
|
bottom: 100%;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
border-width: 6px;
|
|
border-style: solid;
|
|
border-color: transparent transparent #f9f9f9 transparent;
|
|
}
|
|
|
|
.assiduite-bubble::after {
|
|
content: "";
|
|
position: absolute;
|
|
bottom: 100%;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
border-width: 5px;
|
|
border-style: solid;
|
|
border-color: transparent transparent #ccc transparent;
|
|
}
|
|
|
|
.assiduite-id,
|
|
.assiduite-period,
|
|
.assiduite-state,
|
|
.assiduite-user_id {
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.assiduite-bubble.absent {
|
|
border-color: #F1A69C !important;
|
|
}
|
|
|
|
.assiduite-bubble.present {
|
|
border-color: #9CF1AF !important;
|
|
}
|
|
|
|
.assiduite-bubble.retard {
|
|
border-color: #F1D99C !important;
|
|
}
|
|
|
|
.mini-timeline {
|
|
height: 7px;
|
|
border: 1px solid black;
|
|
position: relative;
|
|
background-color: white;
|
|
}
|
|
|
|
.mini-timeline.single {
|
|
height: 9px;
|
|
}
|
|
|
|
.mini-timeline-block {
|
|
position: absolute;
|
|
height: 100%;
|
|
z-index: 1;
|
|
}
|
|
|
|
#page-assiduite-content .mini-timeline-block {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.mini_tick {
|
|
position: absolute;
|
|
text-align: start;
|
|
top: -40px;
|
|
transform: translateX(-50%);
|
|
z-index: 50;
|
|
|
|
}
|
|
|
|
.mini_tick::after {
|
|
display: block;
|
|
content: "|";
|
|
position: absolute;
|
|
bottom: -2px;
|
|
z-index: 2;
|
|
}
|
|
|
|
.mini-timeline-block.creneau {
|
|
outline: 3px solid #7059FF;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.mini-timeline-block.absent {
|
|
background-color: #F1A69C !important;
|
|
}
|
|
|
|
.mini-timeline-block.present {
|
|
background-color: #9CF1AF !important;
|
|
}
|
|
|
|
.mini-timeline-block.retard {
|
|
background-color: #F1D99C !important;
|
|
}
|
|
|
|
.mini-timeline-block.justified {
|
|
background-image: repeating-linear-gradient(135deg, transparent, transparent 4px, #7059FF 4px, #7059FF 8px);
|
|
}
|
|
|
|
.mini-timeline-block.invalid_justified {
|
|
background-image: repeating-linear-gradient(135deg, transparent, transparent 4px, #d61616 4px, #d61616 8px);
|
|
}
|
|
</style> |