diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma
index 479962b..b61a2c5 100644
--- a/backend/prisma/schema.prisma
+++ b/backend/prisma/schema.prisma
@@ -9,14 +9,14 @@ datasource db {
extensions = [uuid_ossp(map: "uuid-ossp")]
}
-model users {
- ID String @id @default(dbgenerated("uuid_generate_v1()")) @db.Uuid
+model Users {
+ ID String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
username String
password String @db.VarChar(128)
token String @db.VarChar(128)
}
-model Mitarbeiter {
+model Employees {
ID String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
Vorname String
Nachname String
diff --git a/backend/src/index.ts b/backend/src/index.ts
index 6179324..224d421 100644
--- a/backend/src/index.ts
+++ b/backend/src/index.ts
@@ -62,7 +62,7 @@ app.get('/api/auth/verify', async (req, res) => {
res.send('OK')
})
-app.post("/api/worker/create", async (req, res) => {
+app.put("/api/employees", async (req, res) => {
const token = req.headers.authorization?.split(' ')[1]
if (!token) return res.status(401).send(Errors.INVALID_CREDENTIALS)
@@ -70,13 +70,43 @@ app.post("/api/worker/create", async (req, res) => {
const user = await authorize(token)
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
- const { title, content, image, sponsors } = req.body
- if (!title || !content || !image) return res.status(400).send(Errors.MISSING_ITEMS)
+ if (!Array.isArray(req.body)) return res.status(400).send(Errors.INVALID_ITEMS)
- // sponsors is an array of sponsor IDs
+ const employees: {
+ ID: string;
+ Vorname: string;
+ Nachname: string;
+ Geburtstag?: number | Date;
+ Anstelldatum?: number | Date;
+ }[] = req.body;
+
+ for (let i in employees) {
+ if (
+ !employees[i].Vorname
+ || !employees[i].Nachname
+ || employees[i].ID
+ ) return res.status(400).send(Errors.MISSING_ITEMS)
+
+ if (employees[i].Geburtstag && typeof employees[i].Geburtstag !== 'number') return res.status(400).send(Errors.INVALID_ITEMS)
+ if (employees[i].Anstelldatum && typeof employees[i].Anstelldatum !== 'number') return res.status(400).send(Errors.INVALID_ITEMS)
+
+ if (employees[i].Geburtstag && typeof employees[i].Geburtstag === 'number') employees[i].Geburtstag = new Date(employees[i].Geburtstag as number)
+ if (employees[i].Anstelldatum && typeof employees[i].Anstelldatum === 'number') employees[i].Anstelldatum = new Date(employees[i].Anstelldatum as number)
+ }
+
+ const newEmployees = await prisma.employees.createMany({
+ data: employees as {
+ Vorname: string;
+ Nachname: string;
+ Geburtstag?: Date;
+ Anstelldatum?: Date;
+ }[]
+ })
+
+ res.send(newEmployees)
})
-app.get('/api/workers', async (req, res) => {
+app.patch("/api/employees/:id", async (req, res) => {
const token = req.headers.authorization?.split(' ')[1]
if (!token) return res.status(401).send(Errors.INVALID_CREDENTIALS)
@@ -84,18 +114,128 @@ app.get('/api/workers', async (req, res) => {
const user = await authorize(token)
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
- const workers = await prisma.mitarbeiter.findMany({
+ let { Vorname, Nachname, Geburtstag, Anstelldatum } = req.body as {
+ Vorname: string;
+ Nachname: string;
+ Geburtstag?: number | Date;
+ Anstelldatum?: number | Date;
+ }
+ if (!Vorname || !Nachname) return res.status(400).send(Errors.MISSING_ITEMS)
+
+
+ if (Geburtstag && typeof Geburtstag !== 'number') return res.status(400).send(Errors.INVALID_ITEMS)
+ if (Anstelldatum && typeof Anstelldatum !== 'number') return res.status(400).send(Errors.INVALID_ITEMS)
+
+ if (Geburtstag && typeof Geburtstag === 'number') Geburtstag = new Date(Geburtstag)
+ if (Anstelldatum && typeof Anstelldatum === 'number') Anstelldatum = new Date(Anstelldatum)
+
+ const updatedEmployee = await prisma.employees.update({
+ where: {
+ ID: req.params.id
+ },
+ data: {
+ Vorname,
+ Nachname,
+ Geburtstag: (Geburtstag as Date | undefined),
+ Anstelldatum: (Anstelldatum as Date | undefined)
+ }
+ })
+
+ res.send(updatedEmployee)
+})
+
+app.patch("/api/employees/", async (req, res) => {
+ 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)
+
+ if (!Array.isArray(req.body)) return res.status(400).send(Errors.INVALID_ITEMS)
+
+ const employees: {
+ ID: string;
+ Vorname: string;
+ Nachname: string;
+ Geburtstag?: number | Date;
+ Anstelldatum?: number | Date;
+ }[] = req.body;
+
+ for (let i in employees) {
+ if (
+ !employees[i].Vorname
+ || !employees[i].Nachname
+ || !employees[i].ID
+ ) return res.status(400).send(Errors.MISSING_ITEMS)
+
+ if (employees[i].Geburtstag && typeof employees[i].Geburtstag !== 'number') return res.status(400).send(Errors.INVALID_ITEMS)
+ if (employees[i].Anstelldatum && typeof employees[i].Anstelldatum !== 'number') return res.status(400).send(Errors.INVALID_ITEMS)
+
+ if (employees[i].Geburtstag && typeof employees[i].Geburtstag === 'number') employees[i].Geburtstag = new Date(employees[i].Geburtstag as number)
+ if (employees[i].Anstelldatum && typeof employees[i].Anstelldatum === 'number') employees[i].Anstelldatum = new Date(employees[i].Anstelldatum as number)
+ }
+
+ const updatedEmployees = await Promise.all(employees.map(employee =>
+ prisma.employees.update({
+ where: { ID: employee.ID },
+ data: {
+ Vorname: employee.Vorname,
+ Nachname: employee.Nachname,
+ Geburtstag: employee.Geburtstag as Date | undefined,
+ Anstelldatum: employee.Anstelldatum as Date | undefined
+ }
+ })
+ ))
+
+ res.send(updatedEmployees)
+})
+
+app.get('/api/employees', async (req, res) => {
+ 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)
+
+ const workers = await prisma.employees.findMany({
select: {
+ ID: true,
Vorname: true,
Nachname: true,
Geburtstag: true,
Anstelldatum: true,
+ },
+ orderBy: {
+ Nachname: 'asc'
}
})
res.send(workers)
})
+app.delete('/api/employees/:employees', async (req, res) => {
+ 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)
+
+ const employees: string[] = req.params.employees.split(',')
+
+ await prisma.employees.deleteMany({
+ where: {
+ ID: {
+ in: employees
+ }
+ }
+ })
+
+ res.send('OK')
+})
+
app.get('/api/users', async (req, res) => {
const token = req.headers.authorization?.split(' ')[1]
@@ -172,8 +312,8 @@ app.patch('/api/users/edit/:id', async (req, res) => {
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
- const { username, password, admin, article_create, article_manage, sponsor_manage, user_manage } = req.body
- if (!username || admin === undefined || article_create === undefined || article_manage === undefined || sponsor_manage === undefined || user_manage === undefined) return res.status(400).send(Errors.MISSING_ITEMS)
+ const { username, password } = req.body
+ if (!username) return res.status(400).send(Errors.MISSING_ITEMS)
const newUser = await prisma.users.update({
where: {
@@ -181,11 +321,6 @@ app.patch('/api/users/edit/:id', async (req, res) => {
},
data: {
username,
- admin,
- article_create,
- article_manage,
- sponsor_manage,
- user_manage,
...(password && { password })
}
})
@@ -211,65 +346,56 @@ 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 (targetDate && targetDate.length !== 10) return res.status(400).send(Errors.INVALID_ITEMS)
- if (!token) return res.status(401).send(Errors.INVALID_CREDENTIALS)
+ let dates: Types.EmployeeEvent[] = await prisma.employees.findMany({})
- 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");
+ 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 &&
+ date &&
(
(
- moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
- moment(dateWithoutYear,"MM-DD") <= currDate
- )
+ 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
+ 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 &&
+ date &&
(
(
- moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
- moment(dateWithoutYear,"MM-DD") <= currDate
- )
+ 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
+ moment(dateWithoutYear, "MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
+ moment(dateWithoutYear, "MM-DD").subtract(1, "year") <= currDate
)
)
) {
@@ -277,36 +403,36 @@ app.get('/api/toshow/:targetDate?', async (req, res) => {
}
}
-
+
if (!validity) delete dates[i];
}
dates = dates.filter((date) => date !== null);
-
- for(let i = 14; i >= 1; i--) {
+
+ 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;
+ if (["Saturday", "Sunday"].includes(dayOfWeek)) continue;
- for(let j in dates) {
+ 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 &&
+ date &&
(
(
- moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
- moment(dateWithoutYear,"MM-DD") <= moment(currDate).subtract(i, "days")
- )
+ 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")
+ moment(dateWithoutYear, "MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
+ moment(dateWithoutYear, "MM-DD").subtract(1, "year") <= moment(currDate).subtract(i, "days")
)
)
) {
@@ -318,16 +444,16 @@ app.get('/api/toshow/:targetDate?', async (req, res) => {
const dateWithoutYear = moment(dates[j].Geburtstag, "YYYY-MM-DD").format("MM-DD");
if (
- date &&
+ date &&
(
(
- moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
- moment(dateWithoutYear,"MM-DD") <= moment(currDate).subtract(i, "days")
- )
+ 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")
+ moment(dateWithoutYear, "MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
+ moment(dateWithoutYear, "MM-DD").subtract(1, "year") <= moment(currDate).subtract(i, "days")
)
)
) {
@@ -337,9 +463,26 @@ app.get('/api/toshow/:targetDate?', async (req, res) => {
console.log(date);
- console.log(date.format("dddd"), dates[j].Vorname, dates[j].Nachname, validity);
- if (validity) delete dates[j];
+ if (validity) {
+ delete dates[j];
+ continue;
+ }
+
+ // get the EventType depending on whats closer to the current date
+ const dateWithoutYear = moment(dates[j].Anstelldatum, "YYYY-MM-DD").format("MM-DD");
+ const dateWithoutYear2 = moment(dates[j].Geburtstag, "YYYY-MM-DD").format("MM-DD");
+
+ if (dates[j].Anstelldatum && !dates[j].Geburtstag) dates[j].EventType = "Jubiläum";
+ else if (dates[j].Geburtstag && !dates[j].Anstelldatum) dates[j].EventType = "Geburtstag";
+ else if (
+ Math.abs(moment(dateWithoutYear, "MM-DD").diff(moment(currDate), "days")) <=
+ Math.abs(moment(dateWithoutYear2, "MM-DD").diff(moment(currDate), "days"))
+ ) dates[j].EventType = "Jubiläum"
+ else dates[j].EventType = "Geburtstag"
+
+
+ console.log(date.format("dddd"), dates[j].Vorname, dates[j].Nachname, validity, dates[j].EventType);
}
dates = dates.filter((date) => date !== null);
}
diff --git a/backend/src/types.d.ts b/backend/src/types.d.ts
index 5dcba8c..08d210d 100644
--- a/backend/src/types.d.ts
+++ b/backend/src/types.d.ts
@@ -5,11 +5,15 @@ declare namespace Types {
message: string
}
- interface Mitarbeiter {
+ interface Employees {
ID: string;
Vorname: string;
Nachname: string;
Anstelldatum: Date | null;
Geburtstag: Date | null;
}
+
+ interface EmployeeEvent extends Employees {
+ EventType?: "Geburtstag" | "Jubiläum";
+ }
}
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 73b848d..cf4fc3f 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -16,12 +16,14 @@
"@mui/lab": "^5.0.0-alpha.154",
"@mui/material": "^5.14.10",
"@mui/x-data-grid": "^6.19.1",
+ "@mui/x-date-pickers": "^6.19.6",
"@types/node": "^16.18.52",
"@types/react": "^18.2.22",
"@types/react-dom": "^18.2.7",
"axios": "^1.5.1",
"js-sha256": "^0.10.1",
"moment": "^2.29.4",
+ "papaparse": "^5.4.1",
"react": "^18.2.0",
"react-calendar": "^4.8.0",
"react-dom": "^18.2.0",
@@ -32,6 +34,9 @@
"suneditor-react": "^3.6.1",
"typescript": "^4.9.5",
"zustand": "^4.4.4"
+ },
+ "devDependencies": {
+ "@types/papaparse": "^5.3.14"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -1951,9 +1956,9 @@
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
},
"node_modules/@babel/runtime": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz",
- "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz",
+ "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -2528,28 +2533,28 @@
}
},
"node_modules/@floating-ui/core": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz",
- "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz",
+ "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==",
"dependencies": {
- "@floating-ui/utils": "^0.1.3"
+ "@floating-ui/utils": "^0.2.1"
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz",
- "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==",
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz",
+ "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==",
"dependencies": {
- "@floating-ui/core": "^1.4.2",
- "@floating-ui/utils": "^0.1.3"
+ "@floating-ui/core": "^1.0.0",
+ "@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/react-dom": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz",
- "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==",
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz",
+ "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==",
"dependencies": {
- "@floating-ui/dom": "^1.5.1"
+ "@floating-ui/dom": "^1.6.1"
},
"peerDependencies": {
"react": ">=16.8.0",
@@ -2557,9 +2562,9 @@
}
},
"node_modules/@floating-ui/utils": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.4.tgz",
- "integrity": "sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA=="
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
+ "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
},
"node_modules/@fontsource-variable/lexend": {
"version": "5.0.12",
@@ -3603,9 +3608,9 @@
}
},
"node_modules/@mui/types": {
- "version": "7.2.10",
- "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz",
- "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==",
+ "version": "7.2.13",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz",
+ "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==",
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0"
},
@@ -3616,11 +3621,11 @@
}
},
"node_modules/@mui/utils": {
- "version": "5.14.19",
- "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.19.tgz",
- "integrity": "sha512-qAHvTXzk7basbyqPvhgWqN6JbmI2wLB/mf97GkSlz5c76MiKYV6Ffjvw9BjKZQ1YRb8rDX9kgdjRezOcoB91oQ==",
+ "version": "5.15.12",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.12.tgz",
+ "integrity": "sha512-8SDGCnO2DY9Yy+5bGzu00NZowSDtuyHP4H8gunhHGQoIlhlY2Z3w64wBzAOLpYw/ZhJNzksDTnS/i8qdJvxuow==",
"dependencies": {
- "@babel/runtime": "^7.23.4",
+ "@babel/runtime": "^7.23.9",
"@types/prop-types": "^15.7.11",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
@@ -3672,6 +3677,102 @@
"react-dom": "^17.0.0 || ^18.0.0"
}
},
+ "node_modules/@mui/x-date-pickers": {
+ "version": "6.19.6",
+ "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.19.6.tgz",
+ "integrity": "sha512-QW9AFcPi0vLpkUhmquhhyhLaBvB0AZJuu3NTrE173qNKx3Z3n51aCLY9bc7c6i4ltZMMsVRHlvzQjsve04TC8A==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.2",
+ "@mui/base": "^5.0.0-beta.22",
+ "@mui/utils": "^5.14.16",
+ "@types/react-transition-group": "^4.4.8",
+ "clsx": "^2.0.0",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@mui/material": "^5.8.6",
+ "@mui/system": "^5.8.0",
+ "date-fns": "^2.25.0 || ^3.2.0",
+ "date-fns-jalali": "^2.13.0-0",
+ "dayjs": "^1.10.7",
+ "luxon": "^3.0.2",
+ "moment": "^2.29.4",
+ "moment-hijri": "^2.1.2",
+ "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "date-fns": {
+ "optional": true
+ },
+ "date-fns-jalali": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ },
+ "moment-hijri": {
+ "optional": true
+ },
+ "moment-jalaali": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/x-date-pickers/node_modules/@mui/base": {
+ "version": "5.0.0-beta.38",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.38.tgz",
+ "integrity": "sha512-AsjD6Y1X5A1qndxz8xCcR8LDqv31aiwlgWMPxFAX/kCKiIGKlK65yMeVZ62iQr/6LBz+9hSKLiD1i4TZdAHKcQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.23.9",
+ "@floating-ui/react-dom": "^2.0.8",
+ "@mui/types": "^7.2.13",
+ "@mui/utils": "^5.15.12",
+ "@popperjs/core": "^2.11.8",
+ "clsx": "^2.1.0",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -4328,6 +4429,15 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.52.tgz",
"integrity": "sha512-sm2aph6cRSsTMFYFgI+RpPLunXO9ClJkpizUVdT7KmGeyfQ14xnjTMT/f3MHcfKqevXqGT6BgVFzW8wcEoDUtA=="
},
+ "node_modules/@types/papaparse": {
+ "version": "5.3.14",
+ "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz",
+ "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@@ -4377,9 +4487,9 @@
}
},
"node_modules/@types/react-transition-group": {
- "version": "4.4.6",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
- "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==",
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz",
+ "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==",
"dependencies": {
"@types/react": "*"
}
@@ -6042,9 +6152,9 @@
}
},
"node_modules/clsx": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
- "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
+ "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
@@ -12842,6 +12952,11 @@
"node": ">=6"
}
},
+ "node_modules/papaparse": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz",
+ "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw=="
+ },
"node_modules/param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 01da27d..58823f8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -11,12 +11,14 @@
"@mui/lab": "^5.0.0-alpha.154",
"@mui/material": "^5.14.10",
"@mui/x-data-grid": "^6.19.1",
+ "@mui/x-date-pickers": "^6.19.6",
"@types/node": "^16.18.52",
"@types/react": "^18.2.22",
"@types/react-dom": "^18.2.7",
"axios": "^1.5.1",
"js-sha256": "^0.10.1",
"moment": "^2.29.4",
+ "papaparse": "^5.4.1",
"react": "^18.2.0",
"react-calendar": "^4.8.0",
"react-dom": "^18.2.0",
@@ -50,5 +52,8 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "@types/papaparse": "^5.3.14"
}
}
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index 194f79a..fcd36cd 100644
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -46,8 +46,8 @@ function Sidebar() {
gap: "2px",
}}>
-
-
+
+ {/* */}
("");
const [password, setPassword] = useState("");
- const [permissions, setPermissions] = useState({
- admin: false,
- article_create: false,
- article_manage: false,
- sponsor_manage: false,
- user_manage: false,
- });
-
const valid = () => {
if (!username) return false;
if (!password && id === "create") return false;
@@ -47,13 +39,6 @@ function UserModal({
useEffect(() => {
setUsername("");
setPassword("");
- setPermissions({
- admin: false,
- article_create: false,
- article_manage: false,
- sponsor_manage: false,
- user_manage: false,
- });
if (!id) return;
if (id === "create") return;
@@ -67,15 +52,6 @@ function UserModal({
})
.then((res) => {
setUsername(res.data.username);
-
- setPermissions({
- admin: res.data.admin,
- article_create: res.data.article_create,
- article_manage: res.data.article_manage,
- sponsor_manage: res.data.sponsor_manage,
- user_manage: res.data.user_manage,
- });
-
setLoading(false);
});
}, [id]);
@@ -186,112 +162,6 @@ function UserModal({
}}
/>
-
-
- {
- setPermissions({
- ...permissions,
- admin: e.target.checked,
- });
- }}
- />
- Admin
-
-
-
- {
- setPermissions({
- ...permissions,
- article_create: e.target.checked,
- });
- }}
- />
- Artikel Erstellen
-
-
-
- {
- setPermissions({
- ...permissions,
- article_manage: e.target.checked,
- });
- }}
- />
- Artikel Verwalten
-
-
-
- {
- setPermissions({
- ...permissions,
- sponsor_manage: e.target.checked,
- });
- }}
- />
- Sponsoren Verwalten
-
-
-
- {
- setPermissions({
- ...permissions,
- user_manage: e.target.checked,
- });
- }}
- />
- Nutzer Verwalten
-
-
-
+
+
);
\ No newline at end of file
diff --git a/frontend/src/pages/AdminFrame.tsx b/frontend/src/pages/AdminFrame.tsx
index 971534b..d975bc6 100644
--- a/frontend/src/pages/AdminFrame.tsx
+++ b/frontend/src/pages/AdminFrame.tsx
@@ -4,8 +4,8 @@ import Sidebar from "../components/Sidebar";
import Dashboard from "./admin/Dashboard";
import Benutzer from "./admin/Benutzer";
import Logout from "./admin/Logout";
-import Import from "./admin/Import";
import Kalender from "./admin/Kalender";
+import ManageData from "./admin/ManageData";
function AdminFrame() {
return (
@@ -31,7 +31,7 @@ function AdminFrame() {
} />
} />
} />
- } />
+ } />
} />
diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx
index f00637c..c8ecdbc 100644
--- a/frontend/src/pages/LandingPage.tsx
+++ b/frontend/src/pages/LandingPage.tsx
@@ -1,21 +1,52 @@
-import { Box, Typography } from "@mui/material";
+import { Box, Collapse, 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";
+import moment from "moment";
+
+interface EmployeeWithColor extends Types.Employees {
+ color: string;
+ EventType: "Geburtstag" | "Jubiläum";
+}
function LandingPage() {
- const [isHalloween, setIsHalloween] = useState(false);
+ const [data, setData] = useState([]);
+ const [currEvent, setCurrEvent] = useState(0);
useEffect(() => {
- const currentDate = new Date();
- const halloweenDate = new Date("2024-03-04");
+ axios
+ .get(`${getBaseURL()}/api/toshow`)
+ .then((res) => {
+ setData(res.data.map((employee: Types.Employees) => ({
+ ...employee,
+ color: `hsl(${Math.random() * 360}, 100%, 50%)`,
+ })));
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+ }, []);
- setIsHalloween(
- currentDate.getMonth() === halloweenDate.getMonth() &&
- currentDate.getDate() === halloweenDate.getDate()
- );
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setCurrEvent((prev) => {
+ if (data.length === 0) return 0;
+ if (data.length === 1) return 0;
+ if (prev === data.length - 1) return 0;
+ else return prev + 1;
+ });
+ }, 5000);
+
+ return () => clearInterval(interval);
+ }, [data]);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ window.location.reload();
+ }, moment().endOf("day").diff(moment(), "milliseconds"));
+
+ return () => clearInterval(interval);
}, []);
return (
@@ -32,7 +63,7 @@ function LandingPage() {
alignItems: "center",
}}
>
-
+ {/* */}
-
- {isHalloween
- ? "Happy Halloween"
- : "Keine Geburtstage oder Jubiläen heute."}
-
+ {data.map((employee, index) => {
+ return (
+
+
+
+ {employee.Vorname} {employee.Nachname}
+
+
+ {employee.EventType === "Geburtstag" ? "hat Geburtstag" : "hat Jubiläum"}
+
+
+
+ );
+ })}
>
);
diff --git a/frontend/src/pages/admin/Benutzer.tsx b/frontend/src/pages/admin/Benutzer.tsx
index 900bced..95dc395 100644
--- a/frontend/src/pages/admin/Benutzer.tsx
+++ b/frontend/src/pages/admin/Benutzer.tsx
@@ -112,7 +112,6 @@ function Benutzer() {
Name
- Berechtigungen
@@ -120,18 +119,6 @@ function Benutzer() {
{users.map((user) => (
{user.username}
-
- {[
- { name: "Admin", value: user.admin },
- { name: "Artikel Erstellen", value: user.article_create },
- { name: "Artikel Verwalten", value: user.article_manage },
- { name: "Sponsoren Verwalten", value: user.sponsor_manage },
- { name: "Nutzer Verwalten", value: user.user_manage },
- ]
- .filter((e) => e.value)
- .map((e) => e.name)
- .join(", ")}
-
moment(params.value).format("DD.MM.YYYY")
-
- },
- {
- field: "Geburtstag",
- headerName: "Geburtstag",
- type: "date",
- width: 160,
- valueFormatter: params => moment(params.value).format("DD.MM.YYYY")
-
- },
-];
+import { Box, Typography } from '@mui/material'
+import React from 'react'
function Dashboard() {
- const [workers, setWorkers] = useState([]);
-
- useEffect(() => {
- axios
- .get(`${getBaseURL()}/api/workers`, {
- headers: {
- Authorization: `Bearer ${localStorage.getItem("token")}`,
- },
- })
- .then((res) => {
- setWorkers(res.data);
- })
- .catch((err) => {
- console.log(err);
- });
- }, []);
-
- const rows = workers.map((worker, index) => ({
- id: index,
- Vorname: worker.Vorname,
- Nachname: worker.Nachname,
- Geburtstag: worker.Geburtstag,
- Anstelldatum: worker.Anstelldatum,
- }))
-
return (
-
-
- Nächste Geburtstage
-
-
-
+
+ Noch nicht Implementiert!
- );
+ )
}
-export default Dashboard;
+export default Dashboard
\ No newline at end of file
diff --git a/frontend/src/pages/admin/ManageData.tsx b/frontend/src/pages/admin/ManageData.tsx
new file mode 100644
index 0000000..b140bca
--- /dev/null
+++ b/frontend/src/pages/admin/ManageData.tsx
@@ -0,0 +1,899 @@
+import {
+ Alert,
+ Backdrop,
+ Box,
+ Button,
+ Checkbox,
+ CircularProgress,
+ Collapse,
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableRow,
+ TextField,
+ Tooltip,
+ Typography,
+} from "@mui/material";
+import axios from "axios";
+import { useEffect, useState } from "react";
+import { getBaseURL } from "../../functions";
+import moment from "moment";
+import { Add, Delete, Edit, Refresh, UploadFile } from "@mui/icons-material";
+import { DatePicker } from "@mui/x-date-pickers";
+import PapaParse from "papaparse";
+
+function ManageData() {
+ const [employees, setEmployees] = useState([]);
+ const [checked, setChecked] = useState([]);
+
+ const [loading, setLoading] = useState(false);
+
+ const [createPopup, setCreatePopup] = useState(false);
+ const [editPopup, setEditPopup] = useState(false);
+ const [deletePopup, setDeletePopup] = useState(
+ false
+ );
+ const [uploadPopup, setUploadPopup] = useState(false);
+
+ const getEmployees = () => {
+ setLoading(true);
+ setChecked([]);
+ axios
+ .get(`${getBaseURL()}/api/employees`, {
+ headers: {
+ Authorization: `Bearer ${localStorage.getItem("token")}`,
+ },
+ })
+ .then((res) => {
+ setEmployees(res.data);
+ setLoading(false);
+ })
+ .catch((err) => {
+ console.log(err);
+ });
+ };
+
+ useEffect(() => {
+ getEmployees();
+ }, []);
+
+ useEffect(() => {
+ if (!createPopup) getEmployees();
+ }, [createPopup]);
+
+ useEffect(() => {
+ if (!editPopup) getEmployees();
+ }, [editPopup]);
+
+ useEffect(() => {
+ if (!deletePopup) getEmployees();
+ }, [deletePopup]);
+
+ useEffect(() => {
+ if (!uploadPopup) getEmployees();
+ }, [uploadPopup]);
+
+ return (
+
+
+
+
+
+ {CreatePopUp(createPopup, setCreatePopup)}
+ {EditPopUp(editPopup, setEditPopup)}
+ {DeletePopUp(deletePopup, setDeletePopup)}
+ {UploadPopUp(uploadPopup, setUploadPopup)}
+
+
+ Daten Verwalten
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0}>
+
+
+
+
+
+
+
+
+
+
+ {
+ if (v) setChecked(employees.map((employee) => employee.ID));
+ else setChecked([]);
+ }}
+ />
+
+ Nachname
+ Vorname
+ Geburtstag
+ Anstelldatum
+
+
+
+
+ {employees.map((employee, index) => (
+
+
+ {
+ if (v) setChecked([...checked, employee.ID]);
+ else setChecked(checked.filter((id) => id !== employee.ID));
+ }}
+ />
+
+ {employee.Nachname}
+ {employee.Vorname}
+
+ {employee.Geburtstag
+ ? moment(employee.Geburtstag).format("DD.MM.YYYY")
+ : "-"}
+
+
+ {employee.Anstelldatum
+ ? moment(employee.Anstelldatum).format("DD.MM.YYYY")
+ : "-"}
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+ );
+}
+
+export default ManageData;
+
+function CreatePopUp(
+ createPopup: boolean,
+ setCreatePopup: (value: boolean) => void
+) {
+ const [vorname, setVorname] = useState("");
+ const [nachname, setNachname] = useState("");
+
+ const [showGeburtstag, setShowGeburtstag] = useState(false);
+ const [geburtstag, setGeburtstag] = useState(null);
+ const [showAnstelldatum, setShowAnstelldatum] = useState(false);
+ const [anstelldatum, setAnstelldatum] = useState(null);
+
+ const [loading, setLoading] = useState(false);
+
+ const checkValid = () => {
+ if (vorname === "" || vorname.length > 24) return false;
+ if (nachname === "" || nachname.length > 24) return false;
+
+ if (showGeburtstag && !geburtstag) return false;
+ if (showAnstelldatum && !anstelldatum) return false;
+
+ return true;
+ };
+
+ useEffect(() => {
+ if (!createPopup) {
+ setVorname("");
+ setNachname("");
+ setShowGeburtstag(false);
+ setGeburtstag(null);
+ setShowAnstelldatum(false);
+ setAnstelldatum(null);
+ setLoading(false);
+ }
+ }, [createPopup]);
+
+ return (
+
+
+
+ Neuen Mitarbeiter Hinzufügen
+
+
+ {
+ if (e.target.value.length > 24) return;
+ setVorname(e.target.value);
+ }}
+ />
+ {
+ if (e.target.value.length > 24) return;
+ setNachname(e.target.value);
+ }}
+ />
+
+
+ setShowGeburtstag(v)}
+ />
+ setGeburtstag(v)}
+ disabled={!showGeburtstag}
+ maxDate={moment() as any}
+ />
+
+
+
+ setShowAnstelldatum(v)}
+ />
+ setAnstelldatum(v)}
+ disabled={!showAnstelldatum}
+ maxDate={moment() as any}
+ />
+
+
+
+
+
+
+
+
+ );
+}
+
+function EditPopUp(
+ editPopup: Types.Employees | false,
+ setEditPopup: (value: Types.Employees | false) => void
+) {
+ const [vorname, setVorname] = useState(
+ editPopup ? editPopup.Vorname : ""
+ );
+ const [nachname, setNachname] = useState(
+ editPopup ? editPopup.Nachname : ""
+ );
+
+ const [showGeburtstag, setShowGeburtstag] = useState(
+ editPopup ? !!editPopup.Geburtstag : false
+ );
+ const [geburtstag, setGeburtstag] = useState(
+ editPopup
+ ? editPopup.Geburtstag
+ ? moment(editPopup.Geburtstag)
+ : null
+ : null
+ );
+ const [showAnstelldatum, setShowAnstelldatum] = useState(
+ editPopup ? !!editPopup.Anstelldatum : false
+ );
+ const [anstelldatum, setAnstelldatum] = useState(
+ editPopup
+ ? editPopup.Anstelldatum
+ ? moment(editPopup.Anstelldatum)
+ : null
+ : null
+ );
+
+ const [loading, setLoading] = useState(false);
+
+ const checkValid = () => {
+ if (vorname === "" || vorname.length > 24) return false;
+ if (nachname === "" || nachname.length > 24) return false;
+
+ if (showGeburtstag && !geburtstag) return false;
+ if (showAnstelldatum && !anstelldatum) return false;
+
+ return true;
+ };
+
+ useEffect(() => {
+ if (editPopup) {
+ setVorname(editPopup.Vorname);
+ setNachname(editPopup.Nachname);
+ setShowGeburtstag(!!editPopup.Geburtstag);
+ setGeburtstag(editPopup.Geburtstag ? moment(editPopup.Geburtstag) : null);
+ setShowAnstelldatum(!!editPopup.Anstelldatum);
+ setAnstelldatum(
+ editPopup.Anstelldatum ? moment(editPopup.Anstelldatum) : null
+ );
+ } else {
+ setVorname("");
+ setNachname("");
+ setShowGeburtstag(false);
+ setGeburtstag(null);
+ setShowAnstelldatum(false);
+ setAnstelldatum(null);
+ setLoading(false);
+ }
+ }, [editPopup]);
+
+ return (
+
+
+
+ {editPopup && editPopup.Vorname[0]}
+ {". "} {editPopup && editPopup.Nachname} Bearbeiten
+
+
+ {
+ if (e.target.value.length > 24) return;
+ setVorname(e.target.value);
+ }}
+ />
+ {
+ if (e.target.value.length > 24) return;
+ setNachname(e.target.value);
+ }}
+ />
+
+
+ setShowGeburtstag(v)}
+ />
+ setGeburtstag(v)}
+ disabled={!showGeburtstag}
+ maxDate={moment() as any}
+ />
+
+
+
+ setShowAnstelldatum(v)}
+ />
+ setAnstelldatum(v)}
+ disabled={!showAnstelldatum}
+ maxDate={moment() as any}
+ />
+
+
+
+
+
+
+
+
+ );
+}
+
+function DeletePopUp(
+ deletePopup: Types.Employees | false,
+ setDeletePopup: (value: Types.Employees | false) => void
+) {
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ if (!deletePopup) setLoading(false);
+ }, [deletePopup]);
+
+ if (deletePopup === false) return <>>;
+
+ return (
+
+
+
+ Mitarbeiter Löschen
+
+
+
+ Wollen Sie wirklich den Mitarbeiter{" "}
+
+ {deletePopup?.Vorname} {deletePopup?.Nachname}{" "}
+
+ löschen?
+
+
+
+
+
+
+
+
+ );
+}
+
+interface EmployeePartial {
+ Vorname: string;
+ Nachname: string;
+ Geburtstag: moment.Moment | null;
+ Anstelldatum: moment.Moment | null;
+}
+
+function UploadPopUp(
+ uploadPopup: boolean,
+ setUploadPopup: (value: boolean) => void
+) {
+ const [loading, setLoading] = useState(false);
+
+ const [data, setData] = useState(null);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (!uploadPopup) setLoading(false);
+ }, [uploadPopup]);
+
+ return (
+
+
+
+ CSV Hochladen
+
+
+
+ {error}
+
+
+ {
+ if (!e.target.files) return;
+
+ const file = e.target.files[0];
+
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const result = e.target?.result as string;
+
+ const data: PapaParse.ParseResult = PapaParse.parse(result)
+
+ if((data.data[0]).length !== 4) return setError("CSV Datei ist nicht im richtigen Format");
+ if(data.data[0][0] !== "Vorname") return setError("CSV Datei ist nicht im richtigen Format");
+ if(data.data[0][1] !== "Nachname") return setError("CSV Datei ist nicht im richtigen Format");
+ if(data.data[0][2] !== "Geburtstag") return setError("CSV Datei ist nicht im richtigen Format");
+ if(data.data[0][3] !== "Anstelldatum") return setError("CSV Datei ist nicht im richtigen Format");
+
+ const employees: EmployeePartial[] = [];
+ for(let i = 1; i < data.data.length; i++) {
+ const employee = data.data[i];
+ if(employee.length !== 4) return setError("CSV Datei ist nicht im richtigen Format");
+ if(employee[0].length > 24) return setError("Vorname ist zu lang");
+ if(employee[1].length > 24) return setError("Nachname ist zu lang");
+ if(employee[2] !== "" && !moment(employee[2], "DD.MM.YYYY", true).isValid()) return setError("Geburtstag ist nicht im richtigen Format");
+ if(employee[3] !== "" && !moment(employee[3], "DD.MM.YYYY", true).isValid()) return setError("Anstelldatum ist nicht im richtigen Format");
+
+ employees.push({
+ Vorname: employee[0],
+ Nachname: employee[1],
+ Geburtstag: employee[2] === "" ? null : moment(employee[2], "DD.MM.YYYY"),
+ Anstelldatum: employee[3] === "" ? null : moment(employee[3], "DD.MM.YYYY"),
+ });
+ }
+
+ setData(employees);
+ };
+
+ reader.readAsText(file);
+ }}
+ />
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/types.d.ts b/frontend/src/types.d.ts
index 2561fdc..288cea7 100644
--- a/frontend/src/types.d.ts
+++ b/frontend/src/types.d.ts
@@ -1,9 +1,10 @@
declare namespace Types {
- interface Worker {
+ interface Employees {
+ ID: string;
Vorname: string;
Nachname: string;
- Geburtstag: Date;
- Anstelldatum: Date;
+ Geburtstag?: Date;
+ Anstelldatum?: Date;
}
interface User extends UserPermissions {
ID: string;
@@ -17,12 +18,4 @@ declare namespace Types {
sponsor_manage: boolean;
user_manage: boolean;
}
-
- interface Sponsor {
- ID: string;
- name: string;
- url: string;
- description: string;
- addedAt: Date;
- }
}
\ No newline at end of file