Author SHA1 Message Date
brausjonas cb2ddc7bcf Hinweis zu Online Backend URL 2023-07-09 00:49:57 +02:00
brausjonas 68e2d553f9 Weitere backend kommentare 2023-07-09 00:42:44 +02:00
brausjonas 86f9e559b5 Weitere Kommentare im Frontend 2023-07-09 00:22:52 +02:00
AliGitGut 65a399693e Comments
Alle, von mir zu bearbeitenden, komplizierten und relevanten Codeteile wurden ausführlich beschrieben
2023-07-08 14:54:50 +02:00
AlexE030 3382d732a9 Improved Calender Side Bar jump Feature
Wenn man jetzt in der Kalender-Sidebar auf einen Monat klickt, dann springt er nicht mehr immer zum Ersten des Monats.
2023-06-30 00:58:11 +02:00
brausjonas 7b6a82c073 Update README.md 2023-06-28 09:31:07 +02:00
brausjonas d80abcaf8c Create LICENSE 2023-06-28 09:29:11 +02:00
brausjonas 17a3ad0b33 Fixed Logout Bug 2023-06-22 00:16:30 +02:00
brausjonas be9ace5238 Fixed User Loading Bug
Manchmal wurden User im Input Form nicht richtig geladen. Dieser Bug ist hiermit behoben
2023-06-22 00:01:48 +02:00
Amira24523 fcdf8492a6 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-06-21 23:34:58 +02:00
Amira24523 d4d01c730a Login Module in deutsch 2023-06-21 23:33:33 +02:00
brausjonas a4c600301e Bessere Erkennbarkeit von nicht Zuordnung von Dozenten zu Modulen 2023-06-21 23:22:25 +02:00
Amira24523 4ec1cb0749 Fixed SideBar 2023-06-21 23:10:02 +02:00
AliGitGut 20e2351ba9 Bugfix Pausen
Pausen werden nicht mehr angerecht aber dem Dozenten mitgeteilt
2023-06-21 22:49:47 +02:00
Amira24523 4f45d48061 InputForm Semester Width change 2023-06-21 22:36:33 +02:00
Amira24523 ee5805434d StatusBar Color update 2023-06-21 22:32:57 +02:00
AliGitGut 024d22711f Firefox
Firefox ist jetzt freigeschalten, wird aber nicht empfohlen
2023-06-21 21:04:27 +02:00
AliGitGut 9315f5b18d Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-06-21 20:38:39 +02:00
AliGitGut 34c2786840 Pausen Updates
Pausenskalierung angepasst, Pausen werden nun in den Modulen angezeigt
2023-06-21 20:38:36 +02:00
brausjonas ca23f7f993 More Dummy Data For Modules 2023-06-21 20:21:22 +02:00
AliGitGut d81922d188 Pausenvalidierung
Alle 4h muss ein Dozent eine Pause von 15 min einlegen // alle 8h eine von 30 min
2023-06-21 20:00:17 +02:00
brausjonas c979c3a801 Multiselect Fixed by Changing Columns 2023-06-21 17:04:26 +02:00
Amira24523 0a3a390bb8 Warning message 2023-06-21 15:55:40 +02:00
AliGitGut 09f288532e names changed 2023-06-20 18:21:50 +02:00
AliGitGut 137684f5be Help Page Angepasst
Help Page nochmal angepasst
2023-06-20 10:53:27 +02:00
AliGitGut a0841f4b2b Help Page Aktualisiert
Die Hilfe Seite wurde auf den neusten Stand gebracht, auf der Login Page entfernt und hat einen Back button bekommen
2023-06-19 15:29:56 +02:00
brausjonas 571e6e72c0 Grayed Out Bug Fixed 2023-06-19 15:02:09 +02:00
brausjonas ac4b62f32c Design Dateien Wiederhergestellt 2023-06-18 14:27:18 +02:00
brausjonas 8dc16c5b2c Bug Fix 2023-06-18 14:10:29 +02:00
75 changed files with 102140 additions and 439 deletions
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JpaBuddyIdeaProjectConfig">
<option name="renamerInitialized" value="true" />
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="16" project-jdk-type="JavaSDK" />
<component name="ProjectType">
<option name="id" value="jpab" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/TIF22A_AnwProjekt_B.iml" filepath="$PROJECT_DIR$/.idea/TIF22A_AnwProjekt_B.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+170
View File
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="744e9299-0ce3-415c-8733-c935bf920887" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/components/CalendarSideBar.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/components/CalendarSideBar.jsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/components/DateElement.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/components/DateElement.jsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/components/WeekSelector.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/components/WeekSelector.jsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/pages/semesteroverview.js" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/pages/semesteroverview.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/pages/semesteroverviewLecturer.js" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/pages/semesteroverviewLecturer.js" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="CSS File" />
<option value="JavaScript File" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2PV5k9t8lC9xvqgtEIMZ2TApWUu" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;C:/Users/afist/WebstormProjects/SideBarCalendarTest&quot;,
&quot;list.type.of.created.stylesheet&quot;: &quot;CSS&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;ts.external.directory.path&quot;: &quot;C:\\Users\\afist\\AppData\\Local\\JetBrains\\Toolbox\\apps\\WebStorm\\ch-0\\231.8770.64\\plugins\\javascript-impl\\jsLanguageServicesImpl\\external&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\TIF22A_AnwProjekt_B\anwendung\src\images" />
</key>
</component>
<component name="RunManager" selected="npm.dev">
<configuration name="index.js" type="NodeJSConfigurationType" temporary="true" nameIsGenerated="true" path-to-js-file="index.js" working-dir="$PROJECT_DIR$/anwendung/src/pages">
<method v="2" />
</configuration>
<configuration name="build" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/anwendung/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="node" />
<envs />
<method v="2" />
</configuration>
<configuration name="dev" type="js.build_tools.npm" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/anwendung/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<node-interpreter value="node" />
<package-manager value="npm" />
<envs />
<method v="2">
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/anwendung/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="node" />
<package-manager value="npm" />
<envs />
</option>
</method>
</configuration>
<list>
<item itemvalue="Node.js.index.js" />
<item itemvalue="npm.build" />
<item itemvalue="npm.dev" />
</list>
<recent_temporary>
<list>
<item itemvalue="Node.js.index.js" />
</list>
</recent_temporary>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="744e9299-0ce3-415c-8733-c935bf920887" name="Changes" comment="" />
<created>1683529551159</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1683529551159</updated>
<workItem from="1683529552463" duration="1756000" />
<workItem from="1683830457997" duration="1285000" />
<workItem from="1684223646646" duration="1195000" />
<workItem from="1684228236564" duration="1017000" />
<workItem from="1684257831013" duration="1011000" />
<workItem from="1684267194850" duration="890000" />
<workItem from="1684672228161" duration="1603000" />
<workItem from="1684788345629" duration="1507000" />
<workItem from="1684856925307" duration="3000" />
<workItem from="1684856964097" duration="5995000" />
<workItem from="1684915449317" duration="9318000" />
<workItem from="1685011281036" duration="2214000" />
<workItem from="1685055429281" duration="634000" />
<workItem from="1685103879210" duration="2066000" />
<workItem from="1685142372079" duration="5289000" />
<workItem from="1685311018550" duration="2063000" />
<workItem from="1685356323722" duration="4005000" />
<workItem from="1685389394962" duration="4465000" />
<workItem from="1685439319096" duration="492000" />
<workItem from="1686165563810" duration="18166000" />
<workItem from="1686259026223" duration="2970000" />
<workItem from="1686313568230" duration="1725000" />
<workItem from="1686331195896" duration="7520000" />
<workItem from="1686345244271" duration="7553000" />
<workItem from="1686572559048" duration="4289000" />
<workItem from="1686655739777" duration="3725000" />
<workItem from="1686659590430" duration="2344000" />
<workItem from="1686690018802" duration="32000" />
<workItem from="1686690072078" duration="307000" />
<workItem from="1686727178400" duration="9281000" />
<workItem from="1686825740350" duration="2964000" />
<workItem from="1686831091729" duration="595000" />
<workItem from="1686906198799" duration="2151000" />
<workItem from="1686910129813" duration="1653000" />
<workItem from="1686923077769" duration="3441000" />
<workItem from="1687173723149" duration="7011000" />
<workItem from="1687240431966" duration="47000" />
<workItem from="1687245202053" duration="3425000" />
<workItem from="1687249039012" duration="3407000" />
<workItem from="1687349584578" duration="477000" />
<workItem from="1687354510081" duration="453000" />
<workItem from="1687354999964" duration="291000" />
<workItem from="1687431213516" duration="596000" />
<workItem from="1688661149524" duration="602000" />
<workItem from="1688661766941" duration="1680000" />
<workItem from="1688812359996" duration="6843000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Ali Fistik, Jonas Braus, Amira Michels, Alexander Ebner, Mike Baier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+64
View File
@@ -0,0 +1,64 @@
# TIF22A_AnwProjekt_B
Team B im Anwendungsprojekt (TIF22A)
Website can be accessed under: http://lectureplanner.de/ (caution no https, only http)
Hinweise für Lokale Installation:
Hinweis: Alles ist auf Windows getestet, sollte aber auch auf Mac und Linux funktionieren
1. es sollte java in einer der neusten Versionen installiert sein. (Empfehlung Java 20)
Downloadlink: https://www.oracle.com/de/java/technologies/downloads/
Eventuell müssen Sie nach der Installation den PC neu Starten.
Im Terminal können Sie mit "java -version" Ihre aktuelle Java version überprüfen.
2. Für das Frontend muss zusätzlich npm auf dem Computer installiert sein. (Weiteres siehe z.B. hier: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
3. Es sollte feiertagejs installiert sein "npm install feiertagejs" (weiters: https://github.com/sfakir/feiertagejs)
Ausführen des Backends (nicht im "backend" ordner):
1. Öffnen Sie ein Terminal, dort wo die datei "backend.jar" liegt. Achten Sie darauf, dass die Dateien "database.mv.db" und "database.trace.db" im gleichen Ordner
wie die ".jar" Datei liegen.
2. Geben sie im Terminal ein: "java -jar backend.jar"
Ausführen des Frontends:
1. Gehen Sie in den Ordner "anwendung"
2. Öffnen Sie hier ein Terminal und führen den Command "npm run build" aus. (Bitte beachten, dass Feiertagejs vorher hier installiert sein sollte)
3. Führen Sie nun im gleichen Terminal den Command "npm run start" aus.
4. Gehen Sie im Browser auf "http://localhost:3000" oder einem davon abeweichenden Link der im Terminal angezeigt wird.
5. Einloggen können Sie sich mit folgenden User-Daten:
Sollte das ausführen lokal nicht funktionieren, können Sie das Projekt immer noch über die website http://www.lectureplanner.de betrachten.
Admins:
Email -------------------- Passwort
braus@gmail.com 123
fistik@gmail.com 123
Dozenten:
Email -------------------- Passwort
gloessner@gmail.com 123
birn@mail.com 123
behrends@gmx.de 123
+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"}
+23 -23
View File
@@ -14,9 +14,9 @@ export default function BasicDateCalendar(p) {
const ref = useRef(null)
function getBackMonthColor(monthIndex)
function getBackMonthColor(monthIndex) //Farbliche Kennzeichnung des Monats in dem man aktuell Plant
{
let date = new Date(parseInt(startParts[2]), parseInt(startParts[1]) + monthIndex - 1, 1)
let date = new Date(parseInt(startParts[2]), parseInt(startParts[1]) + monthIndex - 1, 1) //Datums Objekt des Monats in dem man sich aktuell befindet
if (date.getFullYear() === p.highlightYear && date.getMonth() === p.highlightMonth)
{
if(lastMonth !== p.highlightMonth)
@@ -35,8 +35,8 @@ export default function BasicDateCalendar(p) {
result = []
calculatedDay = []
startDate = new Date(p.startyear, 0 ,p.startday)
let endDate = new Date(p.endyear, 0 , p.endday)
startDate = new Date(p.startyear, 0 ,p.startday) //Startdatum des Theoriesemesters
let endDate = new Date(p.endyear, 0 , p.endday) //Enddatum des Theoriesemesters
let startString = startDate.getDate() + "." + (startDate.getMonth() + 1) + "." + p.startyear
let endString = endDate.getDate() + "." + (endDate.getMonth() + 1) + "." + p.endyear
generateCalendar(startString, endString)
@@ -45,10 +45,10 @@ export default function BasicDateCalendar(p) {
return (
<div className={"Allround"} ref={ref}>
<div className={"Down"}>
{result.map((monthResult, index) => (
{result.map((monthResult, index) => ( //map durch alle Monate aus dem Array monthResult
<div className={"A box-shadow"} onClick={() => p.onMonthClick(
(parseInt(startParts[1]) + index),
startParts
startParts //gibt zurück auf welchen Monat geklickt wurde, wodurch direkt in den jeweiligen Monat gewechselt werden kann
)} >
<p style={{
textAlign : "center",
@@ -63,7 +63,7 @@ export default function BasicDateCalendar(p) {
pointerEvents: "none"
}}>
{weekdays.map((weekday) => (
<p key={weekday} style={{
<p key={weekday} style={{ //generiere einmal alle Wochentage (Montag,...,Sonntag)
pointerEvents: "none"
}}>{weekday}</p>
))}
@@ -82,8 +82,7 @@ export default function BasicDateCalendar(p) {
}
function getMonthName(monthIndex) {
function getMonthName(monthIndex) { //holt die relevanten Monatsnamen aus dem 2D Array
if (startParts[1] - 1 + monthIndex < 12) {
return months[startParts[1] - 1 + monthIndex][0];
} else {
@@ -94,31 +93,31 @@ function getMonthName(monthIndex) {
function generateCalendar(start, ende)
{
splitter(start, ende)
if (startParts[2] < endParts[2])
if (startParts[2] < endParts[2]) //Abfrage für den Fall, dass ein Theoriesemester Jahresübergreifend ist
{
for (let i = startParts[1] - 1; i <= 11; i++)
for (let i = startParts[1] - 1; i <= 11; i++) //Durchlaufe alle Monate bis zum Jahresende
{
let monthResult = [];
for (let j = 1; j <= days[i]; j++)
for (let j = 1; j <= days[i]; j++) //durchlaufe alle Tage des Monats in dem wir uns befinden
{
if (
new Date(startParts[2], i, j) >= new Date(startParts[2], startParts[1] - 1, startParts[0]) &&
new Date(startParts[2], i, j) <= new Date(startParts[2], 11, 31)
)
) //überprüft ob der Tag noch in der angegebenen Zeitspanne des Theoriesemsters liegt
{
monthResult.push(j);
calculateDay(startParts[2], i, j)
}
}
result.push(monthResult);
if (i == 11)
if (i == 11) //erstes Jahr ist fertig abgebildet
{
for (let h = 0; h <= endParts[1] - 1; h++)
for (let h = 0; h <= endParts[1] - 1; h++) //laufe vom Anfang des Jahres bis zum angegebenen Ende des Theoriesemesters
{
let monthResultNewYear = [];
for (let g = 1; g <= days[h]; g++)
for (let g = 1; g <= days[h]; g++) //durchlaufe alle Tage des Monats in dem wir uns befinden
{
if (new Date(endParts[2], h, g) <= new Date(endParts[2], endParts[1] - 1, endParts[0]))
if (new Date(endParts[2], h, g) <= new Date(endParts[2], endParts[1] - 1, endParts[0])) //überprüft ob der Tag noch in der angegebenen Zeitspanne des Theoriesemsters liegt
{
monthResultNewYear.push(g);
calculateDay(endParts[2], h, g)
@@ -128,17 +127,17 @@ function generateCalendar(start, ende)
}
}
}
} else
} else //Normalfall das ein Anfang und Ende eines Theoriesemester im gleichen Jahr liegt
{
for (let i = startParts[1] - 1; i <= endParts[1] - 1; i++)
for (let i = startParts[1] - 1; i <= endParts[1] - 1; i++) //durchlaufe alle Monate in der angegebenen Zeitspanne
{
let monthResult = [];
for (let j = 1; j <= days[i]; j++)
for (let j = 1; j <= days[i]; j++) //durchlaufe alle Tage des Monats in dem wir uns befinden
{
if (
new Date(startParts[2], i, j) >= new Date(startParts[2], startParts[1] - 1, startParts[0]) &&
new Date(startParts[2], i, j) <= new Date(startParts[2], endParts[1] - 1, endParts[0])
)
) //überprüft ob der Tag noch in der angegebenen Zeitspanne des Theoriesemsters liegt
{
monthResult.push(j)
calculateDay(startParts[2], i, j)
@@ -149,7 +148,8 @@ function generateCalendar(start, ende)
}
}
function calculateDay(x, i, j){
function calculateDay(x, i, j)//berechnet den Wochentag eines Datums (Montag,...,Sonntag)
{
if (j == startDate.getDate() && i == startDate.getMonth() || j == 1){
let monthStart = new Date(x, i, j)
if (monthStart.getDay() == 0)
@@ -158,7 +158,7 @@ function calculateDay(x, i, j){
}
}
function freeSpaces(index)
function freeSpaces(index)//generiert Leerzeichen damit Tage genau unter ihrem jeweiligen Wochentag stehen
{
let arrayTest = []
for (let i = 0; i < calculatedDay[index]; i++) {
+187 -17
View File
@@ -9,79 +9,117 @@ import BasicDateCalendar from "@/components/CalendarSideBar";
import feiertagejs from "feiertagejs";
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
@@ -100,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) {
@@ -134,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) {
@@ -149,45 +196,59 @@ 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
if(new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() < semesterStartYear || new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() > semesterEndYear)
{
grayedOut[j] = true
}
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) {
sum += allEn[j].timeend - allEn[j].timestart
}
}
//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
})
}
})
}).catch(() => {})
} catch (e) {
}
}
//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,
@@ -204,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, {
@@ -215,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++) {
@@ -237,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++) {
@@ -250,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) {
@@ -267,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,
@@ -284,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]) {
@@ -315,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]) {
@@ -342,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;
@@ -350,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) {
@@ -360,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
@@ -370,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)
@@ -380,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)
@@ -390,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)
@@ -406,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")
@@ -453,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;
@@ -469,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())
@@ -479,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 === "-") {
@@ -504,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()
@@ -513,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
@@ -529,9 +652,20 @@ 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 date = new Date(parseInt(startParts[2]), monthIndex, 1)
let startDay = 1
let date = new Date(parseInt(startParts[2]), monthIndex, startDay);
if(monthIndex + 1 == startParts[1] && startParts[0] != 1){
startDay = startParts[0];
date = new Date(parseInt(startParts[2]), monthIndex, startDay);
}
if(date.getDay() == 0){
startDay = parseInt(startDay.toString()) + 1
date = new Date(parseInt(startParts[2]), monthIndex, startDay);
}
let start = new Date(date.getFullYear(), 0, 0)
currentWeekStartDay = Math.round((date - start) / (1000 * 60 * 60 * 24))
currentWeekStartDay = currentWeekStartDay - new Date(date.getFullYear(), 0, currentWeekStartDay).getUTCDay()
@@ -543,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={{
@@ -565,14 +702,14 @@ export default function CalenderView(p) {
}).then(() => router.push("/semesteroverviewLecturer"))
}}
/>
<p style={{
fontSize: 40,
marginBottom: 60
}}>{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}
@@ -585,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={{
@@ -595,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>
@@ -624,35 +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)`,
@@ -675,6 +822,8 @@ export default function CalenderView(p) {
<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>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 1, d.semesterid, d.moduleid)
@@ -683,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)`,
@@ -706,6 +856,8 @@ export default function CalenderView(p) {
<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>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 2, d.semesterid, d.moduleid)
@@ -713,7 +865,7 @@ export default function CalenderView(p) {
</div>))}
</div>
{/*gleich wie montag*/}
<div className={"spalte"}
id={"3"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -736,6 +888,8 @@ export default function CalenderView(p) {
<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>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 3, d.semesterid, d.moduleid)
@@ -743,7 +897,7 @@ export default function CalenderView(p) {
</div>))}
</div>
{/*gleich wie montag*/}
<div className={"spalte"}
id={"4"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -766,6 +920,8 @@ export default function CalenderView(p) {
<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>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 4, d.semesterid, d.moduleid)
@@ -773,7 +929,7 @@ export default function CalenderView(p) {
</div>))}
</div>
{/*gleich wie montag*/}
<div className={"spalte"}
id={"5"} style={{
gridTemplateRows: `repeat(96, ${cellHeight}px)`,
@@ -796,6 +952,8 @@ export default function CalenderView(p) {
<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>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 5, d.semesterid, d.moduleid)
@@ -805,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,
@@ -815,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,
@@ -876,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",
@@ -907,12 +1070,17 @@ 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
}}>
<p style={{
display: typeof window !== "undefined" && localStorage.getItem("admin") == 0 ? "block" : "none",
marginTop: 10,
fontSize: 20
}}>{Math.floor(timePlanned)}h {(Math.floor(timePlanned * 3) - Math.floor(Math.floor(timePlanned) * 3)) * 15} min
// 20h</p>
}}>{Math.floor(timePlanned)} Vorlesungsstunden {(Math.floor(timePlanned * 3) - Math.floor(Math.floor(timePlanned) * 3)) * 15} min
// 20 Vorlesungsstunden</p>
</div>
<div style={{
display: typeof window !== "undefined" && localStorage.getItem("admin") == 0 ? "block" : "none",
@@ -920,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}/>
+3
View File
@@ -1,2 +1,5 @@
//Achtung!!! hier kann die URL für das Backend auf das Online Backend geändert werden. Verwendung des Online Backends
//auf eigene Gefahr. Aktuellster Stand der Software kann hier in Kombination mit einem Lokalen Frontend nicht gewährleistet werden.
//export const baseURL = "http://185.245.96.48:8080"
export const baseURL = "http://localhost:8080"
+3 -3
View File
@@ -9,9 +9,9 @@ export default function DateElement(p){
let startDate = new Date(p.year, 0, p.startday);
let endDate = new Date(p.year, 0, p.startday + 5);
let startDateString = `${startDate.getDate()}.${startDate.getMonth()+1}.${startDate.getFullYear()}`;
let endDateString = `${endDate.getDate()}.${endDate.getMonth()+1}.${endDate.getFullYear()}`;
return (
let startDateString = `${startDate.getDate()}.${startDate.getMonth()+1}.${startDate.getFullYear()}`; //Anfang der Woche in der man sich befindet wird in startDateString geladen
let endDateString = `${endDate.getDate()}.${endDate.getMonth()+1}.${endDate.getFullYear()}`; //Ende der Woche in der man sich befindet wird in endDateString geladen
return /*Anzeige des Beginns und Endes der Woche in der man sich befindet*/(
<>
<div className="dateElement round-border box-shadow">
<p>{startDateString} - {endDateString}</p>
+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>`
+240 -262
View File
@@ -5,305 +5,270 @@ import Background from "@/components/Background";
import {baseURL} from "@/components/Constants";
import Back from "@/components/Back";
//dummy daten für die vorlesungsfächer
let modulesDummy = [
["Analysis", "Theo Inf 1"],
["Lineare Algebra", "Anwendungsprojekt"],
["Theo Inf 3", "Software Eng"],
["Security", "BWL"],
["Software Eng", "Security"],
["Studienarbeit", "Bachelor"]
["Grundlagen u. Logik", "Programmieren 1", "Programmieren 2", "Digitaltechnik", "Web. Eng.", "Analysis"],
["Lineare Algebra", "Anwendungsprojekt", "BWL", "Projektmanagement", "Algo. Kompl.", "Python", "Prolog"],
["Software Eng. 1", "Netztechnik", "Betriebssysteme", "Rechnerarchitektur", "Systemnahe Progra.", "Algorithmen 2", "Stochastik", "Angewandte Mathe."],
["Software Eng. 2", "Datenbanken", "Compilerbau", "Automaten", "Formale Sprachen", "IT-Sicherheit", "IOT"],
["Software Eng. 3", "Datenbanken 2", ],
["Bachelor"]
]
let tempSemesterNumber = 0
let update = false
let baseMapping = []
//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) {
const [startDate, setStartDate] = useState("0000-00-00")
const [endDate, setEndDate] = useState("0000-00-00")
const [courseName, setCourseName] = useState("")
const [startDate, setStartDate] = useState("")
const [endDate, setEndDate] = useState("")
const [semesterNumber, setSemesterNumber] = useState(0)
const [users, setUsers] = useState([])
const [modulesSelectorValues, setModulesSelectorValues] = useState(["nothing", "nothing"])
const [userModulesMapping, setUserModulesMapping] = useState({})
const [isChecked, setIsChecked] = useState([])
const [isActivated, setIsActivated] = useState([])
const [moduleUserMapping, setModuleUserMapping] = useState([])
const router = useRouter()
useEffect(() => {
setTimeout(() => {
update = false;
baseMapping = []
hasSemesterNumberChanged = false
let base = baseURL + "/semester/id?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid")
fetch(base).then(r => r.json()).then(j => {
tempSemesterNumber = j.number
setSemesterNumber(j.number)
setCourseName(j.name)
let tempStartDate = new Date(parseInt(j.startyear), 0, parseInt(j.startday))
let tempEndDate = new Date(parseInt(j.endyear), 0, parseInt(j.endday))
setStartDate(tempStartDate.getFullYear() + "-" + ((tempStartDate.getMonth() + 1).toString().padStart(2, "0")) + "-" + tempStartDate.getDate().toString().padStart(2, "0"))
setEndDate(tempEndDate.getFullYear() + "-" + ((tempEndDate.getMonth() + 1).toString().padStart(2, "0")) + "-" + tempEndDate.getDate().toString().padStart(2, "0"))
}).then(() => {
readModules()
update = true
}).catch(() => readModules())
}, 100)
}, [])
function readModules() {
let usersTemp = []
let userURL = baseURL + "/users/all?sessionid=" + localStorage.getItem("sessionid")
fetch(userURL).then(r => r.json()).then(j => {
setUsers(j)
usersTemp = j
let temp = [false, false, false]
let temp2 = []
for (let i = 0; i < j.length; i++) {
temp.push(false)
temp2.push(false)
}
setIsChecked(temp)
setIsActivated(temp2)
}).then(() => {
let modulesURL = baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&semesterid=" + localStorage.getItem("currentsid");
fetch(modulesURL).then(r => r.json()).then(j => {
setUserModulesMapping(j)
baseMapping = j
let temp = isChecked.slice()
let temp2 = isActivated.slice()
for (let i = 0; i < usersTemp.length; i++) {
let currentUser = usersTemp[i]
let found = false
let foundModuleLast = null
for (let f = 0; f < j.length; f++) {
let currentModule = j[f]
if (currentModule.userid === currentUser.id) {
found = true
foundModuleLast = currentModule
}
}
if (found) {
temp[i] = true
temp2[i] = foundModuleLast.activated === 1
}
}
setIsChecked(temp)
setIsActivated(temp2)
}).then(() => {
setModulesSelectorValues(modulesDummy[tempSemesterNumber])
})
//lädt zu beginn alle dummy daten des ersten semesters
let arr = []
modulesDummy[0].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
})
}
setModuleUserMapping(arr)
function onCourseNameChange(e) {
setCourseName(e.target.value)
}
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
let endYear = semester.endyear
let start = new Date(startYear, 0, semester.startday)
let end = new Date(endYear, 0, semester.endday)
function onStartDateChange(e) {
setStartDate(e.target.value)
}
setStartDate(startYear + "-" + ((start.getMonth() + 1) < 10 ? "0" + (start.getMonth() + 1) : (start.getMonth() + 1)) + "-" + (start.getDate() < 10 ? "0" + start.getDate() : start.getDate()))
setEndDate(endYear + "-" + ((end.getMonth() + 1) < 10 ? "0" + (end.getMonth() + 1) : (end.getMonth() + 1)) + "-" + (end.getDate() < 10 ? "0" + end.getDate() : end.getDate()))
function onEndDateChange(e) {
setEndDate(e.target.value)
}
tempSemesterNumber = semester.number
setSemesterNumber(semester.number)
function onSemesterNumberChange(e) {
setSemesterNumber(e.target.value)
setModulesSelectorValues(modulesDummy[e.target.value])
}
arr = []
modulesDummy[semester.number].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
})
function isOptionSelected(e, userid) {
let found = false;
}).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++)
{
for(let j = 0; j < modulesDummy[tempSemesterNumber].length; j++)
{
if(modulesDummy[tempSemesterNumber][j] == modules[i].name)
{
arr[j].userid = modules[i].userid
arr[j].moduleid = modules[i].id
arr[j].activated = modules[i].activated
break
}
}
}
for (let i = 0; i < userModulesMapping.length; i++) {
let current = userModulesMapping[i]
if (current.name === e && current.userid === userid) {
found = true;
}
}
return found;
}
function onCheckedChange(e, index) {
let temp = isChecked.slice()
temp[index] = e.target.checked
setIsChecked(temp)
if (!e.target.checked) {
let temp = []
let currentUser = users[index]
for (let j = 0; j < userModulesMapping.length; j++) {
if (userModulesMapping[j].userid !== currentUser.id) {
temp.push(userModulesMapping[j])
}
}
setUserModulesMapping(temp)
}
}
function onActivatedChange(e, index) {
let temp = isActivated.slice()
temp[index] = e.target.checked
setIsActivated(temp)
let userid = users[index].id
for (let j = 0; j < userModulesMapping.length; j++) {
if (userModulesMapping[j].userid === userid) {
userModulesMapping[j].activated = e.target.checked ? 1 : 0
}
}
}
function onModuleSelectionChange(e, index) {
let userid = users[index].id
let newMapping = []
let oldNamesIds = new Map()
for (let j = 0; j < userModulesMapping.length; j++) {
let currentModuleMapping = userModulesMapping[j]
if (currentModuleMapping.userid != userid) {
newMapping.push(currentModuleMapping)
} else {
oldNamesIds.set(currentModuleMapping.name, currentModuleMapping.id)
}
}
let found = false
for (let i = 0; i < e.target.options.length; i++) {
let currentOption = e.target.options[i]
if (currentOption.selected) {
found = true
newMapping.push({
"id": oldNamesIds.has(currentOption.value) ? oldNamesIds.get(currentOption.value) : -1,
"userid": userid,
"semesterid": -1,
"name": currentOption.value,
"activated": isActivated[index] ? 1 : 0
setModuleUserMapping(arr)
})
})
}
}
})
}, [])
let temp = isChecked.slice()
temp[index] = found
setIsChecked(temp)
setUserModulesMapping(newMapping)
}
function onButtonAbort() {
//sollte auf abbrechen geklickt worden sein...
function onButtonAbort(e) {
router.back()
}
function onButtonSave() {
let tempDateStart = new Date(parseInt(startDate.split("-")[0]), parseInt(startDate.split("-")[1]) - 1, parseInt(startDate.split("-")[2]))
let tempDateEnd = new Date(parseInt(endDate.split("-")[0]), parseInt(endDate.split("-")[1]) - 1, parseInt(endDate.split("-")[2]))
//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) {
let startDayInYear = Math.round((tempDateStart - new Date(tempDateStart.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24))
let endDayInYear = Math.round((tempDateEnd - new Date(tempDateEnd.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24))
//bereite alle relevanten daten des input form auf
let semesterid = localStorage.getItem("currentsid")
let startYear = parseInt(startDate.split("-")[0])
let endYear = parseInt(endDate.split("-")[0])
let semesterJson = {
"id": update ? localStorage.getItem("currentsid") : 0,
"startday": startDayInYear,
"endday": endDayInYear,
"name": courseName,
"startyear": tempDateStart.getFullYear(),
"endyear": tempDateEnd.getFullYear(),
"number": semesterNumber
let start = new Date(startYear, parseInt(startDate.split("-")[1]) - 1, parseInt(startDate.split("-")[2]))
let end = new Date(endYear, parseInt(endDate.split("-")[1]) - 1, parseInt(endDate.split("-")[2]))
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"), {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": 0,
"startday": startDayInYear,
"endday": endDayInYear,
"name": courseName,
"startyear": startYear,
"endyear": endYear,
"number": semesterNumber
})
}).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"), {
method: "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": semesterid,
"startday": startDayInYear,
"endday": endDayInYear,
"name": courseName,
"startyear": startYear,
"endyear": endYear,
"number": semesterNumber
})
}).then(() => modulesInBackend(semesterid))
}
}
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
method: update ? "PUT" : "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(semesterJson)
}).then(r => r.json()).then(async sem => {
let semesterID = sem.id
for (let i = 0; i < baseMapping.length; i++) {
let found = false
for (let j = 0; j < userModulesMapping.length; j++) {
if (baseMapping[i].name === userModulesMapping[j].name) {
found = true
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"
}).then(() => {
for (let i = 0; i < moduleUserMapping.length; i++) {
let current = moduleUserMapping[i]
if (current.userid != -1) {
if (current.moduleid == -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": 0,
"userid": current.userid,
"semesterid": semesterid,
"name": modulesDummy[semesterNumber][i],
"activated": current.activated
})
})
}
}
}
})
} else {
if (!found) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid") + "&id=" + baseMapping[i].id, {
method: "DELETE"
})
//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",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": 0,
"userid": current.userid,
"semesterid": semesterid,
"name": modulesDummy[semesterNumber][i],
"activated": current.activated
})
})
} 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"},
body: JSON.stringify({
"id": current.moduleid,
"userid": current.userid,
"semesterid": 0,
"name": "",
"activated": current.activated
})
})
}
//.. 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, {
method: "DELETE"
})
}
}
}
}
for (let i = 0; i < userModulesMapping.length; i++) {
userModulesMapping[i].semesterid = semesterID
setTimeout(() => {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: userModulesMapping[i].id === -1 ? "POST" : "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(userModulesMapping[i])
})
}, i * 200)
}
})
//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"}}
onChange={e => onCourseNameChange(e)} value={courseName}/>
<input type={"text"} className={"box-shadow round-border"}
style={{padding: 8, width: "100%", backgroundColor: (courseName == "") ? "#E44747" : "white"}}
onChange={(e) => {
setCourseName(e.target.value)
}} value={courseName}/>
<div style={{display: "flex", justifyContent: "flex-start", gap: 40}}>
<p>Theorie Anfang</p>
<p>Theorie Ende</p>
</div>
<div style={{display: "flex", justifyContent: "flex-start", gap: 20}}>
<input type={"date"} className={"box-shadow round-border"} style={{padding: 8, backgroundColor: (startDate == "" || startDate >= endDate) ? "#E44747" : "white"
}}
onChange={e => onStartDateChange(e)} value={startDate}/>
<input type={"date"} className={"box-shadow round-border"} style={{padding: 8, backgroundColor: (endDate == "" || startDate >= endDate) ? "#E44747" : "white"
}}
onChange={e => onEndDateChange(e)} value={endDate}/>
<input type={"date"} className={"box-shadow round-border"} style={{
padding: 8, backgroundColor: (startDate == "" || startDate >= endDate) ? "#E44747" : "white"
}} value={startDate} onChange={e => {
setStartDate(e.target.value)
}}/>
<input type={"date"} className={"box-shadow round-border"} style={{
padding: 8, backgroundColor: (endDate == "" || startDate >= endDate) ? "#E44747" : "white"
}} value={endDate} onChange={e => {
setEndDate(e.target.value)
}}/>
</div>
<p>Semester Wählen</p>
<select className={"round-border box-shadow"} style={{padding: 5, width: "100%"}} value={semesterNumber}
onChange={e => onSemesterNumberChange(e)}>
<select className={"round-border box-shadow"} style={{padding: 5, width: "27%"}} value={semesterNumber}
onChange={e => {
setSemesterNumber(e.target.value)
let arr = []
modulesDummy[e.target.value].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
})
setModuleUserMapping(arr)
hasSemesterNumberChanged = true
}}>
<option value={0}>1. Semester</option>
<option value={1}>2. Semester</option>
<option value={2}>3. Semester</option>
@@ -312,36 +277,45 @@ 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>
<tr>
<th>Wählen</th>
<th>Freischalten</th>
<th>Dozent</th>
<th>Modul</th>
<th>Dozent</th>
</tr>
{
users.map((user, index) => (
<tr>
modulesDummy[semesterNumber].map((module, index) => (
<tr style={{height: 50}}>
<td>
<input type={"checkbox"} checked={isChecked[index]}
onChange={e => onCheckedChange(e, index)}/>
<input type={"checkbox"}
checked={index < moduleUserMapping.length && moduleUserMapping[index].activated == 1}
onChange={e => {
let arr = moduleUserMapping.slice()
arr[index].activated = e.target.checked ? 1 : 0
setModuleUserMapping(arr)
}
}></input>
</td>
<td>
<input type={"checkbox"} checked={isActivated[index]}
onChange={e => onActivatedChange(e, index)}/>
<p style={{fontWeight: "normal"}}>{module}</p>
</td>
<td>
{user.firstName + " " + user.lastName}
</td>
<td>
<select multiple={true} className={"box-shadow round-border"}
style={{padding: 5}}
onChange={e => onModuleSelectionChange(e, index)}>
{modulesSelectorValues.map(msv => (
<option value={msv}
selected={isOptionSelected(msv, user.id)}>{msv}</option>
<select className={"box-shadow round-border"} style={{padding: 5}}
onChange={e => {
let arr = moduleUserMapping.slice()
arr[index].userid = e.target.value
setModuleUserMapping(arr)
console.log(moduleUserMapping)
}}
value={index < moduleUserMapping.length && moduleUserMapping[index].userid}>
<option value={-1}>-</option>
{users.map(user => (
<option value={user.id}>{user.firstName} {user.lastName}</option>
))}
</select>
</td>
@@ -359,8 +333,12 @@ 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 == "") ? () => {} : onButtonSave()}}/>
<Button text={"Speichern"} color={"#77932b"} onClick={() => {
(startDate == "" || endDate == "" || startDate >= endDate || courseName == "") ? () => {
} : onButtonSave()
}}/>
</div>
</div>
</>
+17 -5
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,7 +50,9 @@ export default function Login() {
const [inputUserName, setInputUserName] = useState("")
const [inputPassword, setInputPassword] = useState("")
const [hint, setHint] = useState("type here")
//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)")
const router = useRouter()
@@ -48,19 +60,19 @@ export default function Login() {
return (
// <div className="border">
<login className={"login-container box-shadow"}>
<p className={"font-big-fat placement"}>Login</p>
<div className={"placement"}>
<br/>
<p className={"font-kinda-big"}>Username</p>
<p className={"font-kinda-big"}>Benutzername:</p>
<input type="text" value={inputUserName} onChange={e => setInputUserName(e.target.value.toLowerCase())}
placeholder={hint} className="input input-bordered input-sm w-full max-w-xs box-shadow"
style={{
backgroundColor: backgroundColor
}}/>
<br/>
<p className={"font-kinda-big"}>Password</p>
<p className={"font-kinda-big"}>Passwort:</p>
<input type="password" value={inputPassword} onChange={e => setInputPassword(e.target.value)}
placeholder={hint} className="input input-bordered input-sm w-full max-w-xs box-shadow"
placeholder={hint2} className="input input-bordered input-sm w-full max-w-xs box-shadow"
style={{
backgroundColor: backgroundColor
}}/>
+17 -5
View File
@@ -5,18 +5,30 @@ import {console} from "next/dist/compiled/@edge-runtime/primitives/console";
export default function StatusBar(p)
{
if(p.progress > 100) p.progress = 100;
let classNames = ["not-started", "started", "finished"];
let classNames = ["not-started"];
let index = p.progress / 50;
let index2 = p.progress / 100;
let index3 = p.progress - 100;
let index4 = p.progress - 50;
let actives = ["", "", ""]
let actives = ["", "", ""];
actives[index] = "active";
let actives2 = ["", "", ""];
actives2[index2] = "active";
let actives3 = ["", "", ""];
actives3[index3] = "active";
let actives4 = ["", "", ""];
actives4[index4] = "active";
return (
<div className={"step-container"}>
<div className={"steps"}>
<span className={"step " + classNames[0] + " " + actives[0]}>1</span>
<span className={"step " + classNames[1] + " " + actives[1]}>2</span>
<span className={"step " + classNames[2] + " " + actives[2]}>3</span>
<span className={"step " + classNames[0] + " " + actives[0] + actives2[1] + actives3[1] + actives4[0]}>1</span>
<span className={"step " + classNames[0] + " " + actives[1] + actives2[1] + actives3[1] + actives4[1]}>2</span>
<span className={"step " + classNames[0] + " " + actives[2] + actives2[2] + actives3[2] + actives4[2]}>3</span>
<div className={"progress-bar " + classNames[index]}
style={{
width: p.progress + "%"
+7 -12
View File
@@ -1,19 +1,14 @@
//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)
{
// let datum = new Date(2023, 1, 10);
// let start = new Date(datum.getFullYear(), 0, 0);
//
// let difference = (datum - start) / (1000 * 60 * 60 * 24)
let day = 41
let datum = new Date(2023, 0, 30)
let datum = new Date(2023, 0, day)
datum.getMonth()
return (
<div>
<p>{datum.getMonth()}</p>
</div>
);
let datum2 = new Date(2023, 5, 12);
let start = new Date(datum2.getFullYear(), 0, 0);
let dayInYear = (datum2 - start) / (1000 * 60 * 60 * 24)
}
+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 });
+1 -2
View File
@@ -2,13 +2,12 @@ import Button from "@/components/Button";
import DateElement from "@/components/DateElement";
import { arrowLeft } from "./Icons"
import { arrowRight } from "./Icons"
import { useState } from 'react'
export default function WeekSelector(p){
return (
return /*Aufruf des DateElements mit aktuellem Starttag im Jahr und dem Jahr, sowie Buttons zum hin und her Wechsel der Wochen*/(
<>
<div className="weekSelector">
<Button icon={arrowLeft} onClick={() => p.onFunctionLeft()} width={50} color={"#346991"}/>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 19 KiB

+34 -34
View File
@@ -15,27 +15,26 @@ export default function Help(p)
return (
<div>
<Back onClick={() => router.back()}/>
<div className={"help-line"}>
<img src={screen1.src}/>
<div className={"text-form"}>
<h1>Die Monats-Seiten-Leiste</h1>
<p>- Hier kannst du sehen in welchem Monat du dich aktuell befindest (blau hinterlegt).</p>
<p>- Durch einen Links-Klick auf eine Monatskacheln kannst du direkt an den Anfang dieses Monats springen</p>
<h1>Die Monats-Leiste</h1>
<p>- Hier siehst du in welchem Monat Sie sich aktuell befinden (blau hinterlegt)</p>
<p>- Durch einen Links-Klick auf eine Monatskacheln springst du direkt an den Anfang des jeweiligen Monats</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen2.src}/>
<img src={screen2.src} width={1000}/>
<div className={"text-form"}>
<h1>Die Planungs-Ansicht</h1>
<p>- Hier siehst du alle deine Termine in grün (bzw. gelb bei Warnungen) und von anderen Dozenten in grau</p>
<p>- Hier siehst du deine eingetragenen Vorlesungen in diesem Kurs in Grün, deine eigenen Vorlesungen aus anderen Kursen in Blau und die geplanten Vorlesungen anderer Dozenten in Grau</p>
<p>- Durch einen Links-Klick kannst du eine neue Vorlesung an einem Tag erstellen</p>
<p>- Durch Halten der dunkleren Leisten kannst du die Zeiten des Termins anpassen</p>
<p>- Durch Rechts-Klick kannst du eine Vorlesung löschen</p>
<p>- Durch Klicken auf die Pfeiltasten oben kannst du die Woche wechseln</p>
<p>- Bitte beachte, dass du Vorlesungen nur zwischen den beiden Roten linien erstellen kannst</p>
<p>- Ausgegraute Tage liegen nicht im Semester, hier kannst du nicht planen</p>
<p>- Durch Halten der dunkleren Leisten ist es möglich die Zeiten deiner Termine anzupassen</p>
<p>- Durch einen Rechts-Klick können eigene Termine gelöscht werden</p>
<p>- Mithilfe der Navigationsleiste ist es möglich die Wochen zur Planung zu wechseln</p>
<p>- Ausgegraute Tage liegen entweder nicht im Semester oder sind Feiertage, hier kann nicht geplant werden</p>
</div>
</div>
@@ -44,16 +43,7 @@ export default function Help(p)
<div className={"text-form"}>
<h1>Die Warnungs-Ansicht</h1>
<p>- Sollte ein Termin gelb erscheinen kannst du hier sehen woran das liegt</p>
<p>- Warnung sind empfohlene Verbesserungsverschläge aber müssen nicht zwangshaft beachtet werden</p>
<p>- Sollte hier "Okay" für einen Tag stehen ist alles perfekt</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen5.src}/>
<div className={"text-form"}>
<h1>Der Login</h1>
<p>- Hier kannst du dich mit deiner Email und deinem Passwort einloggen</p>
<p>- Warnung sind empfohlene Verbesserungsverschläge, müssen aber nicht zwangshaft beachtet werden</p>
</div>
</div>
@@ -69,15 +59,23 @@ export default function Help(p)
<div className={"help-line"}>
<img src={screen6.src}/>
<div className={"text-form"}>
<h1>Das Dashboard</h1>
<h2>Für Admins:</h2>
<p>- Über den "+" Knopf kannst du ein neues Semester erstellen</p>
<p>- Über den Stift kannst du ein bestehendes Semester editieren</p>
<p>- Über den Mülleimer kannst du ein bestehndes Semester löschen</p>
<h2>Für Dozenten (und Admins):</h2>
<p>- Hier siehst du deine Semester mit den jeweiligen Modulen</p>
<p>- Sollte ein Semester bei dir Ausgegraut sein, wurdest du für dieses schon gewählt aber noch nicht freigeschalten</p>
<p>- Duch einen Links-Klick auf ein weises Semester kann in die Planungsübersicht gewechselt werden</p>
<h1>Das Dashboard für Admins</h1>
<p>- Hier werden alle bestehenden Semester gelistet</p>
<p>- Über den "+" Button ist es möglich ein neues Semester zu erstellen</p>
<p>- Über das Stift-Symbol kann ein bestehends Semester editiert werden</p>
<p>- Über das Mülleimer-Symbol kann ein bestehndes Semester gelöscht werden</p>
<p>- Die Fortschrittsanzeige bleibt auf der (1) bis ein Dozent seinen Plan abgegeben hat, sobald das geschieht wechselt sie auf die (2) und wenn alle Dozenten ihre Pläne abgegeben haben, springt die Anzeige auf die (3)</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen5.src}/>
<div className={"text-form"}>
<h2>Das Dashboard für Dozenten</h2>
<p>- Hier werden alle Semester angzeigt in welchem der eingeloggte Dozent Vorlesungen planen soll</p>
<p>- Sollte ein Semester ausgegraut sein, wurden Sie für dieses schon gewählt aber noch nicht freigeschalten</p>
<p>- Durch einen Links-Klick auf ein weißes Semester kann in die Planungsübersicht gewechselt werden</p>
<p>- Die Fortschrittsanzeige bleibt auf der (1) bis eine Vorlesung geplant wird, sobald das geschieht wechselt sie auf die (2) und wenn der Dozent seinen Plan abgibt, springt die Anzeige auf die (3)</p>
</div>
</div>
@@ -85,10 +83,12 @@ export default function Help(p)
<img src={screen7.src}/>
<div className={"text-form"}>
<h1>Semester erstellen / bearbeiten</h1>
<p>- Hier kannst du alle daten wie Name, Start- und Endzeitpunkt eines Semesters eintragen</p>
<p>- Du kannst einen Dozenten "wählen" d.h. er soll in diesem Semester dozieren</p>
<p>- Jedem Dozenten kannst du ein Modul zuordnen, welches er dozieren soll</p>
<p>- Sobald du die Schaltfläche "Freischalten" aktiviert hast, kann der Dozent mit der eigenständigen Planung beginnen.</p>
<p>- Hier müssen die folgenden Daten eingetragen werden: Kursname sowie Start- und Endzeitpunkt einer Vorlesungsphase</p>
<p>- Der Start muss vor dem Endzeitpunkt liegen</p>
<p>- Einen Dozenten zu wählen bedeutet ihn dem Kurs hinzuzufügen, sollte ihm kein Modul zugewiesen werden, wird er automatisch abgewählt</p>
<p>- Ein Dozent muss mindestens ein, kann aber auch mehrere Module zugewiesen bekommen</p>
<p>- Um einem Dozenten mehrere Module zuzuweisen, halte die "STRG"-Taste gedrückt während du per Links klick die Module auswählst</p>
<p>- Sobald die Schaltfläche "Freischalten" aktiviert wurde, kann der Dozent mit der eigenständigen Planung beginnen</p>
<p>- Jeder genannte Schritt, insbesondere der Letzte kann auch nachträglich im Bearbeitungsmodus ausgeführt werden</p>
</div>
</div>
+14 -2
View File
@@ -11,11 +11,15 @@ 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
if(!(isEdge || isChrome))
//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")
}
@@ -26,7 +30,6 @@ export default function Home(p) {
<div className={"normal-centered"}>
<Background/>
<HelpButton/>
<h1 style={{
fontSize: 40,
fontWeight: "bold",
@@ -36,6 +39,15 @@ export default function Home(p) {
textAlign: "center"
}}>Willkommen in deinem Vorlesungsplaner</h1>
<Login/>
<p1 style={{
fontSize: 18,
fontWeight: "bold",
color: "red",
marginTop: "5%",
textAlign: "center",
maxWidth: 450,
justifyContent: "start"
}}>Es handelt sich hierbei um eine BETA-VERSION! Keine Gewähr auf Korrekte oder vollständige Informationen</p1>
</div>
)
}
+34 -24
View File
@@ -22,6 +22,7 @@ export default function SemesterOverview(p) {
let allModules
let allEntries
//Datenanfrage an das Backend für alle existierenden Semester
await fetch(urlTest).then(response => response.json()).then(s => {
allSemesters = s
if (set) {
@@ -30,17 +31,21 @@ export default function SemesterOverview(p) {
}).then(() => {
if(!set)
{
//Datenanfrage an das Backend um alle Module zu erhalten
fetch(baseURL + "/module/all?sessionid=" + localStorage.getItem("sessionid")).then(r => r.json()).then(mod => {
allModules = mod
}).then(() => {
//Datenanfrage an das Backend um alle gesetzten Entries zu erhalten
fetch(baseURL + "/entries/all?sessionid=" + localStorage.getItem("sessionid")).then(r => r.json()).then(en => {
allEntries = en
}).then(() => {
let modulesCountInSemester = []
for (let i = 0; i < allSemesters.length; i++) {
for (let i = 0; i < allSemesters.length; i++) //durchlaufe die Anzahl der Semester welche von dem Backend zurück gegeben wurden
{
let count = 0
for (let j = 0; j < allModules.length; j++) {
if (allSemesters[i].id === allModules[j].semesterid) {
for (let j = 0; j < allModules.length; j++) { //durchlaufe die Anzahl der Module welche von dem Backend zurück gegeben wurden
if (allSemesters[i].id === allModules[j].semesterid) //Prüfe ob das Modul zu dem jeweiligen Semester gehört und erhöhe count
{
count++;
}
}
@@ -48,20 +53,25 @@ export default function SemesterOverview(p) {
}
let temp = []
for (let s = 0; s < allSemesters.length; s++) {
for (let s = 0; s < allSemesters.length; s++) //durchlaufe die Anzahl der Semester welche von dem Backend zurück gegeben wurden
{
let count = 0;
for (let i = 0; i < allModules.length; i++) {
if (allModules[i].semesterid === allSemesters[s].id) {
for (let i = 0; i < allModules.length; i++) //durchlaufe die Anzahl der Module welche von dem Backend zurück gegeben wurden
{
if (allModules[i].semesterid === allSemesters[s].id) //Prüfe ob das Modul zu dem jeweiligen Semester gehört
{
let sum = 0
let ent = allEntries.filter(e => e.moduleid === allModules[i].id)
for (let j = 0; j < ent.length; j++) {
sum += ent[j].timeend - ent[j].timestart
let ent = allEntries.filter(e => e.moduleid === allModules[i].id) //lade alle Entries die zu dem Modul gehören in dem wir uns befinden in die Variable
for (let j = 0; j < ent.length; j++) //durchlaufe die Anzahl der Entries aus ent
{
sum += ent[j].timeend - ent[j].timestart //summiere die Dauer aller Entries in dem Semester
}
sum /= 3
if (sum >= 20 && allModules[i].activated === 0) {
if (sum >= 20 && allModules[i].activated === 0) //Überprüfung ob alle 20 Schulstunden eines Moduls gesetzt worden sind und der Vorlesungsplan des Moduls abgegeben worden ist
{
count++;
}
}
@@ -75,7 +85,7 @@ export default function SemesterOverview(p) {
temp.push(100)
}
setProgresses(temp)
setProgresses(temp) //setze die Fortschrittsleiste entsprechend der Einträge im Semester
}
@@ -89,7 +99,7 @@ export default function SemesterOverview(p) {
function onClickSemester(e, m) {
if (m.target === m.currentTarget) {
localStorage.setItem("currentsid", e.id)
router.push("/planning")
router.push("/planning") //leite weiter auf die Planungsseite
localStorage.setItem("semestername", e.name + " Sem. " + (e.number + 1))
}
@@ -97,7 +107,7 @@ export default function SemesterOverview(p) {
function onClickNewSemester() {
localStorage.setItem("currentsid", 0);
router.push("/createSemester");
router.push("/createSemester"); //leite weiter auf die Seite für das Inputform zur Erstellung eines neuen Semesters
}
@@ -115,9 +125,9 @@ export default function SemesterOverview(p) {
async function funcButtonDelete() {
let id = localStorage.getItem("currentsid");
let url = baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid") + "&id=" + id;
let url = baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid") + "&id=" + id; //Anfrage an das Backend auf spezifisches Semesters auf das geklickt worden ist
await fetch(url, {
method: "DELETE"
method: "DELETE" //lösche das spezifisch angeklickte Semester
});
togglePopup();
@@ -129,6 +139,7 @@ export default function SemesterOverview(p) {
localStorage.setItem("currentsid", e.id);
let semester = e;
//setze die Einträge des Semesters auf die aktuell gespeicherten Einträge
let startYear = semester.startyear;
let endYear = semester.endyear;
let startDay = semester.startday;
@@ -137,6 +148,7 @@ export default function SemesterOverview(p) {
let startDate = new Date(startYear, 0, startDay + 1);
let endDate = new Date(endYear, 0, endDay + 1);
//speichere die abgeänderten Daten des Semesters
await router.push({
pathname: "/createSemester",
query: {
@@ -150,13 +162,11 @@ export default function SemesterOverview(p) {
useEffect(() => {
getSemesters(true);
}, [])
useEffect(() => {
setTimeout(() => {
getSemesters(false)
}, 1000)
})
}, 2000)
}, [])
const [entries, setEntries] = useState([])
@@ -172,16 +182,16 @@ export default function SemesterOverview(p) {
{
entries.map((e, index) => (
<div className={"semester-tile box-shadow"} onClick={(f) => onClickSemester(e, f)}>
<SemesterTile text={e.name + " Sem. " + (e.number + 1)} onClick={(f) => onClickSemester(e, f)}
<SemesterTile text={e.name + " Sem. " + (e.number + 1)} onClick={(f) => onClickSemester(e, f) /*Darstellung der Semester mit ihren Namen und der Semesternummer in welcher der Kurs sich befindet*/}
onButtonDeleteClick={() => {
localStorage.setItem("currentsid", e.id)
setModalHint(e.name + " Löschen?");
togglePopup();
}} onButtonEditClick={(m) => {
localStorage.setItem("currentsid", e.id)
funcButtonEdit(e, m);
funcButtonEdit(e, m) /*Aufruf der Editierfunktion für das Angeklickte Semester*/;
}}/>
<StatusBar progress={progresses[index]}/>
<StatusBar progress={progresses[index] /*Fortschrittsleiste wird gesetzt*/}/>
<div style={
{
display: "flex",
@@ -204,7 +214,7 @@ export default function SemesterOverview(p) {
</div>))
}
<Button color={"#dcdcdc"} text={"+"} width={240} height={160} fontColor={"black"} fontSize={50}
onClick={() => onClickNewSemester()}/>
onClick={() => onClickNewSemester() /*Zuweisung der Funktion für den Button zu Erstellung eines neuen Semesters*/}/>
<PopUp hint={modalHint} text1={"Abbrechen"} text2={"Löschen"} displayState={modalDisplay}
function1={funcButtonAbort} function2={funcButtonDelete}/>
</div>
+17 -11
View File
@@ -14,41 +14,48 @@ export default function SemesteroverviewLecturer(p) {
function getModules() {
let urlTest = baseURL + "/module/id?sessionid=" + localStorage.getItem("sessionid");
//Datenanfrage an das Backend für alle Module welche dem User zugewiesen worden sind
fetch(urlTest).then(response => response.json()).then(m => {
setEntries(m);
let args = "";
for (let i = 0; i < m.length; i++) {
args += m[i].semesterid;
for (let i = 0; i < m.length; i++) //durchlaufe die Anzahl der Module
{
args += m[i].semesterid; //füge dem String "args" die Einträge hinzu
if (i < m.length - 1) {
args += "a";
args += "a"; //trenne die Einträge durch ein "a" voneinander ab
}
}
let temp = []
let semesterURL = baseURL + "/semester/id/all?ids=" + args + "&sessionid=" + localStorage.getItem("sessionid");
//Datenanfrage an das Backend für alle Semester welche dem User für die Planung zugewiesen sind
fetch(semesterURL).then(r => r.json()).then(sem => {
sem.map(e => {
temp.push(e.name + " Sem. " + (e.number + 1))
temp.push(e.name + " Sem. " + (e.number + 1)) //lade das Semester in welchem der Kurs sich befindet in das Array "temp"
})
}).then(() => setSemesterNames(temp)).then(() => {
let entriesURL = baseURL + "/entries/all?sessionid=" + localStorage.getItem("sessionid")
//Datenanfrage an das Backend aller Entries eines Moduls eines Semesters (automatisch nur die Entries die durch den User erstellt worden sind)
fetch(entriesURL).then(r => r.json()).then(en => {
let tempTimeStamps = []
for(let j = 0; j < m.length; j++)
for(let j = 0; j < m.length; j++) //durchlaufe die Anzahl an Modulen die von dem Backend zurückgegeben worden sind
{
let sum = 0
let currentModule = m[j]
for (let i = 0; i < en.length; i++)
for (let i = 0; i < en.length; i++) //durchlaufe die Anzahl der Entries die von dem Backend zurückgegeben worden sind
{
if(currentModule.id === en[i].moduleid)
{
sum += en[i].timeend - en[i].timestart
sum += en[i].timeend - en[i].timestart //summiere die Dauer all dieser Entries
}
}
sum /= 3
tempTimeStamps.push(sum)
tempTimeStamps.push(sum) //lade die Summe aller Entries eines Moduls in das Array "tempTimeStamps"
}
setTimeStamps(tempTimeStamps)
@@ -82,9 +89,8 @@ export default function SemesteroverviewLecturer(p) {
const [semesterNames, setSemesterNames] = useState([]);
const router = useRouter();
function getProgressForTime(time, activated)
function getProgressForTime(time, activated)//überprüfe welchen Status die Fortschrittsanzeige haben muss und gib diesen zurück
{
console.log(activated)
if(time === 0)
{
@@ -113,7 +119,7 @@ export default function SemesteroverviewLecturer(p) {
editable={false} text={semesterNames[index]} text2={e.name}
onClick={(f) => onClickSemester(e, f, semesterNames[index])}
/>
<StatusBar progress={getProgressForTime(timeStamps[index], e.activated)} module={e}/>
<StatusBar progress={getProgressForTime(timeStamps[index], e.activated)/*beladenes Array "timeStamps" an der Stelle "index" => relevante Summe der Einträge eines Moduls in einem Semester/Kurs*/} module={e}/>
</div>
))}
</div>
+3 -16
View File
@@ -188,32 +188,20 @@ Step Progress Bar
.steps .not-started {
/*background-image: linear-gradient(#b42121, #b44821);*/
background-color: #77932b;
background-color: grey;
}
.steps .started {
/*background-image: linear-gradient(#c75c0c, #c77c0c);*/
background-color: #77932b;
}
.steps .finished {
/*background-image: linear-gradient(#43C20BFF, #0bc27c);*/
background-color: #77932b;
}
.steps .active {
/*border-width: 2px;*/
/*border-color: #1e2428;*/
background-color: #346991;
background-color: #77932b;
}
.progress-bar {
position: absolute;
height: 8px;
background-color: #5d606e;
background-color: #77932b;
z-index: 100;
}
@@ -446,7 +434,6 @@ Login
flex-direction: column;
align-items: center;
justify-content: space-evenly;
/*gap: 10px;*/
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.5);
width: 375px;
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="h2-2.1.214">
<CLASSES>
<root url="jar://$PROJECT_DIR$/H2JDBCDriver/h2-2.1.214.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+1 -1
View File
@@ -8,5 +8,5 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_20" default="true" project-jdk-name="20" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="20" project-jdk-type="JavaSDK" />
</project>
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -10,6 +10,16 @@ import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//kleiner hinweis zur Datenbank:
//die datenkbank H2 benötigt die beiden dateien database.mv.db und database.trace.db
//um die datenbank verwenden zu können muss der jdbc driver in das projekt eingebunden sein.
//dieser driver liegt im ordner als h2jdbcdriver als .jar datei
//der nutzername für die datenbank ist: adm
//das passwort für die datenbank ist: 73bgjfdsfJ!934
//die datenbank als einzelnes kann entweder über die h2console (windows) oder jetbrains datagrip (alle systeme) editiert werden.
//oder über jedes weitere tool welches h2 datenbanken unterstützt.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public class DataBaseHandler {
//singleton instance of database handler
private static DataBaseHandler instance = null;
@@ -49,7 +59,7 @@ public class DataBaseHandler {
st.executeUpdate("insert into entries (daynumber, yearnumber, semesterid, usercreatedbyid, timestart, timeend, moduleid, info) values (" +
entry.getDaynumber() + ", " + entry.getYearnumber() + ", " + entry.getSemesterid() + ", " +
entry.getUsercreatedbyid() + ", " + entry.getTimestart() + ", " + entry.getTimeend() + ", " + entry.getModuleid() + " ,'" + entry.getInfo() + "')"
);
); //Datenbank Eintrag eines neu erstellten Entry mit allen nötigen Informationen
}
catch(Exception e)
{
@@ -68,28 +78,31 @@ public class DataBaseHandler {
Entry current = null;
while ((current = resultSetToEntry(rs)) != null) {
entryList.add(current);
}
} //Datenbankanfrage für alle Entries bei denen die Semesterid, das Jahr und der Tag mit den übergebenen Paramtern übereinstimmt
Entry[][] entries = new Entry[6][20];
for (int i = 0; i < 6; i++) {
for (int i = 0; i < 6; i++) //durchlaufe die Anzahl der Tage einer Vorlesungswoche (Montag,...,Samstag)
{
int f = 0;
for (int j = 0; j < entryList.size(); j++) {
for (int j = 0; j < entryList.size(); j++)
{
if (entryList.get(j).getDaynumber() == i + daynumber) {
entries[i][f] = entryList.get(j);
entries[i][f] = entryList.get(j); //belade das Array "entries" mit dem entries einer woche
f++;
}
}
}
return entries;
return entries; //gib das Array "entries" zurück
} catch (Exception e) {
return null;
}
}
public Entry[][] getAllEntrys(int semesterid, int daynumber, int yearnumber, int userid) {
public Entry[][] getAllEntrys(int semesterid, int daynumber, int yearnumber, int userid) //Datenbankanfrage für alle Entries eines Users in einem Semester
{
try {
ResultSet rs = st.executeQuery("select * from entries where " +
"semesterid<>" + semesterid +
@@ -119,7 +132,7 @@ public class DataBaseHandler {
}
public Entry[] getAllEntries()
public Entry[] getAllEntries() //Datenbankanfrage für alle Entries
{
try {
ResultSet rs = st.executeQuery("select * from entries");
@@ -137,7 +150,7 @@ public class DataBaseHandler {
}
}
public Entry[] getAllEntriesModule(int moduleid)
public Entry[] getAllEntriesModule(int moduleid) //Datenbankanfrage für alle Entries eines spezifischen Moduls
{
try {
ResultSet rs = st.executeQuery("select * from entries where moduleid=" + moduleid);
@@ -156,7 +169,8 @@ public class DataBaseHandler {
}
}
public void deleteEntry(int id) {
public void deleteEntry(int id) //Löschung eines spezifischen entries
{
try {
st.executeUpdate("delete from entries where id=" + id);
} catch (Exception e) {
@@ -164,7 +178,8 @@ public class DataBaseHandler {
}
}
public void updateEntry(Entry entry) {
public void updateEntry(Entry entry) //Aktualisiere Einträge eines Entry falls es verändert wurde
{
try {
st.executeUpdate("update entries set timeend=" + entry.getTimeend() + ", timestart=" + entry.getTimestart() + " where id=" + entry.getId());
} catch (Exception e) {
@@ -209,7 +224,8 @@ public class DataBaseHandler {
}
}
public Semester getSemester(int id) {
public Semester getSemester(int id)
{
try {
ResultSet rs = st.executeQuery("select * from semester where id=" + id);
return resultSetToSemester(rs);
@@ -244,7 +260,8 @@ public class DataBaseHandler {
}
}
public Semester updateSemester(Semester semester) {
public Semester updateSemester(Semester semester) //Aktualisiere die Einträge eines Semesters bei Veränderungen durch editier Funktion
{
try {
st.executeUpdate("update semester set startday=" + semester.getStartday() + ", " +
"endday=" + semester.getEndday() + ", " +
@@ -260,6 +277,7 @@ public class DataBaseHandler {
}
}
//ist dafür da, um ein semester anhand seiner id aus der datenbank zu löschen
public void deleteSemester(int id) {
try {
st.executeUpdate("DELETE FROM modules WHERE semesterid=" + id);
@@ -270,6 +288,7 @@ public class DataBaseHandler {
}
}
//kann ein resultset der datenbank in ein internes semester objekt umwandeln.
public Semester resultSetToSemester(ResultSet rs) {
try {
rs.next();
@@ -301,6 +320,7 @@ public class DataBaseHandler {
}
}
//ein modul anhand der zuweisung von dozent und semester bekommen.
public Module getModule(int userid, int semesterid) {
try {
ResultSet rs = st.executeQuery("select * from modules where userid=" + userid + " and semesterid=" + semesterid);
@@ -311,7 +331,7 @@ public class DataBaseHandler {
}
}
//get module objects by its semester and its lecturer
//bekomme alle modulzuweisungen, die zu einem dozenten gehören.
public Module[] getModules(int userid) {
try {
ResultSet rs = st.executeQuery("SELECT * FROM modules WHERE userid = " + userid);
@@ -328,6 +348,7 @@ public class DataBaseHandler {
}
}
//füge eine neue modulzuweisung zwischen dozenten und fächern hinzu
public Module addModule(Module m) {
try {
st.executeUpdate("insert into modules (userid, semesterid, name, activated) " +
@@ -340,6 +361,7 @@ public class DataBaseHandler {
}
}
//gibt alle zuweisungen zurück.
public Module[] getAllModules() {
try {
ResultSet rs = st.executeQuery("SELECT * FROM modules");
@@ -355,12 +377,13 @@ public class DataBaseHandler {
}
}
//updatet eine zuweisung anhand ihrer id
public Module updateModule(Module m) {
try {
st.executeUpdate("update modules set activated=" + m.getActivated() + ", semesterid=" + m.getsemesterid() + ", name='" + m.getName() + "' where id=" + m.getid());
st.executeUpdate("update modules set activated=" + m.getActivated() + ", userid=" + m.getUserid() + " where id=" + m.getid());
return getModule(m.getid());
@@ -370,6 +393,7 @@ public class DataBaseHandler {
}
}
//setzt die aktivierung einer modulzuweisung zurück.
public void submitModule(int id)
{
try
@@ -382,6 +406,20 @@ public class DataBaseHandler {
}
}
//kann alle modulzuweisungen innerhalb eines semesters löschen.
//hierbei werden auch alle termine mit gelöscht.
public boolean deleteModuleBySemesterID(int id) {
try {
st.executeUpdate("delete from modules where semesterid=" + id);
st.executeUpdate("delete from entries where semesterid=" + id);
return true;
} catch (Exception ex) {
return false;
}
}
//kann eine einzelne modulzuweisung anhand ihrer id löschen.
//hierbei werden auch alle zu dieser zuweisung gehörigen termine gelöscht
public boolean deleteModule(int id) {
try {
st.executeUpdate("delete from modules where id=" + id);
@@ -392,6 +430,7 @@ public class DataBaseHandler {
}
}
//kann ein result set der datenbank in ein internes modul objekt umwandeln.
public Module resultSetToModule(ResultSet rs) {
try {
rs.next();
@@ -430,7 +469,7 @@ public class DataBaseHandler {
}
}
//einen User
//einen User anhand seiner email und passwort zurückgeben.
public User getUser(String mail, String password) {
try {
@@ -443,6 +482,8 @@ public class DataBaseHandler {
return null;
}
//einen nutzer andhand seiner id zurückgeben.
//diese funktion sollte nur für admins verfügbar sein.
public User getUser(int id) {
try {
ResultSet rs = st.executeQuery("select * from users where id=" + id);
@@ -452,6 +493,7 @@ public class DataBaseHandler {
}
}
//ein nutzer anhand seiner mail zurückgeben. diese funktion sollte nur für admins erreichbar sein.
public User getUser(String mail) {
try {
ResultSet rs = st.executeQuery("select * from users where mail='" + mail + "'");
@@ -465,6 +507,8 @@ public class DataBaseHandler {
}
}
//kann ein result set der datenbank in ein internes nutzer objekt umwandeln.
public User resultSetToUser(ResultSet rs) {
try {
rs.next();
@@ -507,6 +551,8 @@ public class DataBaseHandler {
}
//kann einen nutzer updaten, aber auch dessen rechte verändern, hierbei werden die rechte nur angepasst,
//wenn der boolean elevationRequestByAdmin true ist
public User updateUser(User user, int id, boolean elevationRequestByAdmin) {
try {
String password = user.getPassword();
@@ -544,6 +590,8 @@ public class DataBaseHandler {
}
}
//hier kann ein nutzer anhand seiner email addresse gelöscht werden.
//diese funktion sollte nur für den eigenen nutzer oder für admins verfügbar sein.
public boolean deleteUser(String mail) {
try {
ResultSet rs = st.executeQuery("SELECT id FROM user WHERE mail='" + mail + "'");
@@ -1,6 +1,6 @@
package com.example.backend.anwprj.Entries;
//entry data class
//interne klasse für die darstellung von terminen
public class Entry
{
private int id;
@@ -1,6 +1,6 @@
package com.example.backend.anwprj.Module;
//module data class
//klasse für die interne darstellungen für die zuweisungen zwischen dozenten und fächern.
public class Module {
private int id;
private int userid;
@@ -1,6 +1,6 @@
package com.example.backend.anwprj.Semesters;
//semester data class
//klasse für die interne darstellung von semestern.
public class Semester
{
private int id;
@@ -1,6 +1,6 @@
package com.example.backend.anwprj.Users;
//user data class
//klasse für die darstellung von benutzerobjekten.
public class User
{
private int id;
@@ -1,6 +1,6 @@
package com.example.backend.anwprj.Users;
//mapping of the integer rights to enum
// zuweisung der zahlen 0 für normaler user / dozenten und 1 für admin.
public enum UserPermissions
{
self(0),
@@ -5,6 +5,9 @@ import com.example.backend.anwprj.Database.DataBaseHandler;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
//diese klasse kümmert sich um die zuweisungen von nutzern und deren sessionids.
//wird für alle möglichen anfragen der nutzer an das backend verwendet um eine sessionid
//in ein benutzerobjekt aufzulösen.
public class UserSessionIDHandler
{
//stores mapping of session ids to users
@@ -169,6 +169,18 @@ public class ModuleController
DELETE
Delete A Module
*/
@CrossOrigin
@DeleteMapping("/module/bysemesterid")
public void deleteModuleBySemesterID(@RequestParam(name = "sessionid") String sessionid, @RequestParam(name="id") int id)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if (u != null && u.getPermissions() == UserPermissions.admin.getValue())
{
db.deleteModuleBySemesterID(id);
}
}
@CrossOrigin
@DeleteMapping("/module")
public void deleteModule(@RequestParam(name = "sessionid") String sessionid, @RequestParam(name="id") int id)
@@ -43,6 +43,7 @@ public class SemesterController
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//get a semester object by its id
@CrossOrigin
@GetMapping("/semester/id")
public ResponseEntity<Semester> getSemester(@RequestParam(name="id") int id, @RequestParam(name="sessionid") String sessionID)
@@ -63,6 +64,7 @@ public class SemesterController
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//takes in a list of semester ids seperatet by an a as list seperator
@CrossOrigin
@GetMapping("/semester/id/all")
public ResponseEntity<Semester[]> getSemestersAll(@RequestParam(name="ids") String ids, @RequestParam(name="sessionid") String sessionid)
@@ -80,6 +82,7 @@ public class SemesterController
return new ResponseEntity<>(resultList.toArray(new Semester[0]), HttpStatus.OK);
}
//gibt alle semester zurück
@CrossOrigin
@GetMapping("/semester/all")
public ResponseEntity<Semester[]> getSemester(@RequestParam(name="sessionid") String sessionid)
@@ -122,6 +125,7 @@ public class SemesterController
}
//updatet ein semester
@CrossOrigin
@PutMapping("/semester")
public ResponseEntity<Semester> updateSemester(@RequestBody Semester semester, @RequestParam(name="sessionid") String sessionID)
@@ -142,6 +146,7 @@ public class SemesterController
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//löscht ein semester anhand seiner id
@CrossOrigin
@DeleteMapping("/semester")
public void deleteSemester(@RequestParam(name="sessionid") String sessionid, @RequestParam(name="id") int id)
@@ -9,6 +9,11 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/*
Hier sind einige nutzer funktionen mehr, als für das tool benötigt werden. Diese dienen nur testzwecken
zum verwalten von nutzer z.b. über postman.
*/
@RestController
public class UserController {
//reference to the database handler
@@ -18,6 +23,7 @@ public class UserController {
db = DataBaseHandler.getInstance();
}
//hole alle user, nur erlaubt für admins
@CrossOrigin
@GetMapping("/users/all")
public ResponseEntity<User[]> getAllUsers(@RequestParam(name = "sessionid") String sessionid)
@@ -57,6 +63,7 @@ public class UserController {
return new ResponseEntity<>(sessionID, HttpStatus.OK);
}
//ein nutzer möchte sich ausloggen, damit sollte seinen sessionid entfernt werden.
@CrossOrigin
@GetMapping("/users/logout")
public ResponseEntity<Boolean> logout(@RequestParam(name = "sessionid") String sessionID) {
@@ -64,6 +71,7 @@ public class UserController {
return new ResponseEntity<>(success, HttpStatus.OK);
}
//admins können hier die daten eiens nutzer anfordern.
@CrossOrigin
@GetMapping("/users/data")
public ResponseEntity<User> getUserData(
@@ -141,6 +149,7 @@ public class UserController {
return new ResponseEntity<>(false, HttpStatus.FORBIDDEN);
}
//rechte eines nutzers erhöhen, kann nur von admins ausgeführt werden.
@CrossOrigin
@PutMapping("/users/elevate")
public ResponseEntity<Boolean> elevateUser(
@@ -9,6 +9,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
//alte verworfenen klasse für die funktionalität nicht wichtig
@RestController
public class DayController
{
@@ -1,5 +1,6 @@
package com.example.backend.discard.Days;
//alte verworfene klasse nicht wichtig für die funktionalität
public class Day
{
private int id;
@@ -5,6 +5,8 @@ import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
//hier ein versuch für die übertragung von vertraulichen daten wie nutzername und passwörtern RSA verschlüsselung anzuwenden.
//finde aktuell keine anwendung im projekt.
public class RSA {
private PublicKey publicKey;
@@ -1,3 +1,19 @@
!!!!!!!!!
!!!!!!!!!
hier sieht man eine sammlung alter databasehandler funktionen,
welche nicht benötigt wurden. Von deren Verwendung ist abzuraten,
die Funkionalität dieser bei erneutem einfügen in den Databasehandler
kann nicht gewährleistet werden
!!!!!!!!
!!!!!!!!
!!!!!!!!
/**
* WEEKS
*/
@@ -1,5 +1,6 @@
package com.example.backend.discard.Week;
//alte verworfene klasse, nicht wichtig für die funktionalität
public class Week {
private int id;
@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
import java.sql.SQLException;
//alte verworfene klassen, für die funktionalität des tools nicht wichtig
@RestController
public class WeekController
{
+15
View File
@@ -0,0 +1,15 @@
{
"name": "TIF22A_AnwProjekt_B",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/feiertagejs": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/feiertagejs/-/feiertagejs-1.3.9.tgz",
"integrity": "sha512-tUP+WBv2OWBhPwe3NfqwCtjMq+ym598a42tfqmL0FySswEb9xs96p2iKwqqx+lxKieu1njJBRZKsFm92bJhxZw==",
"engines": {
"node": ">=8.0.0"
}
}
}
}
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Simon Fakir
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+93
View File
@@ -0,0 +1,93 @@
# Feiertage.js
[![npm version](https://badge.fury.io/js/feiertagejs.svg)](https://badge.fury.io/js/feiertagejs)
[![Build Status](https://travis-ci.org/sfakir/feiertagejs.svg?branch=master)](https://travis-ci.org/sfakir/feiertagejs)
Feiertage.js is a small *typescript* npm module without dependencies to calculate German holidays for each Bundesland.
## Installation
- [yarn](https://yarnpkg.com/en/): `yarn add feiertagejs`
- [npm](https://www.npmjs.com/): `npm install feiertagejs`
- [bower](https://bower.io/): `bower install feiertagejs` *outdated!*
- [Plain Javascript](http://extern.fakir.it/feiertagejs/feiertagejs.zip) *outdated!*
## Quick Examples
### ES Modules (Typescript/Javasript)
The prefered whay is to directly import the typescript module. However, you can also use .js.
Please find here some examples and full api [here](docs.md).
```javascript
import { getHolidays, isHoliday, isSpecificHoliday } from 'feiertagejs';
const today = new Date();
console.log(isHoliday(today, 'BW'));
// probably false, because you are working ;)
// check if a day is a specific holiday:
console.log(isSpecificHoliday(today, 'CHRISTIHIMMELFAHRT','ALL'));
// get all holiday for a single year: getHolidays()
// returns an array of "Holiday" Objects. Please see the docs.md for all properties.
const holidays2023 = getHolidays('2023','BUND');
console.log('date', holidays2023[0].date); // = Date("2023-01-01");
console.log('name', holidays2023[0].name); // 'NEUJAHRSTAG' (constant)
console.log('translation', holidays2023[0].trans('de')); // German translation: Neujahrstag
console.log('equals?', holidays2023[0].equals(date)); // Compare days only (ignore time)
```
### Usage in Node.js
```javascript
var feiertagejs = require('feiertagejs');
var today = new Date();
console.log(feiertagejs.isHoliday(today, 'BW'));
// probably false, because you are working ;)
// check if a day is a specific holiday:
console.log(feiertagejs.isSpecificHoliday(today, 'CHRISTIHIMMELFAHRT'));
// get all holiday for a single year: getHolidays()
// returns an array of "Holiday" Objects. Please see the docs.md for all properties.
var holidays2023 = feiertagejs.getHolidays('2023', 'BUND');
console.log('date', holidays2023[0].date); // = Date("2023-01-01");
console.log('name', holidays2023[0].name); // 'NEUJAHRSTAG' (constant)
console.log('translation', holidays2023[0].translate()); // German translation: Neujahrstag
console.log('equals?', holidays2023[0].equals(date)); // Compare days only (ignore time)
```
## API doc
The full API doc can be found [here](docs.md).
## Feedback and Questions
You have two options two give feedback or ask questions:
* Comment the official release [post](https://fakir.tech/de/feiertage-js-deutsche-feiertage-fuer-node-js-und-browser-javascript/)
* Open issues or pullrequests on [github](https://github.com/sfakir/feiertagejs)
## Contributors
Thank you for contributing:
* thetric
* SteveOswald
## Feedback
If you have any questions, feel free to open an issue.
+476
View File
@@ -0,0 +1,476 @@
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
export { addTranslation, getHolidayByDate, getHolidays, getLanguage, isHoliday, isSpecificHoliday, isSunOrHoliday, setLanguage };
//# sourceMappingURL=feiertage.esm.js.map
File diff suppressed because one or more lines are too long
+476
View File
@@ -0,0 +1,476 @@
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
export { addTranslation, getHolidayByDate, getHolidays, getLanguage, isHoliday, isSpecificHoliday, isSunOrHoliday, setLanguage };
//# sourceMappingURL=feiertage.js.map
File diff suppressed because one or more lines are too long
+496
View File
@@ -0,0 +1,496 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () {
var current = global.feiertagejs;
var exports = global.feiertagejs = {};
factory(exports);
exports.noConflict = function () { global.feiertagejs = current; return exports; };
})());
})(this, (function (exports) { 'use strict';
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
exports.addTranslation = addTranslation;
exports.getHolidayByDate = getHolidayByDate;
exports.getHolidays = getHolidays;
exports.getLanguage = getLanguage;
exports.isHoliday = isHoliday;
exports.isSpecificHoliday = isSpecificHoliday;
exports.isSunOrHoliday = isSunOrHoliday;
exports.setLanguage = setLanguage;
}));
//# sourceMappingURL=feiertage.umd.cjs.map
File diff suppressed because one or more lines are too long
+496
View File
@@ -0,0 +1,496 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () {
var current = global.feiertagejs;
var exports = global.feiertagejs = {};
factory(exports);
exports.noConflict = function () { global.feiertagejs = current; return exports; };
})());
})(this, (function (exports) { 'use strict';
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
exports.addTranslation = addTranslation;
exports.getHolidayByDate = getHolidayByDate;
exports.getHolidays = getHolidays;
exports.getLanguage = getLanguage;
exports.isHoliday = isHoliday;
exports.isSpecificHoliday = isSpecificHoliday;
exports.isSunOrHoliday = isSunOrHoliday;
exports.setLanguage = setLanguage;
}));
//# sourceMappingURL=feiertage.umd.js.map
File diff suppressed because one or more lines are too long
+144
View File
@@ -0,0 +1,144 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
### Table of Contents
*Types*
- [HolidayType](#holidaytype)
- [Region](#region)
- [Holiday](#holiday)
- [allHolidays](#allholidays)
- [allRegions](#allregions)
- [TranslationTable](#translationtable)
*API*
- [isHoliday(date, region)](#isholiday)
- [getHolidayByDate(date, region)](#getholidaybydate)
- [getHolidays(year, region)](#getholidays)
- [isSunOrHoliday(date, region)](#issunorholiday)
- [isSpecificHoliday(date, name, region)](#isspecificholiday)
- [addTranslation(isoCode, translation)](#addtranslation)
- [setLanguage(lng)](#setlanguage)
- [getLanguage()](#getlanguage)
## Types
### HolidayType
Type: (`"NEUJAHRSTAG"` \| `"HEILIGEDREIKOENIGE"` \| `"KARFREITAG"` \| `"OSTERSONNTAG"` \| `"OSTERMONTAG"` \| `"TAG_DER_ARBEIT"` \| `"CHRISTIHIMMELFAHRT"` \| `"MARIAHIMMELFAHRT"` \| `"PFINGSTSONNTAG"` \| `"PFINGSTMONTAG"` \| `"FRONLEICHNAM"` \| `"DEUTSCHEEINHEIT"` \| `"REFORMATIONSTAG"` \| `"ALLERHEILIGEN"` \| `"BUBETAG"` \| `"ERSTERWEIHNACHTSFEIERTAG"` \| `"ZWEITERWEIHNACHTSFEIERTAG"` \| `"WELTKINDERTAG"` \| `"WELTFRAUENTAG"` \| `"AUGSBURGER_FRIEDENSFEST"`)
### Region
Type: (`"BW"` \| `"BY"` \| `"BE"` \| `"BB"` \| `"HB"` \| `"HE"` \| `"HH"` \| `"MV"` \| `"NI"` \| `"NW"` \| `"RP"` \| `"SL"` \| `"SN"` \| `"ST"` \| `"SH"` \| `"TH"` \| `"BUND"` \| `"ALL"`)
As defined here: https://de.wikipedia.org/wiki/Land_(Deutschland)#Amtliche_bzw._Eigenbezeichnungen
The difference between BUND and ALL is defined as follows:
* "ALL" refers to every holiday which is valid in **at least** one region. So a holiday that only applies to one state will be included.
* "BUND" refers to holidays that are valid in every region ("bundesweit"). So a holiday that only applies to one state will not be included.
### Holiday
Type: {name: [HolidayType](#holidaytype), date: [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date), trans: function (lang: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?): [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), dateString: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), equals: function (date: [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)): [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)}
**Properties**
- `name` **[HolidayType](#holidaytype)**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `trans` **function (lang: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?): [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `dateString` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `equals` **function (date: [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)): [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### allHolidays
Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[HolidayType](#holidaytype)>
### allRegions
Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[Region](#region)>
### TranslationTable
Map of [HolidayType](#holidaytype) to translation string.
Type: {}
## API
### addTranslation()
Adds a translation for the holidays (e.g. English).
This also allows overriding the German names.
Hint: Interpolates German for missing translations
**Parameters**
- `isoCode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** of the new language
- `newTranslation` **[TranslationTable](#translationtable)** map of {HolidayType} to translation stringg
### setLanguage()
Set a language to default language
**Parameters**
- `isoCode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
### getLanguage()
Get currently set language
Returns **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
### isSunOrHoliday()
Checks if a specific date is sunday or holiday.
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `region` **[Region](#region)**
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### isHoliday()
Check is specific date is holiday.
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `region` **[Region](#region)** two character [Region](#region) code
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### getHolidayByDate()
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `region` **[Region](#region)** (optional, default `'ALL'`)
Returns **([Holiday](#holiday) | void)**
### isSpecificHoliday()
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `holidayName` **[HolidayType](#holidaytype)**
- `region` **[Region](#region)** (optional, default `'ALL'`)
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### getHolidays()
Returns all holidays of a year in a [Region](#region).
**Parameters**
- `year` **([number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))**
- `region` **[Region](#region)**
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[Holiday](#holiday)>**
+113
View File
@@ -0,0 +1,113 @@
declare type Region =
| 'BW' // Baden-Württemberg
| 'BY' // Bayern
| 'BE' // Berlin
| 'BB' // Brandenburg
| 'HB' // Bremen
| 'HE' // Hessen
| 'HH' // Hamburg
| 'MV' // Mecklenburg-Vorpommern
| 'NI' // Niedersachsen
| 'NW' // Nordrhein-Westfalen
| 'RP' // Rheinland-Pfalz
| 'SL' // Saarland
| 'SN' // Sachsen
| 'ST' // Sachsen-Anhalt
| 'SH' // Schleswig-Holstein
| 'TH' // Thüringen
| 'BUND' // Gesamt-Deutschland
| 'AUGSBURG'
| 'ALL';
declare type Holiday = {
name: HolidayType;
date: Date;
trans?: (lang: string | undefined) => string; // deprecated;
translate: (lang?: string | undefined) => string;
dateString: string;
equals: (date: Date) => boolean;
};
declare type HolidayType =
| 'NEUJAHRSTAG'
| 'HEILIGEDREIKOENIGE'
| 'KARFREITAG'
| 'OSTERSONNTAG'
| 'OSTERMONTAG'
| 'TAG_DER_ARBEIT'
| 'CHRISTIHIMMELFAHRT'
| 'MARIAHIMMELFAHRT'
| 'PFINGSTSONNTAG'
| 'PFINGSTMONTAG'
| 'FRONLEICHNAM'
| 'DEUTSCHEEINHEIT'
| 'REFORMATIONSTAG'
| 'ALLERHEILIGEN'
| 'BUBETAG'
| 'ERSTERWEIHNACHTSFEIERTAG'
| 'ZWEITERWEIHNACHTSFEIERTAG';
/**
* Map of {@link HolidayType} to translation string.
*/
export type TranslationTable = {
[key: string]: string;
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
declare function addTranslation(
isoCode: string,
newTranslation: TranslationTable,
): void;
/**
* Set a language to default language
* @param {string} isoCode
*/
declare function setLanguage(isoCode: string): void;
/**
* Get currently set language
* @returns {string}
*/
declare function getLanguage(): string;
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
declare function isSunOrHoliday(date: Date, region: Region): boolean;
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
declare function isHoliday(date: Date, region: Region): boolean;
declare function getHolidayByDate(date: Date, region: Region): Holiday | void;
declare function isSpecificHoliday(
date: Date,
holidayName: HolidayType,
region: Region,
): boolean;
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
declare function getHolidays(year: number | string, region: Region): Holiday[];
+53
View File
@@ -0,0 +1,53 @@
{
"name": "feiertagejs",
"version": "1.3.9",
"description": "A module to calculate German holidays made for node.js",
"type": "module",
"main": "build/feiertage.umd.cjs",
"module": "build/feiertage.js",
"types": "index.d.ts",
"scripts": {
"test": "vitest run --coverage",
"test:w": "vitest watch",
"format": "prettier --write \"{**/*,*}.{ts,json}\" \"!coverage/**\" \"!build/**\" \"!package.json\" \"!package-lock.json\" --cache",
"lint": "eslint \"src\" \"spec\"",
"build": "rollup -c"
},
"repository": {
"type": "git",
"url": "https://github.com/sfakir/feiertagejs"
},
"keywords": [
"node",
"holidays",
"feiertage",
"javascript"
],
"engines": {
"node": ">=8.0.0"
},
"author": "Simon Fakir",
"license": "MIT",
"bugs": {
"url": "https://github.com/sfakir/feiertagejs/issues"
},
"homepage": "https://github.com/sfakir/feiertagejs",
"devDependencies": {
"@vitest/coverage-c8": "^0.26.2",
"prettier": "^2.8.1",
"rollup": "^3.9.0",
"@rollup/plugin-typescript": "^10.0.1",
"typescript": "^4.9.4",
"vitest": "^0.26.2",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0"
},
"files": [
"build",
"docs.md",
"Readme.md",
"index.d.ts"
]
}
+20
View File
@@ -0,0 +1,20 @@
{
"name": "TIF22A_AnwProjekt_B",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"feiertagejs": "^1.3.9"
}
},
"node_modules/feiertagejs": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/feiertagejs/-/feiertagejs-1.3.9.tgz",
"integrity": "sha512-tUP+WBv2OWBhPwe3NfqwCtjMq+ym598a42tfqmL0FySswEb9xs96p2iKwqqx+lxKieu1njJBRZKsFm92bJhxZw==",
"engines": {
"node": ">=8.0.0"
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"dependencies": {
"feiertagejs": "^1.3.9"
}
}