aboutsummaryrefslogtreecommitdiff
path: root/cockpit
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2026-06-24 09:18:26 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2026-06-24 09:18:26 +0200
commitaf8585faa1aa7c39564c583963349c4a2922df9c (patch)
tree5a806a738a76e5f928e68e4def47e0b3a857d490 /cockpit
parent13f9914757b2a72e77369859bbaec35339f31446 (diff)
downloadbycs-sol-af8585faa1aa7c39564c583963349c4a2922df9c.tar.gz
bycs-sol-af8585faa1aa7c39564c583963349c4a2922df9c.zip
cockpit: finish prototype UI
* remove process and calendar * add observation period * improve mocking
Diffstat (limited to 'cockpit')
-rw-r--r--cockpit/index.css14
-rw-r--r--cockpit/index.html83
-rw-r--r--cockpit/js/cockpit.js210
3 files changed, 217 insertions, 90 deletions
diff --git a/cockpit/index.css b/cockpit/index.css
index 810442e..a206067 100644
--- a/cockpit/index.css
+++ b/cockpit/index.css
@@ -100,6 +100,11 @@
flex-direction: column;
}
+#student-observation {
+ margin-left: 2rem;
+ margin-bottom: 1rem;
+}
+
.student-info-mid-element {
padding: 5pt;
border: black solid 0.2pt;
@@ -178,3 +183,12 @@
#student-info-bonus-amount {
font-size: 2rem;
}
+
+.graduation-dropdown > summary {
+ background: lightgray;
+ border: black solid 0.2pt;
+ border-radius: 10px;
+ padding: 0.25rem;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+}
diff --git a/cockpit/index.html b/cockpit/index.html
index d0bb0c7..ddf8005 100644
--- a/cockpit/index.html
+++ b/cockpit/index.html
@@ -48,6 +48,9 @@
</div>
</div>
+ <div id="student-observation" class="student-info-banner">
+ </div>
+
<div id="student-info-mid" class="student-info-banner">
<div id="student-info-green" class="student-info-mid-element">
⚫Grüne Punkte <span class="student-info-points" id="student-info-points-green">0</span>
@@ -70,32 +73,70 @@
<button id="student-info-point-reason-submit">&crarr;</button>
</div>
- <div id="student-info-bottom" class="student-info-banner">
- <div id="student-info-stickers-container" class="student-info-bottom-element">
- Monstersticker
- <div id="student-info-stickers">
- </div>
- </div>
- <div id="student-info-bonus-container" class="student-info-bottom-element">
- Bonuskarten
- <div id="student-info-bonus-row">
- <img></img>
- <span id="student-info-bonus-amount">0</span>
- </div>
- </div>
- </div>
+ <!-- <div id="student-info-bottom" class="student-info-banner"> -->
+ <!-- <div id="student-info-stickers-container" class="student-info-bottom-element"> -->
+ <!-- Monstersticker -->
+ <!-- <div id="student-info-stickers"> -->
+ <!-- </div> -->
+ <!-- </div> -->
+ <!-- <div id="student-info-bonus-container" class="student-info-bottom-element"> -->
+ <!-- Bonuskarten -->
+ <!-- <div id="student-info-bonus-row"> -->
+ <!-- <img></img> -->
+ <!-- <span id="student-info-bonus-amount">0</span> -->
+ <!-- </div> -->
+ <!-- </div> -->
+ <!-- </div> -->
</div>
- <details id="progress">
- <summary>Lernfortschritt</summary>
- </details>
+ <!-- <details id="progress"> -->
+ <!-- <summary>Lernfortschritt</summary> -->
+ <!-- </details> -->
- <details id="calendar">
- <summary>Kalender</summary>
- </details>
+ <!-- <details id="calendar"> -->
+ <!-- <summary>Kalender</summary> -->
+ <!-- </details> -->
- <details id="graduation">
+ <details id="graduation" data-availability="if-lehrer">
<summary>Graduierung</summary>
+
+ <details id="graduation-changes-container" class="graduation-dropdown">
+ <summary>Übersicht über Grüne, Orangene und Rote Punkte</summary>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Datum</th>
+ <th>Grund</th>
+ <th>Coach</th>
+ </tr>
+ </thead>
+ <tbody id="graduation-changes">
+ </tbody>
+ </table>
+ </details>
+
+ <details id="graduation-current-observation-period-container" class="graduation-dropdown">
+ <summary>Aktueller Beobachtungszeitraum</summary>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th></th>
+ <th>Ja</th>
+ <th>Nein</th>
+ </tr>
+ </thead>
+ <tbody id="graduation-current-observation-period">
+ </tbody>
+ </table>
+ </details>
+
+ <details id="graduation-observation-periods-container" class="graduation-dropdown">
+ <summary>Vergangene Beobachtungszeiträume</summary>
+ <table class="table table-striped">
+ <tbody id="graduation-observation-periods">
+ </tbody>
+ </table>
+ </details>
</details>
</div>
</body>
diff --git a/cockpit/js/cockpit.js b/cockpit/js/cockpit.js
index b773f5c..f8ee8e9 100644
--- a/cockpit/js/cockpit.js
+++ b/cockpit/js/cockpit.js
@@ -1,16 +1,21 @@
-import {
- fetchSubjectsMock as fetchSubjects,
- fetchProgressMock as fetchProgress,
-} from "../../js/mock.js";
+// import {
+ // fetchSubjectsMock as fetchSubjects,
+ // fetchProgressMock as fetchProgress,
+// } from "../../js/mock.js";
import {
+ LEVEL_NAMES,
GraduationChange,
fetchGraduation,
submitGraduationChange
} from "../../js/graduation-ENV.js";
-import { Student, fetchStudent, fetchStudents } from "../../js/student-ENV.js";
-import { isTeacher as getIsTeacher } from "../../js/utils-ENV.js";
+import { fetchStudent, fetchStudents } from "../../js/student-ENV.js";
+import {
+ isTeacher as getIsTeacher,
+ getCurrentName,
+ getUserId,
+} from "../../js/utils-ENV.js";
import { initSelection } from "../../js/selection.js";
let isTeacher;
@@ -18,30 +23,20 @@ let firstname;
let lastname;
let student;
-function initCurrentName() {
- const autoNameDiv = document.getElementById("auto-name");
- firstname = autoNameDiv.children[0].innerHTML;
- lastname = autoNameDiv.children[1].innerHTML;
- autoNameDiv.remove();
-}
-
-async function loadNewStudent(id, name) {
- if (isTeacher) {
- student = await fetchStudent(id, name);
- } else {
- student = new Student(id, name);
- }
- await loadStudent(student);
-}
-
async function loadStudent(studentToLoad) {
student = studentToLoad;
fetchAndUpdateStudentInfo();
- updateStudentCalendar();
- updateStudentProgress();
+ // updateStudentCalendar();
+ // updateStudentProgress();
+ // TODO(muhq): fetch graduation only once
updateStudentGraduation();
}
+async function loadNewStudent(id) {
+ student = await fetchStudent(id);
+ await loadStudent(student);
+}
+
function initStudentSelection() {
initSelection(
"student-selection",
@@ -96,6 +91,7 @@ function pointClickHandler(color) {
submitGraduationChange(student, change);
textareaDiv.style.display = "none";
updateStudentInfo();
+ updateStudentGraduation();
}
// Use onEVENT to override any previous handler
textarea.onkeydown = function(e) {
@@ -132,7 +128,7 @@ function updateStudentInfo() {
if (student.graduation) {
const tag = document.getElementById("student-info-tag");
- tag.innerHTML = student.graduation.level;
+ tag.innerHTML = student.graduation.getLevelName();
tag.style.display = "block";
document.getElementById("student-info-points-green").innerHTML = student.graduation.green;
@@ -150,59 +146,131 @@ function updateStudentInfo() {
renderGraduationLevel(student.graduation, document.getElementById("student-info-level"));
- renderGraduationStickers(student.graduation, document.getElementById("student-info-stickers"));
- renderGraduationBonus(student.graduation, document.getElementById("student-info-stickers"));
+ // renderGraduationStickers(student.graduation, document.getElementById("student-info-stickers"));
+ // renderGraduationBonus(student.graduation, document.getElementById("student-info-stickers"));
+
+ renderObservationStatus(student.graduation, document.getElementById("student-observation"));
}
document.getElementById("student-content").style.display = "block";
}
function renderGraduationLevel(graduation, node) {
- node.innerHTML = graduation.level;
+ node.innerHTML = graduation.getLevelName();
}
-function renderGraduationStickers(graduation, node) {
-}
-
-function renderGraduationBonus(graduation, node) {
-}
-
-function newProgressBar(subject) {
- let bar = document.createElement("div");
- fetchProgress(subject).then((progress) => {
- bar.progress = progress;
- });
-
- let s1 = document.createElement("div");
- s1.onhover
-
- bar.appendChild(s1);
- let s2 = document.createElement("div");
- bar.appendChild(s2);
- let s3 = document.createElement("div");
- bar.appendChild(s3);
- return bar;
-}
-
-let selectedSubjects;
-async function updateStudentProgress() {
- selectedSubjects = await fetchSubjects(student);
-
- let prog = document.getElementById("progress");
- for(const subj of selectedSubjects) {
- let subjDiv = document.createElement("div");
- subjDiv.innerHTML = subj;
- subjDiv.appendChild(newProgressBar(subj))
- prog.appendChild(subjDiv);
+// function renderGraduationStickers(graduation, node) {
+ // node.innerHTML = "";
+// }
+
+// function renderGraduationBonus(graduation, node) {
+ // node.innerHTML = "";
+// }
+
+function renderObservationStatus(graduation, node) {
+ node.innerHTML = "";
+
+ let status;
+ if (isTeacher || graduation.isObserved()) {
+ status = document.createElement("span");
+ status.classList.add("student-observation-status");
+ if (graduation.isObserved()) {
+ status.innerHTML = '<span style="font-size: larger;">&#128065</span> Ich befinde mich in der Beobachtungsphase zum Levelaufstieg.';
+ } else {
+ status.innerHTML = "Nicht in Beobachtung.";
+ }
+ } else {
+ status = document.createElement("button");
+ status.classList.add("student-request-observation-button");
+ // Level is 1-based
+ status.innerHTML = `Ich will ${LEVEL_NAMES[graduation.level]} werden`;
+ status.addEventListener("click", async function() {
+ await graduation.requestObservation();
+ // Rerender the observation status
+ renderObservationStatus(graduation, node);
+ });
}
+ node.appendChild(status);
}
-async function updateStudentCalendar() {
- let cal = document.getElementById("calendar");
-}
+// function newProgressBar(subject) {
+ // let bar = document.createElement("div");
+ // fetchProgress(subject).then((progress) => {
+ // bar.progress = progress;
+ // });
+
+ // let s1 = document.createElement("div");
+ // s1.onhover
+
+ // bar.appendChild(s1);
+ // let s2 = document.createElement("div");
+ // bar.appendChild(s2);
+ // let s3 = document.createElement("div");
+ // bar.appendChild(s3);
+ // return bar;
+// }
+
+// let selectedSubjects;
+// async function updateStudentProgress() {
+ // selectedSubjects = await fetchSubjects(student);
+
+ // let prog = document.getElementById("progress");
+ // for(const subj of selectedSubjects) {
+ // let subjDiv = document.createElement("div");
+ // subjDiv.innerHTML = subj;
+ // subjDiv.appendChild(newProgressBar(subj))
+ // prog.appendChild(subjDiv);
+ // }
+// }
+
+// async function updateStudentCalendar() {
+ // let cal = document.getElementById("calendar");
+// }
async function updateStudentGraduation() {
- let graduation = document.getElementById("graduation");
+ if (!isTeacher) return;
+ const graduation = await student.getGraduation();
+
+ const changesTbl = document.getElementById("graduation-changes");
+ changesTbl.innerHTML = "";
+ for (const change of graduation.changes.filter(
+ (ch) => ["Grün", "Rot", "Orange"].includes(ch.change) ))
+ {
+ const changeTr = document.createElement("tr");
+ for (const key in change) {
+ if (key == "json" || key == "id" || key == "name") continue;
+
+ if (key == "change") {
+ switch(change.change) {
+ case "Grün":
+ changeTr.style.background = "green";
+ break;
+ case "Rot":
+ changeTr.style.background = "red";
+ break;
+ case "Orange":
+ changeTr.style.background = "orange";
+ break;
+ default:
+ alert(`unexpected change: ${change.change}`);
+ }
+ continue;
+ }
+
+ const value = change[key];
+ let fmt = "";
+ if (key == "date")
+ fmt = `${value.getDate()}.${value.getMonth()}.${value.getFullYear()} ${value.getHours()}:${value.getMinutes()}`;
+ else
+ fmt = value;
+
+ const changeTd = document.createElement("td");
+ changeTd.innerHTML = fmt;
+ changeTd.dataset.key = key;
+ changeTr.appendChild(changeTd);
+ }
+ changesTbl.appendChild(changeTr);
+ }
}
async function initCockpit() {
@@ -213,14 +281,18 @@ async function initCockpit() {
if (userId)
loadNewStudent(userId);
} else {
- loadNewStudent(null, firstname + " " + lastname);
+ // Remove all elements only suitable for teachers
+ for(const elem of document.querySelectorAll("[data-availability=if-lehrer]")) {
+ elem.remove();
+ }
+
+ loadNewStudent(getUserId());
}
- return;
}
window.onload = function() {
isTeacher = getIsTeacher();
DEFAULT_STUDENT_ICON = document.getElementById("student-info-icon").src;
- initCurrentName();
- initCockpit(isTeacher);
+ [firstname, lastname] = getCurrentName();
+ initCockpit();
}