Gay ass
This commit is contained in:
parent
57a1a0105f
commit
64ea467e3c
@ -9,14 +9,14 @@ datasource db {
|
|||||||
extensions = [uuid_ossp(map: "uuid-ossp")]
|
extensions = [uuid_ossp(map: "uuid-ossp")]
|
||||||
}
|
}
|
||||||
|
|
||||||
model users {
|
model Users {
|
||||||
ID String @id @default(dbgenerated("uuid_generate_v1()")) @db.Uuid
|
ID String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
|
||||||
username String
|
username String
|
||||||
password String @db.VarChar(128)
|
password String @db.VarChar(128)
|
||||||
token String @db.VarChar(128)
|
token String @db.VarChar(128)
|
||||||
}
|
}
|
||||||
|
|
||||||
model Mitarbeiter {
|
model Employees {
|
||||||
ID String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
|
ID String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
|
||||||
Vorname String
|
Vorname String
|
||||||
Nachname String
|
Nachname String
|
||||||
|
@ -62,7 +62,7 @@ app.get('/api/auth/verify', async (req, res) => {
|
|||||||
res.send('OK')
|
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]
|
const token = req.headers.authorization?.split(' ')[1]
|
||||||
|
|
||||||
if (!token) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
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)
|
const user = await authorize(token)
|
||||||
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
||||||
|
|
||||||
const { title, content, image, sponsors } = req.body
|
if (!Array.isArray(req.body)) return res.status(400).send(Errors.INVALID_ITEMS)
|
||||||
if (!title || !content || !image) return res.status(400).send(Errors.MISSING_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]
|
const token = req.headers.authorization?.split(' ')[1]
|
||||||
|
|
||||||
if (!token) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
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)
|
const user = await authorize(token)
|
||||||
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
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: {
|
select: {
|
||||||
|
ID: true,
|
||||||
Vorname: true,
|
Vorname: true,
|
||||||
Nachname: true,
|
Nachname: true,
|
||||||
Geburtstag: true,
|
Geburtstag: true,
|
||||||
Anstelldatum: true,
|
Anstelldatum: true,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
Nachname: 'asc'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
res.send(workers)
|
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) => {
|
app.get('/api/users', async (req, res) => {
|
||||||
const token = req.headers.authorization?.split(' ')[1]
|
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)
|
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
||||||
|
|
||||||
|
|
||||||
const { username, password, admin, article_create, article_manage, sponsor_manage, user_manage } = req.body
|
const { username, password } = 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)
|
if (!username) return res.status(400).send(Errors.MISSING_ITEMS)
|
||||||
|
|
||||||
const newUser = await prisma.users.update({
|
const newUser = await prisma.users.update({
|
||||||
where: {
|
where: {
|
||||||
@ -181,11 +321,6 @@ app.patch('/api/users/edit/:id', async (req, res) => {
|
|||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
username,
|
username,
|
||||||
admin,
|
|
||||||
article_create,
|
|
||||||
article_manage,
|
|
||||||
sponsor_manage,
|
|
||||||
user_manage,
|
|
||||||
...(password && { password })
|
...(password && { password })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -211,65 +346,56 @@ app.delete('/api/users/delete/:id', async (req, res) => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.get('/api/toshow/:targetDate?', async (req, res) => {
|
app.get('/api/toshow/:targetDate?', async (req, res) => {
|
||||||
const { targetDate } = req.params;
|
const { targetDate } = req.params;
|
||||||
if(targetDate && targetDate.length !== 10) return res.status(400).send(Errors.INVALID_ITEMS)
|
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)
|
let dates: Types.EmployeeEvent[] = await prisma.employees.findMany({})
|
||||||
|
|
||||||
const user = await authorize(token)
|
let currDate;
|
||||||
if (!user) return res.status(401).send(Errors.INVALID_CREDENTIALS)
|
if (targetDate) currDate = moment(targetDate, "YYYY-MM-DD");
|
||||||
|
|
||||||
let dates: Types.Mitarbeiter[] = await prisma.mitarbeiter.findMany({})
|
|
||||||
|
|
||||||
let currDate;
|
|
||||||
if(targetDate) currDate = moment(targetDate, "YYYY-MM-DD");
|
|
||||||
else currDate = moment();
|
else currDate = moment();
|
||||||
for (let i in dates) {
|
for (let i in dates) {
|
||||||
let validity = false;
|
let validity = false;
|
||||||
|
|
||||||
|
|
||||||
// `${currDate.getFullYear()}-${getFormatNumber(date.getMonth(), 2)}-${getFormatNumber(date.getDay(), 2)}`
|
// `${currDate.getFullYear()}-${getFormatNumber(date.getMonth(), 2)}-${getFormatNumber(date.getDay(), 2)}`
|
||||||
|
|
||||||
if (dates[i].Anstelldatum) {
|
if (dates[i].Anstelldatum) {
|
||||||
const date = dates[i].Anstelldatum;
|
const date = dates[i].Anstelldatum;
|
||||||
const dateWithoutYear = moment(date).format("MM-DD");
|
const dateWithoutYear = moment(date).format("MM-DD");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
date &&
|
date &&
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
|
moment(dateWithoutYear, "MM-DD") >= moment(currDate).subtract(14, "days") &&
|
||||||
moment(dateWithoutYear,"MM-DD") <= currDate
|
moment(dateWithoutYear, "MM-DD") <= currDate
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
|
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") <= currDate
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
validity = true;
|
validity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dates[i].Geburtstag) {
|
if (dates[i].Geburtstag) {
|
||||||
const date = dates[i].Geburtstag;
|
const date = dates[i].Geburtstag;
|
||||||
const dateWithoutYear = moment(date).format("MM-DD");
|
const dateWithoutYear = moment(date).format("MM-DD");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
date &&
|
date &&
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
|
moment(dateWithoutYear, "MM-DD") >= moment(currDate).subtract(14, "days") &&
|
||||||
moment(dateWithoutYear,"MM-DD") <= currDate
|
moment(dateWithoutYear, "MM-DD") <= currDate
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "days") &&
|
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") <= currDate
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -277,36 +403,36 @@ app.get('/api/toshow/:targetDate?', async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!validity) delete dates[i];
|
if (!validity) delete dates[i];
|
||||||
}
|
}
|
||||||
dates = dates.filter((date) => date !== null);
|
dates = dates.filter((date) => date !== null);
|
||||||
|
|
||||||
|
|
||||||
for(let i = 14; i >= 1; i--) {
|
|
||||||
|
for (let i = 14; i >= 1; i--) {
|
||||||
console.log(i);
|
console.log(i);
|
||||||
const date = moment(currDate).subtract(i, "days")
|
const date = moment(currDate).subtract(i, "days")
|
||||||
const dayOfWeek = date.format("dddd");
|
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;
|
let validity = false;
|
||||||
|
|
||||||
if (dates[j].Anstelldatum) {
|
if (dates[j].Anstelldatum) {
|
||||||
const dateWithoutYear = moment(dates[j].Anstelldatum, "YYYY-MM-DD").format("MM-DD");
|
const dateWithoutYear = moment(dates[j].Anstelldatum, "YYYY-MM-DD").format("MM-DD");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
date &&
|
date &&
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
|
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(i, "days")
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "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(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");
|
const dateWithoutYear = moment(dates[j].Geburtstag, "YYYY-MM-DD").format("MM-DD");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
date &&
|
date &&
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD") >= moment(currDate).subtract(14, "days") &&
|
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(i, "days")
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(
|
(
|
||||||
moment(dateWithoutYear,"MM-DD").subtract(1, "year") >= moment(currDate).subtract(14, "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(i, "days")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -337,9 +463,26 @@ app.get('/api/toshow/:targetDate?', async (req, res) => {
|
|||||||
|
|
||||||
|
|
||||||
console.log(date);
|
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);
|
dates = dates.filter((date) => date !== null);
|
||||||
}
|
}
|
||||||
|
6
backend/src/types.d.ts
vendored
6
backend/src/types.d.ts
vendored
@ -5,11 +5,15 @@ declare namespace Types {
|
|||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Mitarbeiter {
|
interface Employees {
|
||||||
ID: string;
|
ID: string;
|
||||||
Vorname: string;
|
Vorname: string;
|
||||||
Nachname: string;
|
Nachname: string;
|
||||||
Anstelldatum: Date | null;
|
Anstelldatum: Date | null;
|
||||||
Geburtstag: Date | null;
|
Geburtstag: Date | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface EmployeeEvent extends Employees {
|
||||||
|
EventType?: "Geburtstag" | "Jubiläum";
|
||||||
|
}
|
||||||
}
|
}
|
179
frontend/package-lock.json
generated
179
frontend/package-lock.json
generated
@ -16,12 +16,14 @@
|
|||||||
"@mui/lab": "^5.0.0-alpha.154",
|
"@mui/lab": "^5.0.0-alpha.154",
|
||||||
"@mui/material": "^5.14.10",
|
"@mui/material": "^5.14.10",
|
||||||
"@mui/x-data-grid": "^6.19.1",
|
"@mui/x-data-grid": "^6.19.1",
|
||||||
|
"@mui/x-date-pickers": "^6.19.6",
|
||||||
"@types/node": "^16.18.52",
|
"@types/node": "^16.18.52",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"axios": "^1.5.1",
|
"axios": "^1.5.1",
|
||||||
"js-sha256": "^0.10.1",
|
"js-sha256": "^0.10.1",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
"papaparse": "^5.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-calendar": "^4.8.0",
|
"react-calendar": "^4.8.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@ -32,6 +34,9 @@
|
|||||||
"suneditor-react": "^3.6.1",
|
"suneditor-react": "^3.6.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"zustand": "^4.4.4"
|
"zustand": "^4.4.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/papaparse": "^5.3.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aashutoshrathi/word-wrap": {
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
@ -1951,9 +1956,9 @@
|
|||||||
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.23.5",
|
"version": "7.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz",
|
||||||
"integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==",
|
"integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -2528,28 +2533,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@floating-ui/core": {
|
"node_modules/@floating-ui/core": {
|
||||||
"version": "1.5.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz",
|
||||||
"integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==",
|
"integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/utils": "^0.1.3"
|
"@floating-ui/utils": "^0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@floating-ui/dom": {
|
"node_modules/@floating-ui/dom": {
|
||||||
"version": "1.5.3",
|
"version": "1.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz",
|
||||||
"integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==",
|
"integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/core": "^1.4.2",
|
"@floating-ui/core": "^1.0.0",
|
||||||
"@floating-ui/utils": "^0.1.3"
|
"@floating-ui/utils": "^0.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@floating-ui/react-dom": {
|
"node_modules/@floating-ui/react-dom": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz",
|
||||||
"integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==",
|
"integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/dom": "^1.5.1"
|
"@floating-ui/dom": "^1.6.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.8.0",
|
"react": ">=16.8.0",
|
||||||
@ -2557,9 +2562,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@floating-ui/utils": {
|
"node_modules/@floating-ui/utils": {
|
||||||
"version": "0.1.4",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
|
||||||
"integrity": "sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA=="
|
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
|
||||||
},
|
},
|
||||||
"node_modules/@fontsource-variable/lexend": {
|
"node_modules/@fontsource-variable/lexend": {
|
||||||
"version": "5.0.12",
|
"version": "5.0.12",
|
||||||
@ -3603,9 +3608,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/types": {
|
"node_modules/@mui/types": {
|
||||||
"version": "7.2.10",
|
"version": "7.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz",
|
||||||
"integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==",
|
"integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^17.0.0 || ^18.0.0"
|
"@types/react": "^17.0.0 || ^18.0.0"
|
||||||
},
|
},
|
||||||
@ -3616,11 +3621,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/utils": {
|
"node_modules/@mui/utils": {
|
||||||
"version": "5.14.19",
|
"version": "5.15.12",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.19.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.12.tgz",
|
||||||
"integrity": "sha512-qAHvTXzk7basbyqPvhgWqN6JbmI2wLB/mf97GkSlz5c76MiKYV6Ffjvw9BjKZQ1YRb8rDX9kgdjRezOcoB91oQ==",
|
"integrity": "sha512-8SDGCnO2DY9Yy+5bGzu00NZowSDtuyHP4H8gunhHGQoIlhlY2Z3w64wBzAOLpYw/ZhJNzksDTnS/i8qdJvxuow==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.23.4",
|
"@babel/runtime": "^7.23.9",
|
||||||
"@types/prop-types": "^15.7.11",
|
"@types/prop-types": "^15.7.11",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react-is": "^18.2.0"
|
"react-is": "^18.2.0"
|
||||||
@ -3672,6 +3677,102 @@
|
|||||||
"react-dom": "^17.0.0 || ^18.0.0"
|
"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": {
|
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
||||||
"version": "5.1.1-v1",
|
"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",
|
"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",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.52.tgz",
|
||||||
"integrity": "sha512-sm2aph6cRSsTMFYFgI+RpPLunXO9ClJkpizUVdT7KmGeyfQ14xnjTMT/f3MHcfKqevXqGT6BgVFzW8wcEoDUtA=="
|
"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": {
|
"node_modules/@types/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
@ -4377,9 +4487,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-transition-group": {
|
"node_modules/@types/react-transition-group": {
|
||||||
"version": "4.4.6",
|
"version": "4.4.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz",
|
||||||
"integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==",
|
"integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
@ -6042,9 +6152,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
|
||||||
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
|
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@ -12842,6 +12952,11 @@
|
|||||||
"node": ">=6"
|
"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": {
|
"node_modules/param-case": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
"@mui/lab": "^5.0.0-alpha.154",
|
"@mui/lab": "^5.0.0-alpha.154",
|
||||||
"@mui/material": "^5.14.10",
|
"@mui/material": "^5.14.10",
|
||||||
"@mui/x-data-grid": "^6.19.1",
|
"@mui/x-data-grid": "^6.19.1",
|
||||||
|
"@mui/x-date-pickers": "^6.19.6",
|
||||||
"@types/node": "^16.18.52",
|
"@types/node": "^16.18.52",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"axios": "^1.5.1",
|
"axios": "^1.5.1",
|
||||||
"js-sha256": "^0.10.1",
|
"js-sha256": "^0.10.1",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
"papaparse": "^5.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-calendar": "^4.8.0",
|
"react-calendar": "^4.8.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@ -50,5 +52,8 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/papaparse": "^5.3.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ function Sidebar() {
|
|||||||
gap: "2px",
|
gap: "2px",
|
||||||
}}>
|
}}>
|
||||||
<SidebarElement Title="Dashboard" Icon={Home} Path="/admin/dashboard" />
|
<SidebarElement Title="Dashboard" Icon={Home} Path="/admin/dashboard" />
|
||||||
<SidebarElement Title="Daten import" Icon={TableChartOutlined} Path="/admin/import" />
|
<SidebarElement Title="Verwalten" Icon={TableChartOutlined} Path="/admin/manage" />
|
||||||
<SidebarElement Title="Kalender" Icon={Event} Path="/admin/Kalender" />
|
{/* <SidebarElement Title="Kalender" Icon={Event} Path="/admin/Kalender" /> */}
|
||||||
<SidebarElement Title="Benutzer" Icon={Person} Path="/admin/benutzer" />
|
<SidebarElement Title="Benutzer" Icon={Person} Path="/admin/benutzer" />
|
||||||
|
|
||||||
<SidebarElement Title="Zur Website" Icon={ArrowBack} Path="/" sx={{
|
<SidebarElement Title="Zur Website" Icon={ArrowBack} Path="/" sx={{
|
||||||
|
@ -29,14 +29,6 @@ function UserModal({
|
|||||||
const [username, setUsername] = useState<string>("");
|
const [username, setUsername] = useState<string>("");
|
||||||
const [password, setPassword] = useState<string>("");
|
const [password, setPassword] = useState<string>("");
|
||||||
|
|
||||||
const [permissions, setPermissions] = useState<Types.UserPermissions>({
|
|
||||||
admin: false,
|
|
||||||
article_create: false,
|
|
||||||
article_manage: false,
|
|
||||||
sponsor_manage: false,
|
|
||||||
user_manage: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const valid = () => {
|
const valid = () => {
|
||||||
if (!username) return false;
|
if (!username) return false;
|
||||||
if (!password && id === "create") return false;
|
if (!password && id === "create") return false;
|
||||||
@ -47,13 +39,6 @@ function UserModal({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setUsername("");
|
setUsername("");
|
||||||
setPassword("");
|
setPassword("");
|
||||||
setPermissions({
|
|
||||||
admin: false,
|
|
||||||
article_create: false,
|
|
||||||
article_manage: false,
|
|
||||||
sponsor_manage: false,
|
|
||||||
user_manage: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
if (id === "create") return;
|
if (id === "create") return;
|
||||||
@ -67,15 +52,6 @@ function UserModal({
|
|||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setUsername(res.data.username);
|
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);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}, [id]);
|
}, [id]);
|
||||||
@ -186,112 +162,6 @@ function UserModal({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
alignItems: "flex-start",
|
|
||||||
|
|
||||||
width: "80%",
|
|
||||||
mx: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
spacing={1}
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
checked={permissions.admin}
|
|
||||||
onChange={(e) => {
|
|
||||||
setPermissions({
|
|
||||||
...permissions,
|
|
||||||
admin: e.target.checked,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
Admin
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
spacing={1}
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
disabled={permissions.admin}
|
|
||||||
checked={permissions.article_create}
|
|
||||||
onChange={(e) => {
|
|
||||||
setPermissions({
|
|
||||||
...permissions,
|
|
||||||
article_create: e.target.checked,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
Artikel Erstellen
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
spacing={1}
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
disabled={permissions.admin}
|
|
||||||
checked={permissions.article_manage}
|
|
||||||
onChange={(e) => {
|
|
||||||
setPermissions({
|
|
||||||
...permissions,
|
|
||||||
article_manage: e.target.checked,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
Artikel Verwalten
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
spacing={1}
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
disabled={permissions.admin}
|
|
||||||
checked={permissions.sponsor_manage}
|
|
||||||
onChange={(e) => {
|
|
||||||
setPermissions({
|
|
||||||
...permissions,
|
|
||||||
sponsor_manage: e.target.checked,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
Sponsoren Verwalten
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
spacing={1}
|
|
||||||
justifyContent="center"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
disabled={permissions.admin}
|
|
||||||
checked={permissions.user_manage}
|
|
||||||
onChange={(e) => {
|
|
||||||
setPermissions({
|
|
||||||
...permissions,
|
|
||||||
user_manage: e.target.checked,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
Nutzer Verwalten
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
variant="contained"
|
variant="contained"
|
||||||
sx={{ width: "80%" }}
|
sx={{ width: "80%" }}
|
||||||
@ -305,20 +175,7 @@ function UserModal({
|
|||||||
`${getBaseURL()}/api/users/create`,
|
`${getBaseURL()}/api/users/create`,
|
||||||
{
|
{
|
||||||
username,
|
username,
|
||||||
password: sha256(`rheine ${password.trim()} rheine`),
|
password: sha256(`rheine ${password.trim()} rheine`)
|
||||||
admin: permissions.admin,
|
|
||||||
article_create: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.article_create,
|
|
||||||
article_manage: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.article_manage,
|
|
||||||
sponsor_manage: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.sponsor_manage,
|
|
||||||
user_manage: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.user_manage,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@ -339,20 +196,7 @@ function UserModal({
|
|||||||
username,
|
username,
|
||||||
password: password
|
password: password
|
||||||
? sha256(`rheine ${password.trim()} rheine`)
|
? sha256(`rheine ${password.trim()} rheine`)
|
||||||
: undefined,
|
: undefined
|
||||||
admin: permissions.admin,
|
|
||||||
article_create: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.article_create,
|
|
||||||
article_manage: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.article_manage,
|
|
||||||
sponsor_manage: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.sponsor_manage,
|
|
||||||
user_manage: permissions.admin
|
|
||||||
? false
|
|
||||||
: permissions.user_manage,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export function getBaseURL(): string {
|
export function getBaseURL(): string {
|
||||||
if(process.env.NODE_ENV === "development") return "http://100.108.94.138:3001"
|
if(process.env.NODE_ENV === "development") return "http://127.0.0.1:3001"
|
||||||
else return ""
|
else return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,16 @@ import "./index.css";
|
|||||||
import App from "./App";
|
import App from "./App";
|
||||||
import { createTheme, ThemeProvider, CssBaseline } from "@mui/material";
|
import { createTheme, ThemeProvider, CssBaseline } from "@mui/material";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
|
import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
|
||||||
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
// fonts
|
// fonts
|
||||||
import '@fontsource-variable/overpass';
|
import '@fontsource-variable/overpass';
|
||||||
import '@fontsource-variable/lexend';
|
import '@fontsource-variable/lexend';
|
||||||
|
|
||||||
|
moment.locale("de");
|
||||||
|
|
||||||
const theme = createTheme({
|
const theme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
mode: "light",
|
mode: "light",
|
||||||
@ -41,7 +45,9 @@ root.render(
|
|||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterMoment}>
|
||||||
<App />
|
<App />
|
||||||
|
</LocalizationProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
@ -4,8 +4,8 @@ import Sidebar from "../components/Sidebar";
|
|||||||
import Dashboard from "./admin/Dashboard";
|
import Dashboard from "./admin/Dashboard";
|
||||||
import Benutzer from "./admin/Benutzer";
|
import Benutzer from "./admin/Benutzer";
|
||||||
import Logout from "./admin/Logout";
|
import Logout from "./admin/Logout";
|
||||||
import Import from "./admin/Import";
|
|
||||||
import Kalender from "./admin/Kalender";
|
import Kalender from "./admin/Kalender";
|
||||||
|
import ManageData from "./admin/ManageData";
|
||||||
|
|
||||||
function AdminFrame() {
|
function AdminFrame() {
|
||||||
return (
|
return (
|
||||||
@ -31,7 +31,7 @@ function AdminFrame() {
|
|||||||
<Route path="/dashboard" element={<Dashboard />} />
|
<Route path="/dashboard" element={<Dashboard />} />
|
||||||
<Route path="/benutzer" element={<Benutzer />} />
|
<Route path="/benutzer" element={<Benutzer />} />
|
||||||
<Route path="/logout" element={<Logout />} />
|
<Route path="/logout" element={<Logout />} />
|
||||||
<Route path="/import" element={<Import />} />
|
<Route path="/manage" element={<ManageData />} />
|
||||||
<Route path="/kalender" element={<Kalender />} />
|
<Route path="/kalender" element={<Kalender />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,21 +1,52 @@
|
|||||||
import { Box, Typography } from "@mui/material";
|
import { Box, Collapse, Typography } from "@mui/material";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import PhilSwift from "../components/PhilSwift";
|
import PhilSwift from "../components/PhilSwift";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { getBaseURL } from "../functions";
|
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() {
|
function LandingPage() {
|
||||||
const [isHalloween, setIsHalloween] = useState(false);
|
const [data, setData] = useState<EmployeeWithColor[]>([]);
|
||||||
|
const [currEvent, setCurrEvent] = useState<number>(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentDate = new Date();
|
axios
|
||||||
const halloweenDate = new Date("2024-03-04");
|
.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(
|
useEffect(() => {
|
||||||
currentDate.getMonth() === halloweenDate.getMonth() &&
|
const interval = setInterval(() => {
|
||||||
currentDate.getDate() === halloweenDate.getDate()
|
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 (
|
return (
|
||||||
@ -32,7 +63,7 @@ function LandingPage() {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PhilSwift />
|
{/* <PhilSwift /> */}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
@ -48,20 +79,52 @@ function LandingPage() {
|
|||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
{data.map((employee, index) => {
|
||||||
sx={{
|
return (
|
||||||
fontSize: "2rem",
|
<Collapse
|
||||||
color: "red",
|
in={currEvent === index}
|
||||||
textAlign: "center",
|
key={index}
|
||||||
fontWeight: "bold",
|
orientation="horizontal"
|
||||||
textShadow: "2px 2px 4px #000000",
|
timeout={1000} // Add this line to make the collapse slower
|
||||||
zIndex: 10,
|
easing={"ease-in-out"}
|
||||||
}}
|
>
|
||||||
>
|
<Box sx={{
|
||||||
{isHalloween
|
width: "100vw",
|
||||||
? "Happy Halloween"
|
height: "100vh",
|
||||||
: "Keine Geburtstage oder Jubiläen heute."}
|
|
||||||
</Typography>
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}>
|
||||||
|
<Typography
|
||||||
|
variant="h1"
|
||||||
|
sx={{
|
||||||
|
width: "100vw",
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: "Lexend Variable",
|
||||||
|
color: employee.color,
|
||||||
|
fontSize: "15rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{employee.Vorname} {employee.Nachname}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="h2"
|
||||||
|
sx={{
|
||||||
|
width: "100vw",
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: "Lexend Variable",
|
||||||
|
color: employee.color,
|
||||||
|
fontSize: "5rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{employee.EventType === "Geburtstag" ? "hat Geburtstag" : "hat Jubiläum"}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Collapse>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -112,7 +112,6 @@ function Benutzer() {
|
|||||||
<TableCell align="left" width="700px">
|
<TableCell align="left" width="700px">
|
||||||
Name
|
Name
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="right">Berechtigungen</TableCell>
|
|
||||||
<TableCell align="right"></TableCell>
|
<TableCell align="right"></TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
@ -120,18 +119,6 @@ function Benutzer() {
|
|||||||
{users.map((user) => (
|
{users.map((user) => (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell align="left">{user.username}</TableCell>
|
<TableCell align="left">{user.username}</TableCell>
|
||||||
<TableCell align="right">
|
|
||||||
{[
|
|
||||||
{ 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(", ")}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="right">
|
<TableCell align="right">
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1,115 +1,18 @@
|
|||||||
import { Visibility, Newspaper, Person, Savings } from "@mui/icons-material";
|
import { Box, Typography } from '@mui/material'
|
||||||
import { Box, Grid, SvgIconTypeMap, Typography } from "@mui/material";
|
import React from 'react'
|
||||||
import { OverridableComponent } from "@mui/material/OverridableComponent";
|
|
||||||
import axios from "axios";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { getBaseURL } from "../../functions";
|
|
||||||
import { DataGrid, GridColDef, GridValueGetterParams } from "@mui/x-data-grid";
|
|
||||||
import moment from "moment";
|
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
|
||||||
{
|
|
||||||
field: "Vorname",
|
|
||||||
headerName: "Vorname",
|
|
||||||
width: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "Nachname",
|
|
||||||
headerName: "Nachname",
|
|
||||||
width: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "Anstelldatum",
|
|
||||||
headerName: "Anstelldatum",
|
|
||||||
type: "date",
|
|
||||||
width: 160,
|
|
||||||
valueFormatter: params => moment(params.value).format("DD.MM.YYYY")
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "Geburtstag",
|
|
||||||
headerName: "Geburtstag",
|
|
||||||
type: "date",
|
|
||||||
width: 160,
|
|
||||||
valueFormatter: params => moment(params.value).format("DD.MM.YYYY")
|
|
||||||
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
const [workers, setWorkers] = useState<Types.Worker[]>([]);
|
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<Box
|
<Box sx={{
|
||||||
sx={{
|
width: "100%",
|
||||||
width: "100%",
|
height: "100vh",
|
||||||
height: "auto",
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
display: "flex",
|
alignItems: "center",
|
||||||
flexDirection: "column",
|
}}>
|
||||||
justifyContent: "flex-start",
|
<Typography variant="h1">Noch nicht Implementiert!</Typography>
|
||||||
alignItems: "flex-start",
|
|
||||||
|
|
||||||
pt: "30px",
|
|
||||||
px: "30px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="h4" sx={{ fontWeight: "bold" }}>
|
|
||||||
Nächste Geburtstage
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<DataGrid
|
|
||||||
rows={rows}
|
|
||||||
columns={columns}
|
|
||||||
sx={{
|
|
||||||
fontSize: "1rem",
|
|
||||||
marginTop: "1rem",
|
|
||||||
borderRadius: "20px",
|
|
||||||
width: "100%",
|
|
||||||
height: "auto",
|
|
||||||
}}
|
|
||||||
initialState={{
|
|
||||||
sorting: {
|
|
||||||
sortModel: [
|
|
||||||
{
|
|
||||||
field: 'commodity',
|
|
||||||
sort: 'asc',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
pagination: {
|
|
||||||
paginationModel: {
|
|
||||||
pageSize: 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
checkboxSelection
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Dashboard;
|
export default Dashboard
|
899
frontend/src/pages/admin/ManageData.tsx
Normal file
899
frontend/src/pages/admin/ManageData.tsx
Normal file
@ -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<Types.Employees[]>([]);
|
||||||
|
const [checked, setChecked] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const [createPopup, setCreatePopup] = useState<boolean>(false);
|
||||||
|
const [editPopup, setEditPopup] = useState<Types.Employees | false>(false);
|
||||||
|
const [deletePopup, setDeletePopup] = useState<Types.Employees | false>(
|
||||||
|
false
|
||||||
|
);
|
||||||
|
const [uploadPopup, setUploadPopup] = useState<boolean>(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 (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
height: "auto",
|
||||||
|
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
|
||||||
|
pt: "30px",
|
||||||
|
px: "30px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Backdrop open={loading} sx={{ zIndex: 1000 }}>
|
||||||
|
<CircularProgress color="secondary" />
|
||||||
|
</Backdrop>
|
||||||
|
|
||||||
|
{CreatePopUp(createPopup, setCreatePopup)}
|
||||||
|
{EditPopUp(editPopup, setEditPopup)}
|
||||||
|
{DeletePopUp(deletePopup, setDeletePopup)}
|
||||||
|
{UploadPopUp(uploadPopup, setUploadPopup)}
|
||||||
|
|
||||||
|
<Typography variant="h4" sx={{ fontWeight: "bold" }}>
|
||||||
|
Daten Verwalten
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
padding: "10px",
|
||||||
|
backgroundColor: "#00000022",
|
||||||
|
borderRadius: "5px",
|
||||||
|
ml: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip arrow placement="top" title="Mitarbeiter Hinzufügen">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setCreatePopup(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Add />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip arrow placement="top" title="Daten Aktualisieren">
|
||||||
|
<Button onClick={() => getEmployees()}>
|
||||||
|
<Refresh />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip arrow placement="top" title="CSV Hochladen">
|
||||||
|
<Button onClick={() => setUploadPopup(true)}>
|
||||||
|
<UploadFile />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Collapse orientation="horizontal" in={checked.length > 0}>
|
||||||
|
<Tooltip arrow placement="top" title="Ausgewählte Löschen">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setLoading(true);
|
||||||
|
axios
|
||||||
|
.delete(
|
||||||
|
`${getBaseURL()}/api/employees/${checked.join(",")}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem(
|
||||||
|
"token"
|
||||||
|
)}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
getEmployees();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Delete />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Collapse>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={checked.length === employees.length}
|
||||||
|
onChange={(_, v) => {
|
||||||
|
if (v) setChecked(employees.map((employee) => employee.ID));
|
||||||
|
else setChecked([]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>Nachname</TableCell>
|
||||||
|
<TableCell>Vorname</TableCell>
|
||||||
|
<TableCell>Geburtstag</TableCell>
|
||||||
|
<TableCell>Anstelldatum</TableCell>
|
||||||
|
<TableCell align="right"></TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{employees.map((employee, index) => (
|
||||||
|
<TableRow key={index}>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={checked.includes(employee.ID)}
|
||||||
|
onChange={(_, v) => {
|
||||||
|
if (v) setChecked([...checked, employee.ID]);
|
||||||
|
else setChecked(checked.filter((id) => id !== employee.ID));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{employee.Nachname}</TableCell>
|
||||||
|
<TableCell>{employee.Vorname}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{employee.Geburtstag
|
||||||
|
? moment(employee.Geburtstag).format("DD.MM.YYYY")
|
||||||
|
: "-"}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{employee.Anstelldatum
|
||||||
|
? moment(employee.Anstelldatum).format("DD.MM.YYYY")
|
||||||
|
: "-"}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="right">
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => {
|
||||||
|
setEditPopup(employee);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Edit />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="error"
|
||||||
|
onClick={() => {
|
||||||
|
setDeletePopup(employee);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Delete />
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManageData;
|
||||||
|
|
||||||
|
function CreatePopUp(
|
||||||
|
createPopup: boolean,
|
||||||
|
setCreatePopup: (value: boolean) => void
|
||||||
|
) {
|
||||||
|
const [vorname, setVorname] = useState<string>("");
|
||||||
|
const [nachname, setNachname] = useState<string>("");
|
||||||
|
|
||||||
|
const [showGeburtstag, setShowGeburtstag] = useState<boolean>(false);
|
||||||
|
const [geburtstag, setGeburtstag] = useState<moment.Moment | null>(null);
|
||||||
|
const [showAnstelldatum, setShowAnstelldatum] = useState<boolean>(false);
|
||||||
|
const [anstelldatum, setAnstelldatum] = useState<moment.Moment | null>(null);
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState<boolean>(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 (
|
||||||
|
<Backdrop open={createPopup} sx={{ zIndex: 1000 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "500px",
|
||||||
|
height: "auto",
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "5px",
|
||||||
|
boxShadow: "0 0 10px #00000055",
|
||||||
|
padding: "20px",
|
||||||
|
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "center",
|
||||||
|
|
||||||
|
gap: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontWeight: "bold", fontSize: "30px" }}>
|
||||||
|
Neuen Mitarbeiter Hinzufügen
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
label="Vorname"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={vorname}
|
||||||
|
maxRows={1}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 24) return;
|
||||||
|
setVorname(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Nachname"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={nachname}
|
||||||
|
maxRows={1}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 24) return;
|
||||||
|
setNachname(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "5px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={showGeburtstag}
|
||||||
|
onChange={(_, v) => setShowGeburtstag(v)}
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
label="Geburtstag"
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
format="DD.MM.YYYY"
|
||||||
|
value={geburtstag}
|
||||||
|
onChange={(v) => setGeburtstag(v)}
|
||||||
|
disabled={!showGeburtstag}
|
||||||
|
maxDate={moment() as any}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "5px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={showAnstelldatum}
|
||||||
|
onChange={(_, v) => setShowAnstelldatum(v)}
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
label="Anstelldatum"
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
format="DD.MM.YYYY"
|
||||||
|
value={anstelldatum}
|
||||||
|
onChange={(v) => setAnstelldatum(v)}
|
||||||
|
disabled={!showAnstelldatum}
|
||||||
|
maxDate={moment() as any}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
padding: "10px",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disabled={!checkValid() || loading}
|
||||||
|
onClick={() => {
|
||||||
|
if (!checkValid()) return;
|
||||||
|
setLoading(true);
|
||||||
|
axios
|
||||||
|
.put(
|
||||||
|
`${getBaseURL()}/api/employees`,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
Vorname: vorname,
|
||||||
|
Nachname: nachname,
|
||||||
|
Geburtstag: showGeburtstag
|
||||||
|
? moment(geburtstag).add(1, "day").toDate().getTime()
|
||||||
|
: null,
|
||||||
|
Anstelldatum: showAnstelldatum
|
||||||
|
? moment(anstelldatum).add(1, "day").toDate().getTime()
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
setCreatePopup(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{loading && <CircularProgress size={20} />} Hinzufügen
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() => {
|
||||||
|
setCreatePopup(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Backdrop>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditPopUp(
|
||||||
|
editPopup: Types.Employees | false,
|
||||||
|
setEditPopup: (value: Types.Employees | false) => void
|
||||||
|
) {
|
||||||
|
const [vorname, setVorname] = useState<string>(
|
||||||
|
editPopup ? editPopup.Vorname : ""
|
||||||
|
);
|
||||||
|
const [nachname, setNachname] = useState<string>(
|
||||||
|
editPopup ? editPopup.Nachname : ""
|
||||||
|
);
|
||||||
|
|
||||||
|
const [showGeburtstag, setShowGeburtstag] = useState<boolean>(
|
||||||
|
editPopup ? !!editPopup.Geburtstag : false
|
||||||
|
);
|
||||||
|
const [geburtstag, setGeburtstag] = useState<moment.Moment | null>(
|
||||||
|
editPopup
|
||||||
|
? editPopup.Geburtstag
|
||||||
|
? moment(editPopup.Geburtstag)
|
||||||
|
: null
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
const [showAnstelldatum, setShowAnstelldatum] = useState<boolean>(
|
||||||
|
editPopup ? !!editPopup.Anstelldatum : false
|
||||||
|
);
|
||||||
|
const [anstelldatum, setAnstelldatum] = useState<moment.Moment | null>(
|
||||||
|
editPopup
|
||||||
|
? editPopup.Anstelldatum
|
||||||
|
? moment(editPopup.Anstelldatum)
|
||||||
|
: null
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState<boolean>(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 (
|
||||||
|
<Backdrop open={editPopup !== false} sx={{ zIndex: 1000 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "500px",
|
||||||
|
height: "auto",
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "5px",
|
||||||
|
boxShadow: "0 0 10px #00000055",
|
||||||
|
padding: "20px",
|
||||||
|
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "center",
|
||||||
|
|
||||||
|
gap: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontWeight: "bold", fontSize: "30px" }}>
|
||||||
|
{editPopup && editPopup.Vorname[0]}
|
||||||
|
{". "} {editPopup && editPopup.Nachname} Bearbeiten
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
label="Vorname"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={vorname}
|
||||||
|
maxRows={1}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 24) return;
|
||||||
|
setVorname(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Nachname"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={nachname}
|
||||||
|
maxRows={1}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length > 24) return;
|
||||||
|
setNachname(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "5px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={showGeburtstag}
|
||||||
|
onChange={(_, v) => setShowGeburtstag(v)}
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
label="Geburtstag"
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
format="DD.MM.YYYY"
|
||||||
|
value={geburtstag}
|
||||||
|
onChange={(v) => setGeburtstag(v)}
|
||||||
|
disabled={!showGeburtstag}
|
||||||
|
maxDate={moment() as any}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "5px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={showAnstelldatum}
|
||||||
|
onChange={(_, v) => setShowAnstelldatum(v)}
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
label="Anstelldatum"
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
format="DD.MM.YYYY"
|
||||||
|
value={anstelldatum}
|
||||||
|
onChange={(v) => setAnstelldatum(v)}
|
||||||
|
disabled={!showAnstelldatum}
|
||||||
|
maxDate={moment() as any}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
padding: "10px",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disabled={!checkValid() || loading}
|
||||||
|
onClick={() => {
|
||||||
|
if (!checkValid()) return;
|
||||||
|
setLoading(true);
|
||||||
|
if (editPopup && !editPopup.ID) return;
|
||||||
|
axios
|
||||||
|
.patch(
|
||||||
|
`${getBaseURL()}/api/employees`,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
ID: editPopup && editPopup.ID,
|
||||||
|
Vorname: vorname,
|
||||||
|
Nachname: nachname,
|
||||||
|
Geburtstag: showGeburtstag
|
||||||
|
? editPopup && editPopup.Geburtstag
|
||||||
|
? moment(geburtstag).toDate().getTime()
|
||||||
|
: moment(geburtstag).add(1, "day").toDate().getTime()
|
||||||
|
: null,
|
||||||
|
Anstelldatum: showAnstelldatum
|
||||||
|
? editPopup && editPopup.Anstelldatum
|
||||||
|
? moment(anstelldatum).toDate().getTime()
|
||||||
|
: moment(anstelldatum)
|
||||||
|
.add(1, "day")
|
||||||
|
.toDate()
|
||||||
|
.getTime()
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
setEditPopup(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{loading && <CircularProgress size={20} />} Speichern
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() => {
|
||||||
|
setEditPopup(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Backdrop>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DeletePopUp(
|
||||||
|
deletePopup: Types.Employees | false,
|
||||||
|
setDeletePopup: (value: Types.Employees | false) => void
|
||||||
|
) {
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!deletePopup) setLoading(false);
|
||||||
|
}, [deletePopup]);
|
||||||
|
|
||||||
|
if (deletePopup === false) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Backdrop open={Boolean(deletePopup)} sx={{ zIndex: 1000 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "500px",
|
||||||
|
height: "auto",
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "5px",
|
||||||
|
boxShadow: "0 0 10px #00000055",
|
||||||
|
padding: "20px",
|
||||||
|
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "center",
|
||||||
|
|
||||||
|
gap: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontWeight: "bold", fontSize: "30px" }}>
|
||||||
|
Mitarbeiter Löschen
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography>
|
||||||
|
Wollen Sie wirklich den Mitarbeiter{" "}
|
||||||
|
<strong>
|
||||||
|
{deletePopup?.Vorname} {deletePopup?.Nachname}{" "}
|
||||||
|
</strong>
|
||||||
|
löschen?
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
padding: "10px",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() => {
|
||||||
|
setLoading(true);
|
||||||
|
if (deletePopup && !deletePopup.ID) return;
|
||||||
|
axios
|
||||||
|
.delete(`${getBaseURL()}/api/employees/${deletePopup?.ID}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setDeletePopup(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{loading && <CircularProgress size={20} />} Löschen
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() => {
|
||||||
|
setDeletePopup(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Backdrop>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<boolean>(false);
|
||||||
|
|
||||||
|
const [data, setData] = useState<EmployeePartial[] | null>(null);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!uploadPopup) setLoading(false);
|
||||||
|
}, [uploadPopup]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Backdrop open={uploadPopup} sx={{ zIndex: 1000 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "500px",
|
||||||
|
height: "auto",
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "5px",
|
||||||
|
boxShadow: "0 0 10px #00000055",
|
||||||
|
padding: "20px",
|
||||||
|
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "center",
|
||||||
|
|
||||||
|
gap: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontWeight: "bold", fontSize: "30px" }}>
|
||||||
|
CSV Hochladen
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Collapse in={error !== null}>
|
||||||
|
<Alert severity="error">{error}</Alert>
|
||||||
|
</Collapse>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
onChange={(e) => {
|
||||||
|
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<string[]> = 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);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
padding: "10px",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disabled={loading || !data}
|
||||||
|
onClick={() => {
|
||||||
|
setLoading(true);
|
||||||
|
axios.put(`${getBaseURL()}/api/employees`, data, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{loading && <CircularProgress size={20} />} Hochladen
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() => {
|
||||||
|
setUploadPopup(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Backdrop>
|
||||||
|
);
|
||||||
|
}
|
15
frontend/src/types.d.ts
vendored
15
frontend/src/types.d.ts
vendored
@ -1,9 +1,10 @@
|
|||||||
declare namespace Types {
|
declare namespace Types {
|
||||||
interface Worker {
|
interface Employees {
|
||||||
|
ID: string;
|
||||||
Vorname: string;
|
Vorname: string;
|
||||||
Nachname: string;
|
Nachname: string;
|
||||||
Geburtstag: Date;
|
Geburtstag?: Date;
|
||||||
Anstelldatum: Date;
|
Anstelldatum?: Date;
|
||||||
}
|
}
|
||||||
interface User extends UserPermissions {
|
interface User extends UserPermissions {
|
||||||
ID: string;
|
ID: string;
|
||||||
@ -17,12 +18,4 @@ declare namespace Types {
|
|||||||
sponsor_manage: boolean;
|
sponsor_manage: boolean;
|
||||||
user_manage: boolean;
|
user_manage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Sponsor {
|
|
||||||
ID: string;
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
description: string;
|
|
||||||
addedAt: Date;
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user