diff options
Diffstat (limited to 'src/mass-graduation.js')
| -rw-r--r-- | src/mass-graduation.js | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/src/mass-graduation.js b/src/mass-graduation.js new file mode 100644 index 0000000..3cbf32a --- /dev/null +++ b/src/mass-graduation.js @@ -0,0 +1,357 @@ +import { + OBSERVATION_TYPES, + GraduationChange, + submitGraduationChange, + Observation, + submitObservation +} from "./graduation-ENV.js"; + +import { fetchGroups } from "./group.js"; +import { initSelection } from "./selection.js"; +import { getName, DATETIME_FMT, datetimeStringNow } from "./utils-ENV.js"; + +let group; +let name; + +function toggle(btn, others) { + if (btn.innerHTML === "X") { + btn.innerHTML = "o"; + } else { + btn.innerHTML = "X"; + if (others) { + for (const other of others) + other.innerHTML = "o"; + } + } + + document.getElementById("submit-mass-graduation").style.display = "inline"; + document.getElementById("submit-mass-graduation-state").innerHTML = ""; +} + +function observationClickHandler(li) { + let observationDiv = li.observationDiv; + // Build the observation container + if(!observationDiv) { + li.style.background = "lightgray"; + + observationDiv = document.createElement("div"); + // Remember the observation div for this student + li.observationDiv = observationDiv; + observationDiv.id = `${li.student.name}-observation-container`; + observationDiv.classList.add("group-member-observation-container"); + li.appendChild(observationDiv); + + const obsTbl = document.createElement("table"); + obsTbl.classList.add("group-member-observation-table"); + observationDiv.appendChild(obsTbl); + + const obsTh = document.createElement("thead"); + obsTh.innerHTML = ` +<tr> + <th></th> + <th class="group-member-observation-table-yes">Ja</th> + <th class="group-member-observation-table-no">Nein</th> + <th class="group-member-observation-table-maybe">Kann ich nicht beurteilen</th> +</tr>`; + + obsTbl.appendChild(obsTh); + + const obsTbdy = document.createElement("tbody"); + obsTbl.appendChild(obsTbdy); + + for (const obsType of OBSERVATION_TYPES) { + const obsTr = document.createElement("tr"); + + const obsDesc = document.createElement("td"); + obsDesc.innerHTML = obsType; + obsDesc.classList.add("group-member-observation-table-description"); + obsTr.appendChild(obsDesc); + + const obsYes = document.createElement("td"); + obsYes.innerHTML = "o"; + obsYes.dataset.yes = "true"; + obsYes.classList.add("group-member-observation-table-yes"); + obsTr.appendChild(obsYes); + + const obsNo = document.createElement("td"); + obsNo.innerHTML = "o"; + obsNo.dataset.no = "true"; + obsNo.classList.add("group-member-observation-table-no"); + obsTr.appendChild(obsNo); + + const obsMaybe = document.createElement("td"); + obsMaybe.innerHTML = "X"; + obsMaybe.dataset.maybe = "true"; + obsMaybe.classList.add("group-member-observation-table-maybe"); + obsTr.appendChild(obsMaybe); + + obsYes.addEventListener("click", () => { + toggle(obsYes, [obsNo, obsMaybe]); + }); + obsNo.addEventListener("click", () => { + toggle(obsNo, [obsYes, obsMaybe]); + }); + obsMaybe.addEventListener("click", () => { + toggle(obsMaybe, [obsYes, obsNo]); + }); + + obsTbdy.appendChild(obsTr); + } + // Toggle the observation container visibility + } else { + if (observationDiv.style.display === "none") { + observationDiv.style.display = "block"; + li.style.background = "lightgray"; + + } else { + observationDiv.style.display = "none"; + li.style.background = "unset"; + } + } +} + +async function loadGroup(selected) { + group = selected; + const students = await group.getStudents(); + let graduationPromises = []; + document.getElementById("group-content").style.display = "block"; + + const ul = document.getElementById("group-members"); + // Clear group list + ul.innerHTML = ""; + + for (const student of students) { + const graduationPromise = student.getGraduation(); + + const li = document.createElement("li"); + li.classList.add("group-member") + // Remember the student of the entry + li.student = student; + + const i = document.createElement("img"); + i.classList.add("group-member-icon") + graduationPromise.then((graduation) => { + i.src = graduation.getIcon(); + }); + li.appendChild(i); + + const n = document.createElement("span"); + n.classList.add("group-member-name") + n.innerHTML = `${student.name}`; + li.appendChild(n); + + const ob = document.createElement("button"); + ob.classList.add("group-member-observation-icon") + + graduationPromise.then((graduation) => { + if (!graduation.isObserved()) { + return; + } + ob.innerHTML = "👁" + ob.addEventListener("click", () => observationClickHandler(li) ); + }); + graduationPromises.push(graduationPromise); + + li.appendChild(ob); + + for (const col of ["green", "orange", "red"]) { + const b = document.createElement("button"); + b.classList.add(`group-member-${col}`) + b.innerHTML = "o"; + b.addEventListener("click", () => toggle(b) ); + li.appendChild(b); + } + + const textarea = document.createElement("textarea"); + textarea.classList.add("group-member-point-reason"); + li.appendChild(textarea); + + const p = document.createElement("button"); + p.classList.add("group-member-print") + p.innerHTML = "🖶"; + p.addEventListener("click", () => printNote(li) ); + li.appendChild(p); + + ul.appendChild(li); + } + + const graduations = await Promise.all(graduationPromises); + let observations = graduations.filter( + (g) => g.observationRequested || (g.observation && !g.observation.end) + ); + + const observationReuqestsContainer = document.getElementById("observation-requests-container"); + + if (observations.length == 0) { + observationReuqestsContainer.style.display = "none"; + return; + } else { + observationReuqestsContainer.style.display = "unset"; + } + + const observationReuqestsNode = document.getElementById("observation-requests"); + observationReuqestsNode.innerHTML = ""; + observations.sort((g1, g2) => { + let g1D, g2D; + g1D = g1.observationRequested ? g1.observationRequested : g1.observation.start; + g2D = g2.observationRequested ? g2.observationRequested : g2.observation.start; + return g1D - g2D; + }); + + for (const graduation of observations) { + const row = document.createElement("tr"); + const iconCell = document.createElement("td"); + const icon = document.createElement("img"); + icon.src = graduation.getIcon(); + row.appendChild(iconCell); + + const nameCell = document.createElement("td"); + nameCell.innerHTML = `${graduation.student.name}`; + row.appendChild(nameCell); + + const dateCell = document.createElement("td"); + let date; + if (graduation.observationRequested) { + date = graduation.observationRequested; + } else { + date = graduation.observation.start; + } + dateCell.innerHTML = DATETIME_FMT.format(date); + row.appendChild(dateCell); + + const btnCell = document.createElement("td"); + if (graduation.observation && !graduation.observation.ready()) { + btnCell.innerHTML = "In Beobachtungsphase"; + } else { + const startBtn = document.createElement("button"); + if (graduation.observationRequested) { + startBtn.addEventListener("click", () => { + graduation.startObservation(); + //TODO(muhq): Add observation icon-button. + startBtn.remove(); + btnCell.innerHTML = "In Beobachtungsphase"; + }); + startBtn.innerHTML = `Beobachtungsphase beginnen`; + startBtn.classList.add("start-observation"); + } else { + startBtn.addEventListener("click", () => { + window.open(`/mod/page/view.php?id=93017047&userToLoad=${graduation.student.id}`, '_blank'); + }); + startBtn.innerHTML = `Graduierung abschließen`; + startBtn.classList.add("end-observation"); + } + btnCell.appendChild(startBtn); + } + row.appendChild(btnCell); + + observationReuqestsNode.appendChild(row); + } +} + +function submitMassGraduation() { + const state = document.getElementById("submit-mass-graduation-state"); + state.innerHTML = ""; + state.classList.add("submit-mass-graduation-inprogress"); + state.style.display = "unset"; + + // TODO(muhq): await graduation promises + + let promises = []; + for(const li of document.querySelectorAll("li.group-member")) { + const reason = li.querySelector(".group-member-point-reason").value; + const student = li.student; + if (li.querySelector(".group-member-green").innerHTML === "X") { + promises.push(submitGraduationChange(student, GraduationChange.newGreenPointChange(reason, name))); + } + if (li.querySelector(".group-member-orange").innerHTML === "X") { + promises.push(submitGraduationChange(student, GraduationChange.newOrangePointChange(reason, name))); + } + if (li.querySelector(".group-member-red").innerHTML === "X") { + promises.push(submitGraduationChange(student, GraduationChange.newRedPointChange(reason, name))); + } + if (li.observationDiv) { + let status = []; + for (const row of li.observationDiv.querySelectorAll("tbody > tr")) { + if (row.querySelector('td[data-yes="true"]').innerHTML === "X") + status.push("yes"); + else if (row.querySelector('td[data-no="true"]').innerHTML === "X") + status.push("no"); + else + status.push(""); + } + promises.push(submitObservation(student, new Observation(new Date(), status))); + } + } + + Promise.all(promises).then(() => { + state.style.display = "inline"; + state.innerHTML = "✓"; + state.style.color = "green"; + for (const li of document.querySelectorAll("li.group-member")) { + if (!li.observationDiv) + continue; + li.observationDiv.remove(); + li.observationDiv = null; + } + }).catch((error) => { + state.style.display = "inline"; + state.innerHTML = "X"; + state.style.color = "red"; + console.log(error); + }).finally(() => { + state.classList.remove("submit-mass-graduation-inprogress"); + }); +} + +let prePrintBody = null; +function printNote(li) { + // save the current DOM + prePrintBody = document.body; + + // prepare the printable red point notice + const printBdy = document.createElement("body"); + const reason = li.querySelector(".group-member-point-reason").value; + const dateStr = datetimeStringNow(); + let pointType = ""; + if (li.querySelector(".group-member-orange").innerHTML === "X") { + pointType = "Oranger Punkt"; + } + if (li.querySelector(".group-member-red").innerHTML === "X") { + pointType = "Roter Punkt"; + } + + printBdy.innerHTML = ` +<h2>Dokuzettel</h2> +<h3>${pointType}</h3> +<p>Schüler*in: ${li.student.name}</p> +<p>Datum: ${dateStr}</p> +<p>Lehrkraft: ${name}</p> +<p>Klassenleitung: TODO</p> +<h3>Begründung</h3> +<p>${reason}</p> +`; + + document.body = printBdy; + print(); + // Restore the DOM after printing the red point note + document.body = prePrintBody; +} + +async function init() { + document.getElementById("submit-mass-graduation").addEventListener("click", submitMassGraduation); + name = getName(); + + initSelection( + "group-selection", + async function() { return (await fetchGroups()).values(); }, + (group) => `${group.name}`, + loadGroup, + ); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); +} else { + init(); +} + |
