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()
{
//diese komponente generiert über css properties und geschickte rotationen von div element im raum das hintergrundbild
return (
<div style={{
position: "absolute",
+1 -1
View File
@@ -41,7 +41,7 @@ export default function Button(p) {
iconHTML = "";
}
//return the button
//return the button html
return (
<>
<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 {info} from "autoprefixer";
//Dieses Script ist für die Funktionalität der haupt-kalenderansicht
//definiert die höhe einer Zeile
let cellHeight = 20;
let colors = ["#f80000", "#414141"]
//start und ende des semesters (tag)
let semesterStart;
let semesterEnd;
//akuteller tag im jar, mit dem die woche startet
let currentWeekStartDay;
//aktuelles jahr
let currentYear;
//start und end jahr des semesters
let semesterStartYear;
let semesterEndYear;
//akutell ausgewählter Termin (Element)
let selectedElement;
let lastEndTimeDrag;
let lastStartTimeDrag;
let grabbedDown;
//Wochenweiße Variablen:
//Speichert, ob in einem Tag ein Fehler augetreten ist
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]
//gibt an, ob ein Wochentag ausgegraut ist (z.b. feiertag)
let grayedOut = [false, false, false, false, false, false]
//speichert die "verplante" zeit ab. wichtig für abgeben funktion etc.
let timePlanned = 0
export default function CalenderView(p) {
//array, welches wochenweiße alle termine beinhaltet
const [entries, setEntries] = useState([[], [], [], [], [], []])
//update funktion
const [update, setUpdate] = useState(false)
//referenz auf die scroll bar der ansichz
const scrollRef = useRef(null);
//variablen für die kalender seitenansicht
const [startDayCalenderSideBar, setStartDayCalenderSideBar] = useState(0)
const [startYearCalenderSideBar, setStartYearCalenderSideBar] = useState(2000)
const [endDayCalenderSideBar, setEndDayCalenderSideBar] = useState(0)
const [endYearCalenderSideBar, setEndYearCalenderSideBar] = useState(2000)
const [highlightMonth, setHighlightMonth] = useState(0)
const [highlightYear, setHighlightYear] = useState(2000)
//speichert, ob das abgeben popup anzeigt werden soll
const [popUpToggleAbgeben, setPopUpToggleAbgeben] = useState(false)
const router = useRouter();
//funktion, die alle Einträge vom backend liest
function readEntries() {
//url für alle tage für die woche
let url = baseURL + "/entries?semesterid=" + localStorage.getItem("currentsid") +
"&daynumber=" + currentWeekStartDay + "&yearnumber=" + currentYear + "&sessionid=" + localStorage.getItem("sessionid");
//hole die id des aktuellen semester
let currentsid = localStorage.getItem("currentsid")
//hole die id des aktuellen nutzers
let userid = localStorage.getItem("userid")
try {
//frage die daten am backend über die url an
fetch(url).then(r => r.json()).then(en => {
//iterieren über alle 6 wochentage
for (let i = 0; i < en.length; i++) {
//erst einmal ist jeder tag fehlerfrei
isDayOkay[i] = true
let maxLunchBreak = 0
//summe um zu überprüfen, ob 8 stunden am tag schon verplant wurden
let daySum = 0
//iterieren über jeden termin innerhalb eines tages
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) {
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) {
errorState[i] = ErrorType.TooEarly
isDayOkay[i] = false
break
//bedinung, falls der termin zu spät liegt
} else if ((elem.timeend - 1) / 4 > 17) {
errorState[i] = ErrorType.TooLate
isDayOkay[i] = false
break
//bedinung, falls der termin an einem samstag liegt
} else if (new Date(currentYear, 0, elem.daynumber).getUTCDay() === 5) {
errorState[i] = ErrorType.Saturday
isDayOkay[i] = false
} 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) {
errorState[i] = ErrorType.NotEnoughLunchTime
isDayOkay[i] = false
break
//2. abfragen, ob mehrere termine in kombination die mittagspause überdecken
} else if ((elem.timeend - 1) / 4 >= 11 && (elem.timeend - 1) / 4 <= 14) {
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
}
//rechne für jeden termin die "delta zeit" (länge des termins) auf die gesamt zeit
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) {
errorState[i] = ErrorType.TooLong
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 k = 0; k < 20; k++) {
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) {
for (let l = 0; l < 20; l++) {
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) {
for (let l = 0; l < 20; l++) {
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;
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
@@ -159,21 +207,26 @@ export default function CalenderView(p) {
}
j++
}
//hier wird die ausgrauung für feiertage überprüft
for (let i = 0; i < 6; 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]
}
//die termine können nun angezeigt werden. (der state wird geändert)
setEntries(en)
//sollte ein dozent die planugsansicht verwende, muss seine gesamt verplante zeit in der aktuellen vorlesung berechnet werden.
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")
fetch(entriesURL).then(r => r.json()).then(allEn => {
let moduleid = localStorage.getItem("moduleid")
let sum = 0
//die zeitsplannen aller termine werden aufsummiert
let checkTime = 0
for (let j = 0; j < allEn.length; j++) {
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
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) {
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 = {
"id": 0,
"daynumber": currentWeekStartDay + currentColumnID,
@@ -209,10 +265,12 @@ export default function CalenderView(p) {
headers: {"Content-Type": "application/json"},
body: JSON.stringify(json)
}).then(r => {
//einträge werden nach dem hochladen neu synchronisiert und damit auch validiert
readEntries()
})
}
//schickt eine delete anfrage für einen termin an das backend
function deleteEntry(id) {
let url = baseURL + "/entries?id=" + id + "&sessionid=" + localStorage.getItem("sessionid");
fetch(url, {
@@ -220,12 +278,15 @@ export default function CalenderView(p) {
}).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) {
var feiertagejs = require('feiertagejs');
let today = new Date(year, month, day)
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) {
let currentList = entries[column];
for (let i = 0; i < currentList.length; i++) {
@@ -242,6 +303,7 @@ export default function CalenderView(p) {
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) {
let currentList = entries[column];
for (let i = 0; i < currentList.length; i++) {
@@ -255,12 +317,17 @@ export default function CalenderView(p) {
return null;
}
//hier werden termin operationen wie vergrößern oder verkleiner final validiert etc.
function onMouseUp(e) {
//überprüft, ob ein element gewählt ist (maus hält einen termin fest)
if (selectedElement != null) {
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) {
//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 deltaTimeEnd = (selectedElement.timeend - lastEndTimeDrag) / 3
if (timePlanned + deltaTimeEnd > 20) {
@@ -272,6 +339,7 @@ export default function CalenderView(p) {
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 json = {
"id": id,
@@ -289,24 +357,32 @@ export default function CalenderView(p) {
headers: {"Content-Type": "application/json"},
body: JSON.stringify(json)
}).then(r => {
//elemente werden nach einem update neu synchronisiert und damit auch validiert
readEntries()
})
}
//es gibt kein aktuelle mit der maus "gehaltenes" element mehr.
selectedElement = null;
}
}
function onMouseMove(e) {
//überprüft, ob ein element gewählt ist (maus hält einen termin fest)
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_target_offset = e.currentTarget.getBoundingClientRect().top;
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)
//logik sollte ein termin an der unteren kante gezogen werden.
if (grabbedDown) {
if (row - 1 > selectedElement.timestart) {
//überprüft ob an der gezogenen position keine termine bereits sind.
let free = true;
for (let i = 0; i < entries[currentColumnID].length; 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) {
selectedElement.timeend = row + 1;
}
}
//logik sollte ein termin an der oberen kante gezogen werden.
} else if (row + 2 < selectedElement.timeend) {
//logik wie bei unterer kante
let free = true;
for (let i = 0; i < entries[currentColumnID].length; i++) {
if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) {
@@ -347,6 +426,7 @@ export default function CalenderView(p) {
}
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_target_offset = e.currentTarget.getBoundingClientRect().top;
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 currentsid = localStorage.getItem("currentsid")
//sollte ein Links-klick ausgeführt worden sein:
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")) {
//schauen, ob auf keine resize bar gedrückt wurde
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 ((row - 1) / 4 >= 7 && (row + 2) / 4 <= 18) {
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 {
//hole die id des termins (hierbei darf das entry e nicht mitgenommen werden)
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")) {
//anhand der id herausfinden ob nach oben oder unten gezogen werden sollte
//speichere aktuelle daten des termins ab
grabbedDown = currentId.includes("down")
selectedElement = getElementInColumn(parentID, currentColumnID);
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) {
//id holen
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")) {
//aktuellen termin löschen
let id = parseInt(currentId.replace("e", ""))
errorState[currentColumnID] = ErrorType.Okay
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() {
currentWeekStartDay -= 7;
let date = new Date(currentYear, 0, currentWeekStartDay + 5)
@@ -395,9 +490,11 @@ export default function CalenderView(p) {
errorState[i] = ErrorType.Okay
}
//einträge müssen für die neue woche neu geholt werden.
readEntries()
}
//inverse logik zu nach links
function onWeekRight() {
currentWeekStartDay += 7;
let date = new Date(currentYear, 0, currentWeekStartDay + 5)
@@ -411,30 +508,37 @@ export default function CalenderView(p) {
readEntries()
}
//gibt die farbe eines termins anhand der gegebenen parameter zurück
function getEntryColor(userCreatedByID, columnID, semesterid, moduleid) {
let id = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid")
if(localStorage.getItem("admin") == 0)
{
//ist der termin vom nutzer selbst:
if (id == userCreatedByID) {
if (isDayOkay[columnID] && moduleid == localStorage.getItem("moduleid")) {
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")) {
return "#346991";
//gibt es ein problem mit einem einem termin der wohl im aktuellen fach liegt, wird er gelb
} else {
return "#e5a10e";
}
//von anderen nutzern...
} else {
return "#a2a2a2";
}
}
//oder für die ansicht von admins immer grau
else
{
return "#a2a2a2";
}
}
//gleiche logik wie für die termine, nur mit etwas dunkleren farbwerten
function getResizeBarColor(userCreatedByID, columnID, semesterid, moduleid) {
let id = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid")
@@ -458,8 +562,11 @@ export default function CalenderView(p) {
}
}
//beim neu laden der seite:
useEffect(() => {
//kleines delay zum start, um ladefehler zu vermeiden.
setTimeout(() => {
//setze allde daten zum beginn auf ihre default werte.
semesterStart = 0;
semesterEnd = 0;
semesterStartYear = 0;
@@ -474,9 +581,11 @@ export default function CalenderView(p) {
"&id=" + localStorage.getItem("currentsid");
//lese alle informationen über das aktuelle semester aus (start ende etc.)
fetch(url).then(r => r.json()).then(s => {
currentWeekStartDay = s.startday - new Date(s.startyear, 0, s.startday).getUTCDay();
currentYear = s.startyear;
//setze alle informationen für die kalender seitenansicht
setStartYearCalenderSideBar(currentYear)
setEndYearCalenderSideBar(s.endyear)
setHighlightMonth(new Date(s.startyear, 0, s.startday).getMonth())
@@ -484,18 +593,26 @@ export default function CalenderView(p) {
semesterStart = s.startday;
semesterEnd = s.endday;
//setze alle informationen für die kalender seitenansicht
semesterStartYear = s.startyear;
semesterEndYear = s.endyear;
setStartDayCalenderSideBar(semesterStart)
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)
//setze den scroll der kompontente auf ca. die mitte der ansicht
scrollRef.current.scrollTop = 600;
//blockiere das kontextmenü, damit es bei rechtsklickoperationen nicht stört
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) => {
try {
//hierbei wird die cell height (ganz oben im script) angepasst und auf ein minimum limitiert.
//ein maximum gibt es nicht.
if (e.key === "+") {
cellHeight += 2
} 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 () {
if (selectedElement == null) {
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) {
internal -= 1
internal /= 4
@@ -534,7 +652,9 @@ export default function CalenderView(p) {
temp.push(i);
}
//funktionalität in diesem komponente, sollte in der seitenansicht auf einen monat geklickt werden.
function onMonthClick(monthIndex, startParts) {
//berechne den neuen starttag in der woche, und lade alle benötigten daten neu.
monthIndex--
let startDay = 1
let date = new Date(parseInt(startParts[2]), monthIndex, startDay);
@@ -557,9 +677,12 @@ export default function CalenderView(p) {
errorState[i] = ErrorType.Okay
}
//hole die daten für die neue woche vom backend erneut
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 (
<div style={{
@@ -586,6 +709,7 @@ export default function CalenderView(p) {
}}>{p.semesterName}</p>
<div className={"calender-direction-wrapper"}>
<div>
{/*füge hier die kalender seitenansicht ein links von der planungsansicht*/}
<BasicDateCalendar startyear={startYearCalenderSideBar} startday={startDayCalenderSideBar}
endyear={endYearCalenderSideBar} endday={endDayCalenderSideBar}
highlightYear={highlightYear} highlightMonth={highlightMonth}
@@ -598,6 +722,7 @@ export default function CalenderView(p) {
justifyContent: "center",
alignItems: "center",
}} id={update}>
{/*füge hier den wochenwechsler ein. Oberhalb der planungsansicht*/}
<WeekSelector year={currentYear} startday={currentWeekStartDay} onFunctionLeft={() => onWeekLeft()}
onFunctionRight={() => onWeekRight()}/>
<div style={{
@@ -608,6 +733,7 @@ export default function CalenderView(p) {
backgroundColor: "white",
gap: 5,
}}>
{/*hier wird die leiste für die namen der wochentage generiert*/}
<div style={{borderRadius: 10, padding: 10, backgroundColor: "#f1f1f1"}}
className={"box-shadow"}>
<div>
@@ -637,37 +763,43 @@ export default function CalenderView(p) {
<div className={"calender-view content"} style={{height: cellHeight * 96 + 10}}>
{/*hier die spalte für den montag*/}
<div className={"spalte"}
id={"0"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
backgroundColor: grayedOut[0] ? "#aaaaaa" : "#ffffff"
}}
// weise mausfunktionalitäten der spalte zu
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(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={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid)
}} id={d.id + "e"}>
{/*hier die obere bar, an der termin gezogen werden kann*/}
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid)
}}></div>
{/*hier der mittelteil des termins (zeitinfos usw.)*/}
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
<br/>
<p>{(Math.floor((d.timeend - d.timestart) / 12)) > 0 ? (Math.floor((d.timeend - d.timestart) / 12) * 15) + "min Pause einplanen" : ""}</p>
</div>
{/*hier die untere bar, an der termin gezogen werden kann*/}
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid, d.moduleid)
}}></div>
</div>))}
</div>
{/*gleich wie montag, aber für dienstag*/}
<div className={"spalte"}
id={"1"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -700,6 +832,7 @@ export default function CalenderView(p) {
</div>
{/*gleich wie montag aber für mittwoch*/}
<div className={"spalte"}
id={"2"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -732,7 +865,7 @@ export default function CalenderView(p) {
</div>))}
</div>
{/*gleich wie montag*/}
<div className={"spalte"}
id={"3"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -764,7 +897,7 @@ export default function CalenderView(p) {
</div>))}
</div>
{/*gleich wie montag*/}
<div className={"spalte"}
id={"4"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -796,7 +929,7 @@ export default function CalenderView(p) {
</div>))}
</div>
{/*gleich wie montag*/}
<div className={"spalte"}
id={"5"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -830,8 +963,8 @@ export default function CalenderView(p) {
</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)"}}>
{/*maps a list of internal time stamps to lines and time stamps*/}
{temp.map(i => (<div style={{
width: "100%",
height: cellHeight * 2,
@@ -840,9 +973,12 @@ export default function CalenderView(p) {
justifyContent: "space-around",
alignItems: "center",
}} className={"no-pointer-events"}>
{/*das div element ist für die linie*/}
<div style={{
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",
marginTop: cellHeight - 3,
marginRight: 120,
@@ -901,7 +1037,9 @@ export default function CalenderView(p) {
</div>
</div>
</div>
{/*die seitliche anzeige, welche die fehler anzeigt*/}
<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) => (
<div style={{
display: e === ErrorType.Okay ? "none" : "flex",
@@ -932,6 +1070,7 @@ export default function CalenderView(p) {
</div>
</div>
{/*hier ein element, welches die oben berechneten verplanten vorlesungsstunden des dozenten anzeigt*/}
<div className={"box-shadow round-border"} style={{
marginTop: 30,
padding: 5
@@ -949,6 +1088,8 @@ export default function CalenderView(p) {
right: 70,
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={() => {
Math.floor(timePlanned) == 20 ? setPopUpToggleAbgeben(true) : {}
}} 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 = {
Okay: "Okay",
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">
<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>`
+26
View File
@@ -5,6 +5,7 @@ import Background from "@/components/Background";
import {baseURL} from "@/components/Constants";
import Back from "@/components/Back";
//dummy daten für die vorlesungsfächer
let modulesDummy = [
["Grundlagen u. Logik", "Programmieren 1", "Programmieren 2", "Digitaltechnik", "Web. Eng.", "Analysis"],
["Lineare Algebra", "Anwendungsprojekt", "BWL", "Projektmanagement", "Algo. Kompl.", "Python", "Prolog"],
@@ -14,6 +15,8 @@ let modulesDummy = [
["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
export default function InputForm(p) {
@@ -31,6 +34,7 @@ export default function InputForm(p) {
hasSemesterNumberChanged = false
//lädt zu beginn alle dummy daten des ersten semesters
let arr = []
modulesDummy[0].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
@@ -38,12 +42,16 @@ export default function InputForm(p) {
setModuleUserMapping(arr)
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 => {
setUsers(u)
}).then(() => {
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)
{
//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 => {
setCourseName(semester.name)
let startYear = semester.startyear
@@ -63,6 +71,7 @@ export default function InputForm(p) {
})
}).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 => {
console.log(modules)
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) {
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) {
//bereite alle relevanten daten des input form auf
let semesterid = localStorage.getItem("currentsid")
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 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)
{
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))
}
//wenn das semester nur editiert wurde, stelle eine put anfrage an das backend.
else
{
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
@@ -139,6 +154,7 @@ export default function InputForm(p) {
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) {
fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid"), {
method: "DELETE"
@@ -164,9 +180,12 @@ export default function InputForm(p) {
})
} else {
//hier werden modulzuweisungen zu dozenten am backend aktualisiert
for (let i = 0; i < moduleUserMapping.length; i++) {
let current = moduleUserMapping[i]
//solte die zuweisung des modules zum dozenten noch aktiv sein...
if (current.userid != -1) {
//im fall, dass das die zuweisung nocht nie existiert hat, stelle eine post anfrage
if (current.moduleid == -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "POST",
@@ -180,6 +199,7 @@ export default function InputForm(p) {
})
})
} 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"), {
method: "PUT",
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 {
if (current.moduleid != -1) {
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()
}
return (
<>
{/*das hintergrundbild*/}
<Background/>
<div className={"box-shadow input-form round-border"}>
{/*grundlegende input forms für namen... semesternummer usw.*/}
<p>Kursname</p>
<input type={"text"} className={"box-shadow round-border"}
style={{padding: 8, width: "100%", backgroundColor: (courseName == "") ? "#E44747" : "white"}}
@@ -253,6 +277,7 @@ export default function InputForm(p) {
<option value={5}>6. Semester</option>
</select>
{/*hier die tabelle, die alle zuweisungen von dozenten und modulen / vorlesungen anzeigt*/}
<div className={"table-wrapper"}>
<table>
<tbody>
@@ -308,6 +333,7 @@ export default function InputForm(p) {
width: "100%",
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={"Speichern"} color={"#77932b"} onClick={() => {
(startDate == "" || endDate == "" || startDate >= endDate || courseName == "") ? () => {
+11
View File
@@ -9,13 +9,18 @@ export default function Login() {
let url = baseURL + "/users"
//sollte auf den login knopf geklickt worden sein...
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;
let response = await fetch(url, {
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 value = String.fromCharCode.apply(null, ((await reader.read()).value))
if (value != "failed") {
@@ -26,7 +31,12 @@ export default function Login() {
let admin = 0
await fetch(url).then(o => o.json()).then(user => {
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)
//leite den nutzer je nach seinem status auf die admin oder dozenten ansicht weiter.
if(admin === 1) {
await router.push("/semesteroverview")
}else await router.push("/semesteroverviewLecturer")
@@ -40,6 +50,7 @@ export default function Login() {
const [inputUserName, setInputUserName] = 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 [hint2, setHint2] = useState("Passwort")
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)
{
+2
View File
@@ -1,5 +1,7 @@
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 [isHovered, setIsHovered] = React.useState(false);
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) {
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(() => {
let isEdge = window.navigator.userAgent.indexOf("Edg") > -1
let isChrome = window.navigator.userAgent.indexOf("Chrome") > -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))
{
router.push("/browserNotSupported")