aboutsummaryrefslogtreecommitdiff
path: root/src/mass-graduation.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/mass-graduation.js')
-rw-r--r--src/mass-graduation.js357
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 = "&#128065"
+ 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();
+}
+