This commit is contained in:
Ipmake 2024-03-11 18:10:10 +01:00
parent 7bc638bf8c
commit 57a1a0105f
10 changed files with 340 additions and 31 deletions

View File

@ -13,6 +13,7 @@
"chalk": "^4.0.0",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"moment": "^2.30.1",
"prisma": "^5.3.1"
},
"devDependencies": {
@ -569,6 +570,14 @@
"node": ">= 0.6"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",

View File

@ -14,6 +14,7 @@
"chalk": "^4.0.0",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"moment": "^2.30.1",
"prisma": "^5.3.1"
},
"devDependencies": {

View File

@ -20,6 +20,6 @@ model Mitarbeiter {
ID String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
Vorname String
Nachname String
Anstelldatum DateTime @db.Date
Geburtstag DateTime @db.Date
Anstelldatum DateTime? @db.Date
Geburtstag DateTime? @db.Date
}

View File

@ -10,6 +10,7 @@ export function errorBuilder(type: string, message: string): Types.ErrorResponse
const Errors = {
MISSING_ITEMS: errorBuilder("missing_items", "Die Anfrage ist Fehlerhaft."),
INVALID_ITEMS: errorBuilder("invalid_items", "Die Anfrage ist Fehlerhaft."),
INVALID_CREDENTIALS: errorBuilder("invalid_credentials", "Die eingegebenen Anmeldedaten sind inkorrekt!"),
NOT_FOUND: errorBuilder("not_found", "Die angeforderte Ressource wurde nicht gefunden!"),
}
@ -25,3 +26,8 @@ export async function authorize(token: string) {
if (!user) return false
return user
}
export function getFormatNumber(number: number, digits: number): string {
// format the number with the digits. so if the digits is 2 and the number is 9 return 09
return number.toString().padStart(digits, '0')
}

View File

@ -2,9 +2,10 @@ import { PrismaClient } from '@prisma/client'
import express from 'express'
import dotenv from 'dotenv'
import init from './init'
import Errors, { authorize } from './functions'
import Errors, { authorize, getFormatNumber } from './functions'
import fs from 'fs'
import crypto from 'crypto'
import moment from 'moment'
dotenv.config()
@ -210,6 +211,144 @@ app.delete('/api/users/delete/:id', async (req, res) => {
app.get('/api/toshow/:targetDate?', async (req, res) => {
const { targetDate } = req.params;
if(targetDate && targetDate.length !== 10) return res.status(400).send(Errors.INVALID_ITEMS)
const token = req.headers.authorization?.split(' ')[1]
if (!token) return res.status(401).send(Errors.INVALID_CREDENTIALS)
const user = await authorize(token)
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
let dates: Types.Mitarbeiter[] = await prisma.mitarbeiter.findMany({})
let currDate;
if(targetDate) currDate = moment(targetDate, "YYYY-MM-DD");
else currDate = moment();
for (let i in dates) {
let validity = false;
// `${currDate.getFullYear()}-${getFormatNumber(date.getMonth(), 2)}-${getFormatNumber(date.getDay(), 2)}`
if (dates[i].Anstelldatum) {
const date = dates[i].Anstelldatum;
const dateWithoutYear = moment(date).format("MM-DD");
if (
date &&
(
(
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD") <= currDate
)
||
(
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD").subtract(1, "year") <= currDate
)
)
) {
validity = true;
}
}
if (dates[i].Geburtstag) {
const date = dates[i].Geburtstag;
const dateWithoutYear = moment(date).format("MM-DD");
if (
date &&
(
(
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD") <= currDate
)
||
(
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD").subtract(1, "year") <= currDate
)
)
) {
validity = true;
}
}
if (!validity) delete dates[i];
}
dates = dates.filter((date) => date !== null);
for(let i = 14; i >= 1; i--) {
console.log(i);
const date = moment(currDate).subtract(i, "days")
const dayOfWeek = date.format("dddd");
if(["Saturday", "Sunday"].includes(dayOfWeek)) continue;
for(let j in dates) {
let validity = false;
if (dates[j].Anstelldatum) {
const dateWithoutYear = moment(dates[j].Anstelldatum, "YYYY-MM-DD").format("MM-DD");
if (
date &&
(
(
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD") <= moment(currDate).subtract(i, "days")
)
||
(
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD").subtract(1, "year") <= moment(currDate).subtract(i, "days")
)
)
) {
validity = true;
}
}
if (dates[j].Geburtstag) {
const dateWithoutYear = moment(dates[j].Geburtstag, "YYYY-MM-DD").format("MM-DD");
if (
date &&
(
(
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD") <= moment(currDate).subtract(i, "days")
)
||
(
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
moment(dateWithoutYear,"MM-DD").subtract(1, "year") <= moment(currDate).subtract(i, "days")
)
)
) {
validity = true;
}
}
console.log(date);
console.log(date.format("dddd"), dates[j].Vorname, dates[j].Nachname, validity);
if (validity) delete dates[j];
}
dates = dates.filter((date) => date !== null);
}
res.send(dates)
})
app.listen(process.env.PORT, () => {
console.log(`Server is running on port ${process.env.PORT}`)
})

View File

@ -4,4 +4,12 @@ declare namespace Types {
type: string
message: string
}
interface Mitarbeiter {
ID: string;
Vorname: string;
Nachname: string;
Anstelldatum: Date | null;
Geburtstag: Date | null;
}
}

View File

@ -0,0 +1,25 @@
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { getBaseURL } from '../functions';
const CompareDate = () => {
axios
.get(`${getBaseURL()}/api/workers`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
return (
<div>
<h1>Compare Date</h1>
</div>
);
};
export default CompareDate;

View File

@ -1,10 +1,27 @@
import { Avatar, Box, Stack, Typography } from "@mui/material";
import { Box, Typography } from "@mui/material";
import { useEffect, useState } from "react";
import PhilSwift from "../components/PhilSwift";
import axios from "axios";
import { getBaseURL } from "../functions";
import CompareDate from "../components/CompareDate";
function LandingPage() {
const [isHalloween, setIsHalloween] = useState(false);
useEffect(() => {
const currentDate = new Date();
const halloweenDate = new Date("2024-03-04");
setIsHalloween(
currentDate.getMonth() === halloweenDate.getMonth() &&
currentDate.getDate() === halloweenDate.getDate()
);
}, []);
return (
<>
<Box sx={{
<Box
sx={{
width: "100%",
height: "100vh",
position: "absolute",
@ -13,9 +30,39 @@ function LandingPage() {
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}>
}}
>
<PhilSwift />
</Box>
<Box
sx={{
display: "center",
width: "100%",
height: "100vh",
top: 0,
left: 0,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
zIndex: 10,
}}
>
<Typography
sx={{
fontSize: "2rem",
color: "red",
textAlign: "center",
fontWeight: "bold",
textShadow: "2px 2px 4px #000000",
zIndex: 10,
}}
>
{isHalloween
? "Happy Halloween"
: "Keine Geburtstage oder Jubiläen heute."}
</Typography>
</Box>
</>
);
}

View File

@ -1,13 +1,18 @@
import React, { useState, ChangeEvent, FormEvent } from "react";
import Alert from "@mui/material/Alert";
import { Box, Button, Typography } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import moment from "moment";
function Import() {
let correct = 0;
let incorrect = 0;
const [file, setFile] = useState<File | null>(null);
const [csvData, setCsvData] = useState<
Array<{ [key: string]: string } | null>
>([]);
const [correctCount, setCorrectCount] = useState(0);
const [incorrectCount, setIncorrectCount] = useState(0);
const fileReader = new FileReader();
@ -37,6 +42,25 @@ function Import() {
.filter(Boolean);
setCsvData(newArray);
newArray.forEach((row) => {
let isValid = true;
for (const key in row) {
if (!key.includes("name") && row[key]) {
if (!moment(row[key], "DD.MM.YYYY", false).isValid()) {
isValid = false;
break;
}
}
}
if (isValid) {
correct++;
} else {
incorrect++;
}
});
setCorrectCount(correct);
setIncorrectCount(incorrect);
};
const handleOnSubmit = (e: FormEvent) => {
@ -70,8 +94,31 @@ function Import() {
{csvData.length > 0 ? (
<div>
<Typography variant="h4">Fehlerhafte Daten</Typography>
<Alert variant="filled" severity="error" sx={{textAlign:"center"}}>
{incorrectCount} von {correctCount + incorrectCount} Datensätze
enthalten fehlerhafte Daten und wurden nicht importiert.Üperprüfen Sie die Daten und korrigieren Sie die Fehler.
</Alert>
<DataGrid
rows={csvData.map((row, index) => ({ id: index, ...row }))}
rows={(csvData || [])
.map((row, index) => ({ id: index, ...row }))
.filter((row: { [key: string]: any }) => {
for (const key in row) {
if (row.hasOwnProperty(key)) {
const value = row[key];
if (
!key.includes("name") &&
value &&
value.length > 0 &&
!moment(value, "DD.MM.YYYY", false).isValid()
) {
return true;
}
}
}
correct++;
return false;
})}
columns={
csvData.length > 0
? Object.keys(csvData[0] || {}).map(
@ -79,7 +126,7 @@ function Import() {
({
field: header,
headerName: header.replace(/"/g, ""),
width: 150,
width: 250,
editable: true,
valueFormatter: (params) => {
if (params.value) {
@ -88,14 +135,20 @@ function Import() {
params.value,
"DD.MM.YYYY",
false
).isValid() && !header.includes("name")
).isValid()
) {
return params.value;
}
return `Falsches Datum: ${params.value}`;
if (
!header.includes("name") &&
params.value.length > 0
) {
incorrect++;
return `Error: ${params.value}`;
}
correct++;
return params.value;
}
return "";
},
} as GridColDef)
)
@ -106,6 +159,14 @@ function Import() {
) : (
<p>Keine Daten zum anzeigen</p>
)}
<Button
sx={{
marginTop: 2,
}}
variant="contained"
>
Daten einspielen
</Button>
</Box>
);
}

View File

@ -1,9 +1,22 @@
import React from "react";
import { Typography } from "@mui/material";
import axios from "axios";
import Calendar from "react-calendar";
function Kalender() {
return (
axios.get('https://feiertage-api.de/api/')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
}),
<div className="container">
<Typography variant="h4" style={{ margin: "20px 0" }}>
Kalender
</Typography>
<Calendar/>
</div>
);