Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb2ddc7bcf | ||
|
|
68e2d553f9 | ||
|
|
86f9e559b5 | ||
|
|
65a399693e | ||
|
|
3382d732a9 | ||
|
|
7b6a82c073 | ||
|
|
d80abcaf8c | ||
|
|
17a3ad0b33 | ||
|
|
be9ace5238 | ||
|
|
fcdf8492a6 | ||
|
|
d4d01c730a | ||
|
|
a4c600301e | ||
|
|
4ec1cb0749 | ||
|
|
20e2351ba9 | ||
|
|
4f45d48061 | ||
|
|
ee5805434d | ||
|
|
024d22711f | ||
|
|
9315f5b18d | ||
|
|
34c2786840 | ||
|
|
ca23f7f993 | ||
|
|
d81922d188 | ||
|
|
c979c3a801 | ||
|
|
0a3a390bb8 | ||
|
|
09f288532e | ||
|
|
137684f5be | ||
|
|
a0841f4b2b | ||
|
|
571e6e72c0 | ||
|
|
ac4b62f32c | ||
|
|
8dc16c5b2c |
@@ -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>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JpaBuddyIdeaProjectConfig">
|
||||
<option name="renamerInitialized" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"git-widget-placeholder": "main",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"last_opened_file_path": "C:/Users/afist/WebstormProjects/SideBarCalendarTest",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"ts.external.directory.path": "C:\\Users\\afist\\AppData\\Local\\JetBrains\\Toolbox\\apps\\WebStorm\\ch-0\\231.8770.64\\plugins\\javascript-impl\\jsLanguageServicesImpl\\external",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</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>
|
||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 8.4 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
@@ -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.
|
||||
@@ -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
|
||||
@@ -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",
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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={{
|
||||
@@ -566,13 +703,13 @@ export default function CalenderView(p) {
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<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}/>
|
||||
|
||||
@@ -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"
|
||||
@@ -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,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!",
|
||||
|
||||
@@ -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>`
|
||||
|
||||
@@ -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 => {
|
||||
//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)
|
||||
|
||||
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"))
|
||||
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(() => {
|
||||
readModules()
|
||||
update = true
|
||||
}).catch(() => readModules())
|
||||
}, 100)
|
||||
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)
|
||||
|
||||
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()))
|
||||
|
||||
tempSemesterNumber = semester.number
|
||||
setSemesterNumber(semester.number)
|
||||
|
||||
arr = []
|
||||
modulesDummy[semester.number].map(e => {
|
||||
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
|
||||
})
|
||||
|
||||
}).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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setModuleUserMapping(arr)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
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])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function onCourseNameChange(e) {
|
||||
setCourseName(e.target.value)
|
||||
}
|
||||
|
||||
function onStartDateChange(e) {
|
||||
setStartDate(e.target.value)
|
||||
}
|
||||
|
||||
function onEndDateChange(e) {
|
||||
setEndDate(e.target.value)
|
||||
}
|
||||
|
||||
function onSemesterNumberChange(e) {
|
||||
setSemesterNumber(e.target.value)
|
||||
setModulesSelectorValues(modulesDummy[e.target.value])
|
||||
}
|
||||
|
||||
function isOptionSelected(e, userid) {
|
||||
let found = false;
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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": tempDateStart.getFullYear(),
|
||||
"endyear": tempDateEnd.getFullYear(),
|
||||
"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: update ? "PUT" : "POST",
|
||||
method: "PUT",
|
||||
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
|
||||
body: JSON.stringify({
|
||||
"id": semesterid,
|
||||
"startday": startDayInYear,
|
||||
"endday": endDayInYear,
|
||||
"name": courseName,
|
||||
"startyear": startYear,
|
||||
"endyear": endYear,
|
||||
"number": semesterNumber
|
||||
})
|
||||
}).then(() => modulesInBackend(semesterid))
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid") + "&id=" + baseMapping[i].id, {
|
||||
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 {
|
||||
|
||||
//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>
|
||||
</>
|
||||
|
||||
@@ -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
|
||||
}}/>
|
||||
|
||||
@@ -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 + "%"
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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 });
|
||||
|
||||
@@ -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"}/>
|
||||
|
||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 19 KiB |
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# Feiertage.js
|
||||
|
||||
[](https://badge.fury.io/js/feiertagejs)
|
||||
[](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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)<[HolidayType](#holidaytype)>
|
||||
|
||||
### allRegions
|
||||
|
||||
Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[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)<[Holiday](#holiday)>**
|
||||
@@ -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[];
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"feiertagejs": "^1.3.9"
|
||||
}
|
||||
}
|
||||