Weitere Kommentare im Frontend

This commit is contained in:
brausjonas
2023-07-09 00:22:52 +02:00
parent 65a399693e
commit 86f9e559b5
10 changed files with 198 additions and 9 deletions
+1
View File
@@ -2,6 +2,7 @@ import React from "react";
export default function Background() export default function Background()
{ {
//diese komponente generiert über css properties und geschickte rotationen von div element im raum das hintergrundbild
return ( return (
<div style={{ <div style={{
position: "absolute", position: "absolute",
+1 -1
View File
@@ -41,7 +41,7 @@ export default function Button(p) {
iconHTML = ""; iconHTML = "";
} }
//return the button //return the button html
return ( return (
<> <>
<button className={"round-border button font font-small"} <button className={"round-border button font font-small"}
+149 -8
View File
@@ -11,78 +11,115 @@ import PopUp from "@/components/PopUp";
import {useRouter} from "next/router"; import {useRouter} from "next/router";
import {info} from "autoprefixer"; import {info} from "autoprefixer";
//Dieses Script ist für die Funktionalität der haupt-kalenderansicht
//definiert die höhe einer Zeile
let cellHeight = 20; let cellHeight = 20;
let colors = ["#f80000", "#414141"] let colors = ["#f80000", "#414141"]
//start und ende des semesters (tag)
let semesterStart; let semesterStart;
let semesterEnd; let semesterEnd;
//akuteller tag im jar, mit dem die woche startet
let currentWeekStartDay; let currentWeekStartDay;
//aktuelles jahr
let currentYear; let currentYear;
//start und end jahr des semesters
let semesterStartYear; let semesterStartYear;
let semesterEndYear; let semesterEndYear;
//akutell ausgewählter Termin (Element)
let selectedElement; let selectedElement;
let lastEndTimeDrag; let lastEndTimeDrag;
let lastStartTimeDrag; let lastStartTimeDrag;
let grabbedDown; let grabbedDown;
//Wochenweiße Variablen:
//Speichert, ob in einem Tag ein Fehler augetreten ist
let isDayOkay = [true, true, true, true, true, true] let isDayOkay = [true, true, true, true, true, true]
//Speichert für jeden Wochentag den Fehlerstatus ab
let errorState = [ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay] let errorState = [ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay]
//gibt an, ob ein Wochentag ausgegraut ist (z.b. feiertag)
let grayedOut = [false, false, false, false, false, false] let grayedOut = [false, false, false, false, false, false]
//speichert die "verplante" zeit ab. wichtig für abgeben funktion etc.
let timePlanned = 0 let timePlanned = 0
export default function CalenderView(p) { export default function CalenderView(p) {
//array, welches wochenweiße alle termine beinhaltet
const [entries, setEntries] = useState([[], [], [], [], [], []]) const [entries, setEntries] = useState([[], [], [], [], [], []])
//update funktion
const [update, setUpdate] = useState(false) const [update, setUpdate] = useState(false)
//referenz auf die scroll bar der ansichz
const scrollRef = useRef(null); const scrollRef = useRef(null);
//variablen für die kalender seitenansicht
const [startDayCalenderSideBar, setStartDayCalenderSideBar] = useState(0) const [startDayCalenderSideBar, setStartDayCalenderSideBar] = useState(0)
const [startYearCalenderSideBar, setStartYearCalenderSideBar] = useState(2000) const [startYearCalenderSideBar, setStartYearCalenderSideBar] = useState(2000)
const [endDayCalenderSideBar, setEndDayCalenderSideBar] = useState(0) const [endDayCalenderSideBar, setEndDayCalenderSideBar] = useState(0)
const [endYearCalenderSideBar, setEndYearCalenderSideBar] = useState(2000) const [endYearCalenderSideBar, setEndYearCalenderSideBar] = useState(2000)
const [highlightMonth, setHighlightMonth] = useState(0) const [highlightMonth, setHighlightMonth] = useState(0)
const [highlightYear, setHighlightYear] = useState(2000) const [highlightYear, setHighlightYear] = useState(2000)
//speichert, ob das abgeben popup anzeigt werden soll
const [popUpToggleAbgeben, setPopUpToggleAbgeben] = useState(false) const [popUpToggleAbgeben, setPopUpToggleAbgeben] = useState(false)
const router = useRouter(); const router = useRouter();
//funktion, die alle Einträge vom backend liest
function readEntries() { function readEntries() {
//url für alle tage für die woche
let url = baseURL + "/entries?semesterid=" + localStorage.getItem("currentsid") + let url = baseURL + "/entries?semesterid=" + localStorage.getItem("currentsid") +
"&daynumber=" + currentWeekStartDay + "&yearnumber=" + currentYear + "&sessionid=" + localStorage.getItem("sessionid"); "&daynumber=" + currentWeekStartDay + "&yearnumber=" + currentYear + "&sessionid=" + localStorage.getItem("sessionid");
//hole die id des aktuellen semester
let currentsid = localStorage.getItem("currentsid") let currentsid = localStorage.getItem("currentsid")
//hole die id des aktuellen nutzers
let userid = localStorage.getItem("userid") let userid = localStorage.getItem("userid")
try { try {
//frage die daten am backend über die url an
fetch(url).then(r => r.json()).then(en => { fetch(url).then(r => r.json()).then(en => {
//iterieren über alle 6 wochentage
for (let i = 0; i < en.length; i++) { for (let i = 0; i < en.length; i++) {
//erst einmal ist jeder tag fehlerfrei
isDayOkay[i] = true isDayOkay[i] = true
let maxLunchBreak = 0 let maxLunchBreak = 0
//summe um zu überprüfen, ob 8 stunden am tag schon verplant wurden
let daySum = 0 let daySum = 0
//iterieren über jeden termin innerhalb eines tages
for (let j = 0; j < en[i].length; j++) { for (let j = 0; j < en[i].length; j++) {
//überpüfen, ob der termin wirklich im aktuellen planungssemester liegt
if (en[i][j] != null && currentsid == (en[i][j]).semesterid) { if (en[i][j] != null && currentsid == (en[i][j]).semesterid) {
let elem = en[i][j] let elem = en[i][j]
//hier werden fehler abgefragt, je weiter oben der fehler liegt, um so wichtiger ist er
//bedienung falls der termin zu früh liegt
if ((elem.timestart - 1) / 4 < 8) { if ((elem.timestart - 1) / 4 < 8) {
errorState[i] = ErrorType.TooEarly errorState[i] = ErrorType.TooEarly
isDayOkay[i] = false isDayOkay[i] = false
break break
//bedinung, falls der termin zu spät liegt
} else if ((elem.timeend - 1) / 4 > 17) { } else if ((elem.timeend - 1) / 4 > 17) {
errorState[i] = ErrorType.TooLate errorState[i] = ErrorType.TooLate
isDayOkay[i] = false isDayOkay[i] = false
break break
//bedinung, falls der termin an einem samstag liegt
} else if (new Date(currentYear, 0, elem.daynumber).getUTCDay() === 5) { } else if (new Date(currentYear, 0, elem.daynumber).getUTCDay() === 5) {
errorState[i] = ErrorType.Saturday errorState[i] = ErrorType.Saturday
isDayOkay[i] = false isDayOkay[i] = false
} else { } else {
//bedinung falls die mittagspause nicht eingehalten wurde
//1. ein einziger termin überdeckt die ganze mittagszeit
if ((elem.timestart - 1) / 4 <= 11 && (elem.timeend - 1) / 4 >= 14) { if ((elem.timestart - 1) / 4 <= 11 && (elem.timeend - 1) / 4 >= 14) {
errorState[i] = ErrorType.NotEnoughLunchTime errorState[i] = ErrorType.NotEnoughLunchTime
isDayOkay[i] = false isDayOkay[i] = false
break break
//2. abfragen, ob mehrere termine in kombination die mittagspause überdecken
} else if ((elem.timeend - 1) / 4 >= 11 && (elem.timeend - 1) / 4 <= 14) { } else if ((elem.timeend - 1) / 4 >= 11 && (elem.timeend - 1) / 4 <= 14) {
let min = 24 * 3 let min = 24 * 3
@@ -101,24 +138,31 @@ export default function CalenderView(p) {
} }
} }
//sollte kein fehler gefunden worden sein ist der tag okay.
errorState[i] = ErrorType.Okay errorState[i] = ErrorType.Okay
} }
//rechne für jeden termin die "delta zeit" (länge des termins) auf die gesamt zeit
daySum += elem.timeend - elem.timestart daySum += elem.timeend - elem.timestart
} }
} }
//sollte die gesamt zeit über 8 sein, sind zu viele vorlesungen bzw. zu lang an diesem tag verplant
if (daySum / 4 > 8) { if (daySum / 4 > 8) {
errorState[i] = ErrorType.TooLong errorState[i] = ErrorType.TooLong
isDayOkay[i] = false isDayOkay[i] = false
} }
} }
//hier ist eine logik für blaue termine, die sich mit grauen überscheiden (von der planung her kein problem)
//da blau in der aktuellen planung nicht berücksichtig wird, trotzdem sollte dieser fall aus visuellen gründen abgedeckt sein
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
for (let k = 0; k < 20; k++) { for (let k = 0; k < 20; k++) {
if (en[i][k] != null) { if (en[i][k] != null) {
//hier für einen blauen termin wird ein grauer gesucht, der diesen schneidet
//in diesem wird der blaue termin verkürzt dargestellt
if (en[i][k].semesterid != currentsid) { if (en[i][k].semesterid != currentsid) {
for (let l = 0; l < 20; l++) { for (let l = 0; l < 20; l++) {
if (en[i][l] != null && en[i][l].usercreatedbyid != userid) { if (en[i][l] != null && en[i][l].usercreatedbyid != userid) {
@@ -135,6 +179,8 @@ export default function CalenderView(p) {
} }
} }
} }
//hier für einen grauen termin der von einem blauen geschnitten wird
//hier wird der graue termin verkürzt dargestellt
if (en[i][k] != null && en[i][k].usercreatedbyid != userid) { if (en[i][k] != null && en[i][k].usercreatedbyid != userid) {
for (let l = 0; l < 20; l++) { for (let l = 0; l < 20; l++) {
if (en[i][l] != null && en[i][l].semesterid != currentsid) { if (en[i][l] != null && en[i][l].semesterid != currentsid) {
@@ -150,6 +196,8 @@ export default function CalenderView(p) {
} }
//hier wird überprüft, ob sich ein tag innerhalb der semestergrenzen befindet
//wenn nicht, muss er ausgegraut werden, damit dort nichts geplant werden kann.
let j = 0; let j = 0;
for (let i = Math.round(((new Date(currentYear, 0, currentWeekStartDay) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))); i <= Math.round(((new Date(currentYear, 0, currentWeekStartDay + 5) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))); i++) { for (let i = Math.round(((new Date(currentYear, 0, currentWeekStartDay) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))); i <= Math.round(((new Date(currentYear, 0, currentWeekStartDay + 5) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))); i++) {
grayedOut[j] = i % Math.round(((new Date(currentYear, 11, 31) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))) < semesterStart && semesterEnd && new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() == semesterStartYear || i % Math.round(((new Date(currentYear, 11, 31) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))) > semesterEnd && new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() == semesterEndYear grayedOut[j] = i % Math.round(((new Date(currentYear, 11, 31) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))) < semesterStart && semesterEnd && new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() == semesterStartYear || i % Math.round(((new Date(currentYear, 11, 31) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))) > semesterEnd && new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() == semesterEndYear
@@ -159,21 +207,26 @@ export default function CalenderView(p) {
} }
j++ j++
} }
//hier wird die ausgrauung für feiertage überprüft
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
let date = new Date(currentYear, 0, currentWeekStartDay + i) let date = new Date(currentYear, 0, currentWeekStartDay + i)
grayedOut[i] = holiday(currentYear, date.getMonth(), date.getDate()) ? holiday(currentYear, date.getMonth(), date.getDate()) : grayedOut[i] grayedOut[i] = holiday(currentYear, date.getMonth(), date.getDate()) ? holiday(currentYear, date.getMonth(), date.getDate()) : grayedOut[i]
} }
//die termine können nun angezeigt werden. (der state wird geändert)
setEntries(en) setEntries(en)
//sollte ein dozent die planugsansicht verwende, muss seine gesamt verplante zeit in der aktuellen vorlesung berechnet werden.
if(localStorage.getItem("admin") == 0) if(localStorage.getItem("admin") == 0)
{ {
//es werden alle relevanten termine vom backend angefordert
let entriesURL = baseURL + "/entries/all/module?sessionid=" + localStorage.getItem("sessionid") + "&moduleid=" + localStorage.getItem("moduleid") let entriesURL = baseURL + "/entries/all/module?sessionid=" + localStorage.getItem("sessionid") + "&moduleid=" + localStorage.getItem("moduleid")
fetch(entriesURL).then(r => r.json()).then(allEn => { fetch(entriesURL).then(r => r.json()).then(allEn => {
let moduleid = localStorage.getItem("moduleid") let moduleid = localStorage.getItem("moduleid")
let sum = 0 let sum = 0
//die zeitsplannen aller termine werden aufsummiert
let checkTime = 0 let checkTime = 0
for (let j = 0; j < allEn.length; j++) { for (let j = 0; j < allEn.length; j++) {
if (allEn[j] != null && allEn[j].moduleid == moduleid) { if (allEn[j] != null && allEn[j].moduleid == moduleid) {
@@ -181,6 +234,7 @@ export default function CalenderView(p) {
} }
} }
//um auf einen stundensatz von 45 min pro stunde zu kommen muss die resultierende zeit (in 15 min takten) durch 3 geteilt werden.
sum /= 3 sum /= 3
timePlanned = sum timePlanned = sum
}) })
@@ -191,8 +245,10 @@ export default function CalenderView(p) {
} }
} }
//hierbei wird ein neu angelegter termin (immer 45 minuten zu beginn) and das backend gesendet
function pushEntry(currentColumnID, row) { function pushEntry(currentColumnID, row) {
let url = baseURL + "/entries" + "?sessionid=" + localStorage.getItem("sessionid") let url = baseURL + "/entries" + "?sessionid=" + localStorage.getItem("sessionid")
//json objekt, das alle relavanten informationen über den termin enthält, resultiert aus der datenbank.
let json = { let json = {
"id": 0, "id": 0,
"daynumber": currentWeekStartDay + currentColumnID, "daynumber": currentWeekStartDay + currentColumnID,
@@ -209,10 +265,12 @@ export default function CalenderView(p) {
headers: {"Content-Type": "application/json"}, headers: {"Content-Type": "application/json"},
body: JSON.stringify(json) body: JSON.stringify(json)
}).then(r => { }).then(r => {
//einträge werden nach dem hochladen neu synchronisiert und damit auch validiert
readEntries() readEntries()
}) })
} }
//schickt eine delete anfrage für einen termin an das backend
function deleteEntry(id) { function deleteEntry(id) {
let url = baseURL + "/entries?id=" + id + "&sessionid=" + localStorage.getItem("sessionid"); let url = baseURL + "/entries?id=" + id + "&sessionid=" + localStorage.getItem("sessionid");
fetch(url, { fetch(url, {
@@ -220,12 +278,15 @@ export default function CalenderView(p) {
}).then(r => readEntries()) }).then(r => readEntries())
} }
//gibt für ein datum zurück, ob es sich um einen feiertag handelt. Wichtig für die ausgrau funktion.
//verwendung von feiertagejs (keine garantie auf korrektheit, externe library)
function holiday(year, month, day) { function holiday(year, month, day) {
var feiertagejs = require('feiertagejs'); var feiertagejs = require('feiertagejs');
let today = new Date(year, month, day) let today = new Date(year, month, day)
return feiertagejs.isHoliday(today, 'BW') return feiertagejs.isHoliday(today, 'BW')
} }
//funktion, welche überprüft, ob an einem tag (column) zu einer gewissen zeit (row) ein termin bereits vorhanden ist
function checkForElementAtRow(row, column) { function checkForElementAtRow(row, column) {
let currentList = entries[column]; let currentList = entries[column];
for (let i = 0; i < currentList.length; i++) { for (let i = 0; i < currentList.length; i++) {
@@ -242,6 +303,7 @@ export default function CalenderView(p) {
return false; return false;
} }
//kann ein element an einem tag anhand seiner id zurückgeben. Wichtig wenn das gleiche Termin objekt verwendet werden muss.
function getElementInColumn(id, column) { function getElementInColumn(id, column) {
let currentList = entries[column]; let currentList = entries[column];
for (let i = 0; i < currentList.length; i++) { for (let i = 0; i < currentList.length; i++) {
@@ -255,12 +317,17 @@ export default function CalenderView(p) {
return null; return null;
} }
//hier werden termin operationen wie vergrößern oder verkleiner final validiert etc.
function onMouseUp(e) { function onMouseUp(e) {
//überprüft, ob ein element gewählt ist (maus hält einen termin fest)
if (selectedElement != null) { if (selectedElement != null) {
let id = selectedElement.id; let id = selectedElement.id;
//überprüft, ob der termin sich über oder unter den erlaubten grenzen von 7 uhr morgens oder 18 uhr abends befindet.
if ((selectedElement.timestart - 1) / 4 >= 7 && (selectedElement.timeend - 1) / 4 <= 18) { if ((selectedElement.timestart - 1) / 4 >= 7 && (selectedElement.timeend - 1) / 4 <= 18) {
//rechnet bei einem überschreiten der gesamtzeit die überschrittene zeit aus, und lässt den termin zurück auf die letze
//valide länge springen
let finalTimeEnd = selectedElement.timeend let finalTimeEnd = selectedElement.timeend
let deltaTimeEnd = (selectedElement.timeend - lastEndTimeDrag) / 3 let deltaTimeEnd = (selectedElement.timeend - lastEndTimeDrag) / 3
if (timePlanned + deltaTimeEnd > 20) { if (timePlanned + deltaTimeEnd > 20) {
@@ -272,6 +339,7 @@ export default function CalenderView(p) {
finalTimeStart += (timePlanned + deltaTimeStart - 20) * 3 finalTimeStart += (timePlanned + deltaTimeStart - 20) * 3
} }
//hier wird ein termin (vergrößert oder verkleinert) hinsichtlich seiner zeit am backend geupdated.
let url = baseURL + "/entries?sessionid=" + localStorage.getItem("sessionid"); let url = baseURL + "/entries?sessionid=" + localStorage.getItem("sessionid");
let json = { let json = {
"id": id, "id": id,
@@ -289,24 +357,32 @@ export default function CalenderView(p) {
headers: {"Content-Type": "application/json"}, headers: {"Content-Type": "application/json"},
body: JSON.stringify(json) body: JSON.stringify(json)
}).then(r => { }).then(r => {
//elemente werden nach einem update neu synchronisiert und damit auch validiert
readEntries() readEntries()
}) })
} }
//es gibt kein aktuelle mit der maus "gehaltenes" element mehr.
selectedElement = null; selectedElement = null;
} }
} }
function onMouseMove(e) { function onMouseMove(e) {
//überprüft, ob ein element gewählt ist (maus hält einen termin fest)
if (selectedElement != null) { if (selectedElement != null) {
//berechne die zeile (zeit) über welcher sich die maus befindet = die zeile in der planungsansicht in welcher sich die maus befindet
let y_window = e.clientY; let y_window = e.clientY;
let y_target_offset = e.currentTarget.getBoundingClientRect().top; let y_target_offset = e.currentTarget.getBoundingClientRect().top;
let row = Math.floor((y_window - y_target_offset) / cellHeight) + 1; let row = Math.floor((y_window - y_target_offset) / cellHeight) + 1;
//bekomme die nummber des aktuellen tages. 0 = montag, 1 = dienstag usw.
let currentColumnID = parseInt(e.currentTarget.id) let currentColumnID = parseInt(e.currentTarget.id)
//logik sollte ein termin an der unteren kante gezogen werden.
if (grabbedDown) { if (grabbedDown) {
if (row - 1 > selectedElement.timestart) { if (row - 1 > selectedElement.timestart) {
//überprüft ob an der gezogenen position keine termine bereits sind.
let free = true; let free = true;
for (let i = 0; i < entries[currentColumnID].length; i++) { for (let i = 0; i < entries[currentColumnID].length; i++) {
if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) { if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) {
@@ -320,11 +396,14 @@ export default function CalenderView(p) {
} }
} }
//sollte keine termine vorhanden sein, kann der termin verlängert bzw. verkürzt werden.
if (free) { if (free) {
selectedElement.timeend = row + 1; selectedElement.timeend = row + 1;
} }
} }
//logik sollte ein termin an der oberen kante gezogen werden.
} else if (row + 2 < selectedElement.timeend) { } else if (row + 2 < selectedElement.timeend) {
//logik wie bei unterer kante
let free = true; let free = true;
for (let i = 0; i < entries[currentColumnID].length; i++) { for (let i = 0; i < entries[currentColumnID].length; i++) {
if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) { if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) {
@@ -347,6 +426,7 @@ export default function CalenderView(p) {
} }
function onMouseDown(e) { function onMouseDown(e) {
//berechnet alle wichtigen informationen, wie die nummer des geklickten tages in der woche und die angeklickte zeit.
let y_window = e.clientY; let y_window = e.clientY;
let y_target_offset = e.currentTarget.getBoundingClientRect().top; let y_target_offset = e.currentTarget.getBoundingClientRect().top;
let row = Math.floor((y_window - y_target_offset) / cellHeight) + 1; let row = Math.floor((y_window - y_target_offset) / cellHeight) + 1;
@@ -355,9 +435,14 @@ export default function CalenderView(p) {
let currentUserID = localStorage.getItem("userid"); let currentUserID = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid") let currentsid = localStorage.getItem("currentsid")
//sollte ein Links-klick ausgeführt worden sein:
if (e.button === 0) { if (e.button === 0) {
//überprüfen ob auf einen freien platz gedrückt wurde (e in der id steht für entry)
if (!currentId.includes("e")) { if (!currentId.includes("e")) {
//schauen, ob auf keine resize bar gedrückt wurde
if (!currentId.includes("grab")) { if (!currentId.includes("grab")) {
//sollte im geklickten bereich genug zeit frei sein 3 * 15 min dann lege einen neuen termin an
if (!checkForElementAtRow(row + 2, currentColumnID) && !checkForElementAtRow(row + 1, currentColumnID)) { if (!checkForElementAtRow(row + 2, currentColumnID) && !checkForElementAtRow(row + 1, currentColumnID)) {
if ((row - 1) / 4 >= 7 && (row + 2) / 4 <= 18) { if ((row - 1) / 4 >= 7 && (row + 2) / 4 <= 18) {
if (!grayedOut[currentColumnID] && timePlanned + 0.8 < 20) { if (!grayedOut[currentColumnID] && timePlanned + 0.8 < 20) {
@@ -365,9 +450,14 @@ export default function CalenderView(p) {
} }
} }
} }
//wurde auf eine resize leiste gedrückt (nach oben oder unten):
} else { } else {
//hole die id des termins (hierbei darf das entry e nicht mitgenommen werden)
let parentID = parseInt(e.target.parentElement.id.replace("e", "")); let parentID = parseInt(e.target.parentElement.id.replace("e", ""));
//überpüfen, ob der termin tatsächlich dem aktuellem dozenten gehört.
if (currentUserID == getElementInColumn(parentID, currentColumnID).usercreatedbyid && getElementInColumn(parentID, currentColumnID).moduleid == localStorage.getItem("moduleid")) { if (currentUserID == getElementInColumn(parentID, currentColumnID).usercreatedbyid && getElementInColumn(parentID, currentColumnID).moduleid == localStorage.getItem("moduleid")) {
//anhand der id herausfinden ob nach oben oder unten gezogen werden sollte
//speichere aktuelle daten des termins ab
grabbedDown = currentId.includes("down") grabbedDown = currentId.includes("down")
selectedElement = getElementInColumn(parentID, currentColumnID); selectedElement = getElementInColumn(parentID, currentColumnID);
lastEndTimeDrag = selectedElement.timeend lastEndTimeDrag = selectedElement.timeend
@@ -375,9 +465,13 @@ export default function CalenderView(p) {
} }
} }
} }
//sollte ein Rechts-klick ausgeführt worden sein:
} else if (e.button === 2) { } else if (e.button === 2) {
//id holen
let parentID = parseInt(e.target.id.replace("e", "")); let parentID = parseInt(e.target.id.replace("e", ""));
//überpüfen, ob der termin tatsächlich dem aktuellen dozenten gehört
if (currentUserID == getElementInColumn(parentID, currentColumnID).usercreatedbyid && currentId.includes("e") && getElementInColumn(parentID, currentColumnID).moduleid == localStorage.getItem("moduleid")) { if (currentUserID == getElementInColumn(parentID, currentColumnID).usercreatedbyid && currentId.includes("e") && getElementInColumn(parentID, currentColumnID).moduleid == localStorage.getItem("moduleid")) {
//aktuellen termin löschen
let id = parseInt(currentId.replace("e", "")) let id = parseInt(currentId.replace("e", ""))
errorState[currentColumnID] = ErrorType.Okay errorState[currentColumnID] = ErrorType.Okay
deleteEntry(id) deleteEntry(id)
@@ -385,6 +479,7 @@ export default function CalenderView(p) {
} }
} }
//wenn die woche nach links gewechselt wurden, müssen tages und wochendaten angepasst werden.
function onWeekLeft() { function onWeekLeft() {
currentWeekStartDay -= 7; currentWeekStartDay -= 7;
let date = new Date(currentYear, 0, currentWeekStartDay + 5) let date = new Date(currentYear, 0, currentWeekStartDay + 5)
@@ -395,9 +490,11 @@ export default function CalenderView(p) {
errorState[i] = ErrorType.Okay errorState[i] = ErrorType.Okay
} }
//einträge müssen für die neue woche neu geholt werden.
readEntries() readEntries()
} }
//inverse logik zu nach links
function onWeekRight() { function onWeekRight() {
currentWeekStartDay += 7; currentWeekStartDay += 7;
let date = new Date(currentYear, 0, currentWeekStartDay + 5) let date = new Date(currentYear, 0, currentWeekStartDay + 5)
@@ -411,30 +508,37 @@ export default function CalenderView(p) {
readEntries() readEntries()
} }
//gibt die farbe eines termins anhand der gegebenen parameter zurück
function getEntryColor(userCreatedByID, columnID, semesterid, moduleid) { function getEntryColor(userCreatedByID, columnID, semesterid, moduleid) {
let id = localStorage.getItem("userid"); let id = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid") let currentsid = localStorage.getItem("currentsid")
if(localStorage.getItem("admin") == 0) if(localStorage.getItem("admin") == 0)
{ {
//ist der termin vom nutzer selbst:
if (id == userCreatedByID) { if (id == userCreatedByID) {
if (isDayOkay[columnID] && moduleid == localStorage.getItem("moduleid")) { if (isDayOkay[columnID] && moduleid == localStorage.getItem("moduleid")) {
return "#77932b"; return "#77932b";
//ist der termin vom nutzer selbst aber liegt in einem anderen fach / modul, dann wird er blau
} else if (moduleid != localStorage.getItem("moduleid")) { } else if (moduleid != localStorage.getItem("moduleid")) {
return "#346991"; return "#346991";
//gibt es ein problem mit einem einem termin der wohl im aktuellen fach liegt, wird er gelb
} else { } else {
return "#e5a10e"; return "#e5a10e";
} }
//von anderen nutzern...
} else { } else {
return "#a2a2a2"; return "#a2a2a2";
} }
} }
//oder für die ansicht von admins immer grau
else else
{ {
return "#a2a2a2"; return "#a2a2a2";
} }
} }
//gleiche logik wie für die termine, nur mit etwas dunkleren farbwerten
function getResizeBarColor(userCreatedByID, columnID, semesterid, moduleid) { function getResizeBarColor(userCreatedByID, columnID, semesterid, moduleid) {
let id = localStorage.getItem("userid"); let id = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid") let currentsid = localStorage.getItem("currentsid")
@@ -458,8 +562,11 @@ export default function CalenderView(p) {
} }
} }
//beim neu laden der seite:
useEffect(() => { useEffect(() => {
//kleines delay zum start, um ladefehler zu vermeiden.
setTimeout(() => { setTimeout(() => {
//setze allde daten zum beginn auf ihre default werte.
semesterStart = 0; semesterStart = 0;
semesterEnd = 0; semesterEnd = 0;
semesterStartYear = 0; semesterStartYear = 0;
@@ -474,9 +581,11 @@ export default function CalenderView(p) {
"&id=" + localStorage.getItem("currentsid"); "&id=" + localStorage.getItem("currentsid");
//lese alle informationen über das aktuelle semester aus (start ende etc.)
fetch(url).then(r => r.json()).then(s => { fetch(url).then(r => r.json()).then(s => {
currentWeekStartDay = s.startday - new Date(s.startyear, 0, s.startday).getUTCDay(); currentWeekStartDay = s.startday - new Date(s.startyear, 0, s.startday).getUTCDay();
currentYear = s.startyear; currentYear = s.startyear;
//setze alle informationen für die kalender seitenansicht
setStartYearCalenderSideBar(currentYear) setStartYearCalenderSideBar(currentYear)
setEndYearCalenderSideBar(s.endyear) setEndYearCalenderSideBar(s.endyear)
setHighlightMonth(new Date(s.startyear, 0, s.startday).getMonth()) setHighlightMonth(new Date(s.startyear, 0, s.startday).getMonth())
@@ -484,18 +593,26 @@ export default function CalenderView(p) {
semesterStart = s.startday; semesterStart = s.startday;
semesterEnd = s.endday; semesterEnd = s.endday;
//setze alle informationen für die kalender seitenansicht
semesterStartYear = s.startyear; semesterStartYear = s.startyear;
semesterEndYear = s.endyear; semesterEndYear = s.endyear;
setStartDayCalenderSideBar(semesterStart) setStartDayCalenderSideBar(semesterStart)
setEndDayCalenderSideBar(s.endday) setEndDayCalenderSideBar(s.endday)
//sollte alle semesterinformationen da und verteilt sein, lese zum ersten mal die termine für die aktuelle woche (semester start woche)
//vom backend
}).then(readEntries) }).then(readEntries)
//setze den scroll der kompontente auf ca. die mitte der ansicht
scrollRef.current.scrollTop = 600; scrollRef.current.scrollTop = 600;
//blockiere das kontextmenü, damit es bei rechtsklickoperationen nicht stört
window.addEventListener("contextmenu", (e) => (e.preventDefault())) window.addEventListener("contextmenu", (e) => (e.preventDefault()))
//verwende einen keylistener für die resize funktionen der komponente mit der plus und minus taste
window.addEventListener("keypress", (e) => { window.addEventListener("keypress", (e) => {
try { try {
//hierbei wird die cell height (ganz oben im script) angepasst und auf ein minimum limitiert.
//ein maximum gibt es nicht.
if (e.key === "+") { if (e.key === "+") {
cellHeight += 2 cellHeight += 2
} else if (e.key === "-") { } else if (e.key === "-") {
@@ -509,6 +626,7 @@ export default function CalenderView(p) {
}) })
//führe diese funktion parellel zum rest aus, damit alle 500ms die daten neu vom backend geladen werden (live sync)
setInterval(function () { setInterval(function () {
if (selectedElement == null) { if (selectedElement == null) {
readEntries() readEntries()
@@ -518,7 +636,7 @@ export default function CalenderView(p) {
}, []) }, [])
//returns internal format (0 - 96) to a string //rechnet das interne zeitformat 0-96 in lesbaren zeiten um
function internal_to_time(internal) { function internal_to_time(internal) {
internal -= 1 internal -= 1
internal /= 4 internal /= 4
@@ -534,7 +652,9 @@ export default function CalenderView(p) {
temp.push(i); temp.push(i);
} }
//funktionalität in diesem komponente, sollte in der seitenansicht auf einen monat geklickt werden.
function onMonthClick(monthIndex, startParts) { function onMonthClick(monthIndex, startParts) {
//berechne den neuen starttag in der woche, und lade alle benötigten daten neu.
monthIndex-- monthIndex--
let startDay = 1 let startDay = 1
let date = new Date(parseInt(startParts[2]), monthIndex, startDay); let date = new Date(parseInt(startParts[2]), monthIndex, startDay);
@@ -557,9 +677,12 @@ export default function CalenderView(p) {
errorState[i] = ErrorType.Okay errorState[i] = ErrorType.Okay
} }
//hole die daten für die neue woche vom backend erneut
readEntries() readEntries()
} }
//sichtbarer html teil der komponente, im allgemeinen über flex layouts und div elemente realisiert. in jeder einzelnen tages-spalte
//befindet sich allerdings ein grid layout mit der breite 1. In diesem werden die Termine angesiedelt
return ( return (
<div style={{ <div style={{
@@ -586,6 +709,7 @@ export default function CalenderView(p) {
}}>{p.semesterName}</p> }}>{p.semesterName}</p>
<div className={"calender-direction-wrapper"}> <div className={"calender-direction-wrapper"}>
<div> <div>
{/*füge hier die kalender seitenansicht ein links von der planungsansicht*/}
<BasicDateCalendar startyear={startYearCalenderSideBar} startday={startDayCalenderSideBar} <BasicDateCalendar startyear={startYearCalenderSideBar} startday={startDayCalenderSideBar}
endyear={endYearCalenderSideBar} endday={endDayCalenderSideBar} endyear={endYearCalenderSideBar} endday={endDayCalenderSideBar}
highlightYear={highlightYear} highlightMonth={highlightMonth} highlightYear={highlightYear} highlightMonth={highlightMonth}
@@ -598,6 +722,7 @@ export default function CalenderView(p) {
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
}} id={update}> }} id={update}>
{/*füge hier den wochenwechsler ein. Oberhalb der planungsansicht*/}
<WeekSelector year={currentYear} startday={currentWeekStartDay} onFunctionLeft={() => onWeekLeft()} <WeekSelector year={currentYear} startday={currentWeekStartDay} onFunctionLeft={() => onWeekLeft()}
onFunctionRight={() => onWeekRight()}/> onFunctionRight={() => onWeekRight()}/>
<div style={{ <div style={{
@@ -608,6 +733,7 @@ export default function CalenderView(p) {
backgroundColor: "white", backgroundColor: "white",
gap: 5, gap: 5,
}}> }}>
{/*hier wird die leiste für die namen der wochentage generiert*/}
<div style={{borderRadius: 10, padding: 10, backgroundColor: "#f1f1f1"}} <div style={{borderRadius: 10, padding: 10, backgroundColor: "#f1f1f1"}}
className={"box-shadow"}> className={"box-shadow"}>
<div> <div>
@@ -637,37 +763,43 @@ export default function CalenderView(p) {
<div className={"calender-view content"} style={{height: cellHeight * 96 + 10}}> <div className={"calender-view content"} style={{height: cellHeight * 96 + 10}}>
{/*hier die spalte für den montag*/}
<div className={"spalte"} <div className={"spalte"}
id={"0"} style={{ id={"0"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`, gridTemplateRows: `repeat(96, ${cellHeight}px)`,
backgroundColor: grayedOut[0] ? "#aaaaaa" : "#ffffff" backgroundColor: grayedOut[0] ? "#aaaaaa" : "#ffffff"
}} }}
// weise mausfunktionalitäten der spalte zu
onMouseDown={e => onMouseDown(e)} onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)} onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}> onMouseUp={e => onMouseUp(e)}>
{/*füge die einträge dieses tages in das grid layout ein*/}
{entries[0].map(d => (d != null && <div className={"entry"} style={{ {entries[0].map(d => (d != null && <div className={"entry"} style={{
width: "100%", width: "100%",
gridRowStart: d.timestart, gridRowStart: d.timestart,
gridRowEnd: d.timeend, gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid) backgroundColor: getEntryColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid)
}} id={d.id + "e"}> }} id={d.id + "e"}>
{/*hier die obere bar, an der termin gezogen werden kann*/}
<div className={"resize-grab"} id={"grabup"} style={{ <div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid) backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid)
}}></div> }}></div>
{/*hier der mittelteil des termins (zeitinfos usw.)*/}
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}> <div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p> <p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p> <p>{d.info}</p>
<br/> <br/>
<p>{(Math.floor((d.timeend - d.timestart) / 12)) > 0 ? (Math.floor((d.timeend - d.timestart) / 12) * 15) + "min Pause einplanen" : ""}</p> <p>{(Math.floor((d.timeend - d.timestart) / 12)) > 0 ? (Math.floor((d.timeend - d.timestart) / 12) * 15) + "min Pause einplanen" : ""}</p>
</div> </div>
{/*hier die untere bar, an der termin gezogen werden kann*/}
<div className={"resize-grab"} id={"grabdown"} style={{ <div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid) backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid)
}}></div> }}></div>
</div>))} </div>))}
</div> </div>
{/*gleich wie montag, aber für dienstag*/}
<div className={"spalte"} <div className={"spalte"}
id={"1"} style={{ id={"1"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`, gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -700,6 +832,7 @@ export default function CalenderView(p) {
</div> </div>
{/*gleich wie montag aber für mittwoch*/}
<div className={"spalte"} <div className={"spalte"}
id={"2"} style={{ id={"2"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`, gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -732,7 +865,7 @@ export default function CalenderView(p) {
</div>))} </div>))}
</div> </div>
{/*gleich wie montag*/}
<div className={"spalte"} <div className={"spalte"}
id={"3"} style={{ id={"3"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`, gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -764,7 +897,7 @@ export default function CalenderView(p) {
</div>))} </div>))}
</div> </div>
{/*gleich wie montag*/}
<div className={"spalte"} <div className={"spalte"}
id={"4"} style={{ id={"4"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`, gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -796,7 +929,7 @@ export default function CalenderView(p) {
</div>))} </div>))}
</div> </div>
{/*gleich wie montag*/}
<div className={"spalte"} <div className={"spalte"}
id={"5"} style={{ id={"5"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`, gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -830,8 +963,8 @@ export default function CalenderView(p) {
</div> </div>
{/*hier ein zweites element, das über den eigentlichen terminen usw. liegt und dafür verantwortlich ist zeitstempel und trennlinen anzuzeigen*/}
<div className={"overlay"} style={{backgroundColor: "rgba(0, 0, 0, 0)"}}> <div className={"overlay"} style={{backgroundColor: "rgba(0, 0, 0, 0)"}}>
{/*maps a list of internal time stamps to lines and time stamps*/}
{temp.map(i => (<div style={{ {temp.map(i => (<div style={{
width: "100%", width: "100%",
height: cellHeight * 2, height: cellHeight * 2,
@@ -840,9 +973,12 @@ export default function CalenderView(p) {
justifyContent: "space-around", justifyContent: "space-around",
alignItems: "center", alignItems: "center",
}} className={"no-pointer-events"}> }} className={"no-pointer-events"}>
{/*das div element ist für die linie*/}
<div style={{ <div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"), borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{ }}>
{/*das p element ist für den zeitstempel*/}
<p style={{
color: "gray", color: "gray",
marginTop: cellHeight - 3, marginTop: cellHeight - 3,
marginRight: 120, marginRight: 120,
@@ -901,7 +1037,9 @@ export default function CalenderView(p) {
</div> </div>
</div> </div>
</div> </div>
{/*die seitliche anzeige, welche die fehler anzeigt*/}
<div className={"error-bar"}> <div className={"error-bar"}>
{/*iteriert über das array der fehlercodes und zeigt nur "fehler" bzw. warnungen an, die nicht gleich okay sind*/}
{errorState.map((e, index) => ( {errorState.map((e, index) => (
<div style={{ <div style={{
display: e === ErrorType.Okay ? "none" : "flex", display: e === ErrorType.Okay ? "none" : "flex",
@@ -932,6 +1070,7 @@ export default function CalenderView(p) {
</div> </div>
</div> </div>
{/*hier ein element, welches die oben berechneten verplanten vorlesungsstunden des dozenten anzeigt*/}
<div className={"box-shadow round-border"} style={{ <div className={"box-shadow round-border"} style={{
marginTop: 30, marginTop: 30,
padding: 5 padding: 5
@@ -949,6 +1088,8 @@ export default function CalenderView(p) {
right: 70, right: 70,
bottom: 20, bottom: 20,
}}> }}>
{/*hier der button für das abgeben. dieser überprüft, ob schon 20 vorlesungsstunden verplant wurden*/}
{/*diese 20 vorlesungsstunden könnten durch eine anbindung an andere systeme ersetzt werden (temporärer wert)*/}
<Button color={timePlanned < 20 ? "#AAAAAA": "#77932b"} onClick={() => { <Button color={timePlanned < 20 ? "#AAAAAA": "#77932b"} onClick={() => {
Math.floor(timePlanned) == 20 ? setPopUpToggleAbgeben(true) : {} Math.floor(timePlanned) == 20 ? setPopUpToggleAbgeben(true) : {}
}} text={"Abgeben"} width={100} height={40}/> }} text={"Abgeben"} width={100} height={40}/>
+1
View File
@@ -1,3 +1,4 @@
//hier werden fehlertypen mit ihrem anzeigetext für die CalenderView hinterlegt
export const ErrorType = { export const ErrorType = {
Okay: "Okay", Okay: "Okay",
TooLong: "Zu lang, maximal 8h pro Tag!", TooLong: "Zu lang, maximal 8h pro Tag!",
+3
View File
@@ -1,3 +1,6 @@
//hier sind wichtige svg images zur späteren verwendung auf buttons usw. hinterlegt. In diese können später evtl. per stringmanipulation weitere infos
//wie breite und höhe eingearbeitet werden.
export const arrowLeft = `<svg xmlns="http://www.w3.org/2000/svg" fill="white" class="bi bi-arrow-left" viewBox="0 0 16 16"> export const arrowLeft = `<svg xmlns="http://www.w3.org/2000/svg" fill="white" class="bi bi-arrow-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/> <path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
</svg>` </svg>`
+26
View File
@@ -5,6 +5,7 @@ import Background from "@/components/Background";
import {baseURL} from "@/components/Constants"; import {baseURL} from "@/components/Constants";
import Back from "@/components/Back"; import Back from "@/components/Back";
//dummy daten für die vorlesungsfächer
let modulesDummy = [ let modulesDummy = [
["Grundlagen u. Logik", "Programmieren 1", "Programmieren 2", "Digitaltechnik", "Web. Eng.", "Analysis"], ["Grundlagen u. Logik", "Programmieren 1", "Programmieren 2", "Digitaltechnik", "Web. Eng.", "Analysis"],
["Lineare Algebra", "Anwendungsprojekt", "BWL", "Projektmanagement", "Algo. Kompl.", "Python", "Prolog"], ["Lineare Algebra", "Anwendungsprojekt", "BWL", "Projektmanagement", "Algo. Kompl.", "Python", "Prolog"],
@@ -14,6 +15,8 @@ let modulesDummy = [
["Bachelor"] ["Bachelor"]
] ]
//speichert ab, ob die nummer des semesters in der bearbeitung geändert wurde.
//wichtig umd daten (aus alten semester nummern) korrekt löschen zu können
let hasSemesterNumberChanged = false let hasSemesterNumberChanged = false
export default function InputForm(p) { export default function InputForm(p) {
@@ -31,6 +34,7 @@ export default function InputForm(p) {
hasSemesterNumberChanged = false hasSemesterNumberChanged = false
//lädt zu beginn alle dummy daten des ersten semesters
let arr = [] let arr = []
modulesDummy[0].map(e => { modulesDummy[0].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0}) arr.push({"moduleid": -1, "userid": -1, "activated": 0})
@@ -38,12 +42,16 @@ export default function InputForm(p) {
setModuleUserMapping(arr) setModuleUserMapping(arr)
let url = baseURL + "/users/all?sessionid=" + localStorage.getItem("sessionid") let url = baseURL + "/users/all?sessionid=" + localStorage.getItem("sessionid")
//holt alle dozenten, die für das dozieren in fragen kommen.
fetch(url).then(r => r.json()).then(u => { fetch(url).then(r => r.json()).then(u => {
setUsers(u) setUsers(u)
}).then(() => { }).then(() => {
let tempSemesterNumber = 0 let tempSemesterNumber = 0
//hier kann ausgemacht werden, ob ein semester neu erstellt werden soll oder bearbeitet, wenn 0 dann wird neu erstellt
//also hier wird bearbeitet
if(localStorage.getItem("currentsid") != 0) if(localStorage.getItem("currentsid") != 0)
{ {
//holen alle daten, die bis jetzt in diesem semester vorhanden sind (noch keine zuweisungen von dozenten zu vorlesungen)
fetch(baseURL + "/semester/id?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid")).then(r => r.json()).then(semester => { fetch(baseURL + "/semester/id?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid")).then(r => r.json()).then(semester => {
setCourseName(semester.name) setCourseName(semester.name)
let startYear = semester.startyear let startYear = semester.startyear
@@ -63,6 +71,7 @@ export default function InputForm(p) {
}) })
}).then(() => { }).then(() => {
//hole alle zuweisungen von dozenten zu vorlesungen / fächern innerhalb dieses semesters.
fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&semesterid=" + localStorage.getItem("currentsid")).then(r => r.json()).then(modules => { fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&semesterid=" + localStorage.getItem("currentsid")).then(r => r.json()).then(modules => {
console.log(modules) console.log(modules)
for(let i = 0; i < modules.length; i++) for(let i = 0; i < modules.length; i++)
@@ -86,12 +95,16 @@ export default function InputForm(p) {
}) })
}, []) }, [])
//sollte auf abbrechen geklickt worden sein...
function onButtonAbort(e) { function onButtonAbort(e) {
router.back() router.back()
} }
//sollte auf speichern geklickt worden sein... hier werden nur daten des semesters übermittelt, noch nicht die
//zweisungen von dozenten und vorlesungen / modulen
function onButtonSave(e) { function onButtonSave(e) {
//bereite alle relevanten daten des input form auf
let semesterid = localStorage.getItem("currentsid") let semesterid = localStorage.getItem("currentsid")
let startYear = parseInt(startDate.split("-")[0]) let startYear = parseInt(startDate.split("-")[0])
@@ -103,6 +116,7 @@ export default function InputForm(p) {
let startDayInYear = Math.round((start - new Date(startYear, 0, 0)) / (1000 * 60 * 60 * 24)) let startDayInYear = Math.round((start - new Date(startYear, 0, 0)) / (1000 * 60 * 60 * 24))
let endDayInYear = Math.round((end - new Date(endYear, 0, 0)) / (1000 * 60 * 60 * 24)) let endDayInYear = Math.round((end - new Date(endYear, 0, 0)) / (1000 * 60 * 60 * 24))
//wenn das semester neu erstellt werden soll, sende eine post anfrage and das backend.
if(semesterid == 0) if(semesterid == 0)
{ {
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), { fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
@@ -119,6 +133,7 @@ export default function InputForm(p) {
}) })
}).then(r => r.json()).then(semester => {semesterid = semester.id}).then(() => modulesInBackend(semesterid)) }).then(r => r.json()).then(semester => {semesterid = semester.id}).then(() => modulesInBackend(semesterid))
} }
//wenn das semester nur editiert wurde, stelle eine put anfrage an das backend.
else else
{ {
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), { fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
@@ -139,6 +154,7 @@ export default function InputForm(p) {
function modulesInBackend(semesterid) function modulesInBackend(semesterid)
{ {
//sollte sich die nummer des semesters geändert haben, lösche alle alten zuweisungen von dozenten und modulen aus dem backend.
if (hasSemesterNumberChanged) { if (hasSemesterNumberChanged) {
fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid"), { fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid"), {
method: "DELETE" method: "DELETE"
@@ -164,9 +180,12 @@ export default function InputForm(p) {
}) })
} else { } else {
//hier werden modulzuweisungen zu dozenten am backend aktualisiert
for (let i = 0; i < moduleUserMapping.length; i++) { for (let i = 0; i < moduleUserMapping.length; i++) {
let current = moduleUserMapping[i] let current = moduleUserMapping[i]
//solte die zuweisung des modules zum dozenten noch aktiv sein...
if (current.userid != -1) { if (current.userid != -1) {
//im fall, dass das die zuweisung nocht nie existiert hat, stelle eine post anfrage
if (current.moduleid == -1) { if (current.moduleid == -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), { fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "POST", method: "POST",
@@ -180,6 +199,7 @@ export default function InputForm(p) {
}) })
}) })
} else { } else {
//im fall, dass die zuweisung schon existiert hat aber nur geändert wurde, stelle eine PUT anfrage
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), { fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "PUT", method: "PUT",
headers: {"Content-Type": "application/json"}, headers: {"Content-Type": "application/json"},
@@ -192,6 +212,7 @@ export default function InputForm(p) {
}) })
}) })
} }
//.. ist diese zuweisung nicht mehr aktiv, lösche die zuweisung aus dem backend.
} else { } else {
if (current.moduleid != -1) { if (current.moduleid != -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid") + "&id=" + current.moduleid, { fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid") + "&id=" + current.moduleid, {
@@ -202,14 +223,17 @@ export default function InputForm(p) {
} }
} }
//gehe nach dem speichern zurück auf das dashboard
router.back() router.back()
} }
return ( return (
<> <>
{/*das hintergrundbild*/}
<Background/> <Background/>
<div className={"box-shadow input-form round-border"}> <div className={"box-shadow input-form round-border"}>
{/*grundlegende input forms für namen... semesternummer usw.*/}
<p>Kursname</p> <p>Kursname</p>
<input type={"text"} className={"box-shadow round-border"} <input type={"text"} className={"box-shadow round-border"}
style={{padding: 8, width: "100%", backgroundColor: (courseName == "") ? "#E44747" : "white"}} style={{padding: 8, width: "100%", backgroundColor: (courseName == "") ? "#E44747" : "white"}}
@@ -253,6 +277,7 @@ export default function InputForm(p) {
<option value={5}>6. Semester</option> <option value={5}>6. Semester</option>
</select> </select>
{/*hier die tabelle, die alle zuweisungen von dozenten und modulen / vorlesungen anzeigt*/}
<div className={"table-wrapper"}> <div className={"table-wrapper"}>
<table> <table>
<tbody> <tbody>
@@ -308,6 +333,7 @@ export default function InputForm(p) {
width: "100%", width: "100%",
gap: 10 gap: 10
}}> }}>
{/*hier die knöpfe abbrechen und speichern mit einer kleinen validierung, ob die grundlegen semesterdaten angegeben wurden*/}
<Button text={"Abbrechen"} onClick={onButtonAbort}/> <Button text={"Abbrechen"} onClick={onButtonAbort}/>
<Button text={"Speichern"} color={"#77932b"} onClick={() => { <Button text={"Speichern"} color={"#77932b"} onClick={() => {
(startDate == "" || endDate == "" || startDate >= endDate || courseName == "") ? () => { (startDate == "" || endDate == "" || startDate >= endDate || courseName == "") ? () => {
+11
View File
@@ -9,13 +9,18 @@ export default function Login() {
let url = baseURL + "/users" let url = baseURL + "/users"
//sollte auf den login knopf geklickt worden sein...
async function on_login_click() { async function on_login_click() {
//füge der url die mail und das passwort an, sicherheitsfeatures werden die hier vorläufig nicht berücktsichtigt
url += "?mail=" + inputUserName + "&password=" + inputPassword; url += "?mail=" + inputUserName + "&password=" + inputPassword;
let response = await fetch(url, { let response = await fetch(url, {
method: "GET", method: "GET",
}); });
//lese die antwort vom backend, und versuche die sessionid (für weitere anfragen am backend wird diese übergeben) auszulesen.
//ist der status nicht "failed" wurden die einloggdaten gefunden und im fall, dass kein fehler aufgetreten ist
//eine sessionid zurückgegeben.
let reader = response.body.getReader(); let reader = response.body.getReader();
let value = String.fromCharCode.apply(null, ((await reader.read()).value)) let value = String.fromCharCode.apply(null, ((await reader.read()).value))
if (value != "failed") { if (value != "failed") {
@@ -26,7 +31,12 @@ export default function Login() {
let admin = 0 let admin = 0
await fetch(url).then(o => o.json()).then(user => { await fetch(url).then(o => o.json()).then(user => {
admin = user.permissions}) admin = user.permissions})
//setze für die spätere verwendung im localstorage, ob es sich bei dem aktuellen nutzer um einen admin handelt.
//selbst wenn diese informationen vom nutzer im browser manuell editiert werden, blockt das backend
//über sämtliche anfrage mit einer sessionid die dozenten bezogen ist ab. => diese information ist nur für die anzeige.
//diese könnte allerdings nicht ordnungsgemäß funktionieren sollte ein nutzer versuchen das tool "auszutricksen"
localStorage.setItem("admin", admin) localStorage.setItem("admin", admin)
//leite den nutzer je nach seinem status auf die admin oder dozenten ansicht weiter.
if(admin === 1) { if(admin === 1) {
await router.push("/semesteroverview") await router.push("/semesteroverview")
}else await router.push("/semesteroverviewLecturer") }else await router.push("/semesteroverviewLecturer")
@@ -40,6 +50,7 @@ export default function Login() {
const [inputUserName, setInputUserName] = useState("") const [inputUserName, setInputUserName] = useState("")
const [inputPassword, setInputPassword] = useState("") const [inputPassword, setInputPassword] = useState("")
//hier states für die hinweise in den loginfeldern für späteres anzeigen von evtl. fehlgeschlagen login versuchen.
const [hint, setHint] = useState("Benutzername") const [hint, setHint] = useState("Benutzername")
const [hint2, setHint2] = useState("Passwort") const [hint2, setHint2] = useState("Passwort")
const [backgroundColor, setBackgroundColor] = useState("rgb(255, 255, 255)") const [backgroundColor, setBackgroundColor] = useState("rgb(255, 255, 255)")
+1
View File
@@ -1,3 +1,4 @@
//hier ein test für die umrechnung zwischen internen und externen datumsformaten. Kann zur nachvollziehbarkeit der rechnung evtl. nützlich sein.
export default function Test(p) export default function Test(p)
{ {
+2
View File
@@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
//hier eine verworfene version der SemesterTile, welche einen hübschen hover effekt ansetzt. Könnte evtl.
//wieder eingepflegt werden.
const Tile = () => { const Tile = () => {
const [isHovered, setIsHovered] = React.useState(false); const [isHovered, setIsHovered] = React.useState(false);
const [cursorPosition, setCursorPosition] = React.useState({ x: 0, y: 0 }); const [cursorPosition, setCursorPosition] = React.useState({ x: 0, y: 0 });
+3
View File
@@ -11,11 +11,14 @@ const inter = Inter({subsets: ['latin']})
export default function Home(p) { export default function Home(p) {
const router = useRouter() const router = useRouter()
//hier wird im login fenster überpüft ob der aktuelle browser mit dem tool kompatibel ist.
//evtl. sind auch browser, die nicht chrome basiert sind kompatibel, diese konnten aber nicht ausführlich genug getest werden.
useEffect(() => { useEffect(() => {
let isEdge = window.navigator.userAgent.indexOf("Edg") > -1 let isEdge = window.navigator.userAgent.indexOf("Edg") > -1
let isChrome = window.navigator.userAgent.indexOf("Chrome") > -1 let isChrome = window.navigator.userAgent.indexOf("Chrome") > -1
let isFireFox = window.navigator.userAgent.indexOf("firefox") > -1 let isFireFox = window.navigator.userAgent.indexOf("firefox") > -1
//ist der browser nicht unterstützt so wird der nutzer auf die browser nicht unterstützt seite weitergeleitet.
if(!(isEdge || isChrome || isFireFox)) if(!(isEdge || isChrome || isFireFox))
{ {
router.push("/browserNotSupported") router.push("/browserNotSupported")