Add timewish routes to backend and frontend; implement routing and UI components for timewish settings
This commit is contained in:
167
backend/src/services/TimewishService.js
Normal file
167
backend/src/services/TimewishService.js
Normal file
@@ -0,0 +1,167 @@
|
||||
const database = require('../config/database');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
/**
|
||||
* Service-Klasse für Zeitwünsche (Timewish)
|
||||
* Verwaltet gewünschte Arbeitszeiten pro Wochentag und Zeitraum
|
||||
*/
|
||||
class TimewishService {
|
||||
/**
|
||||
* Holt alle Zeitwünsche eines Users
|
||||
* @param {number} userId - Benutzer-ID
|
||||
* @returns {Promise<Array>} Array von Zeitwünschen
|
||||
*/
|
||||
async getAllTimewishes(userId) {
|
||||
const { Timewish } = database.getModels();
|
||||
|
||||
const timewishes = await Timewish.findAll({
|
||||
where: {
|
||||
user_id: userId
|
||||
},
|
||||
order: [['day', 'ASC'], ['start_date', 'DESC']],
|
||||
raw: true
|
||||
});
|
||||
|
||||
// Konvertiere DB-Format zu Frontend-Format
|
||||
const dayNames = {
|
||||
1: 'Montag',
|
||||
2: 'Dienstag',
|
||||
3: 'Mittwoch',
|
||||
4: 'Donnerstag',
|
||||
5: 'Freitag',
|
||||
6: 'Samstag',
|
||||
7: 'Sonntag'
|
||||
};
|
||||
|
||||
const wishtypeNames = {
|
||||
0: 'Kein Wunsch',
|
||||
1: 'Frei',
|
||||
2: 'Arbeit'
|
||||
};
|
||||
|
||||
return timewishes.map(tw => ({
|
||||
id: tw.id,
|
||||
day: tw.day,
|
||||
dayName: dayNames[tw.day] || `Tag ${tw.day}`,
|
||||
wishtype: tw.wishtype,
|
||||
wishtypeName: wishtypeNames[tw.wishtype] || 'Unbekannt',
|
||||
hours: tw.hours,
|
||||
startDate: tw.start_date,
|
||||
endDate: tw.end_date
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Zeitwunsch
|
||||
* @param {number} userId - Benutzer-ID
|
||||
* @param {number} day - Wochentag (1=Mo, 7=So)
|
||||
* @param {number} wishtype - Typ (0=Kein Wunsch, 1=Frei, 2=Arbeit)
|
||||
* @param {number} hours - Stunden (nur bei wishtype=2)
|
||||
* @param {string} startDate - Startdatum (YYYY-MM-DD)
|
||||
* @param {string} endDate - Enddatum (YYYY-MM-DD, optional)
|
||||
* @returns {Promise<Object>} Erstellter Zeitwunsch
|
||||
*/
|
||||
async createTimewish(userId, day, wishtype, hours, startDate, endDate) {
|
||||
const { Timewish } = database.getModels();
|
||||
|
||||
// Validierung
|
||||
if (day < 1 || day > 7) {
|
||||
throw new Error('Wochentag muss zwischen 1 (Montag) und 7 (Sonntag) liegen');
|
||||
}
|
||||
|
||||
if (wishtype < 0 || wishtype > 2) {
|
||||
throw new Error('Ungültiger Wunschtyp');
|
||||
}
|
||||
|
||||
if (wishtype === 2 && (!hours || hours < 0 || hours > 24)) {
|
||||
throw new Error('Arbeitsstunden müssen zwischen 0 und 24 liegen');
|
||||
}
|
||||
|
||||
if (!startDate) {
|
||||
throw new Error('Startdatum ist erforderlich');
|
||||
}
|
||||
|
||||
// Prüfe auf Überschneidungen
|
||||
const overlapping = await Timewish.findOne({
|
||||
where: {
|
||||
user_id: userId,
|
||||
day: day,
|
||||
[Op.or]: [
|
||||
// Fall 1: Neuer Eintrag hat kein Enddatum (gilt ab start_date)
|
||||
endDate ? {} : {
|
||||
[Op.or]: [
|
||||
// Bestehender Eintrag hat kein Enddatum UND start_date <= neuer start_date
|
||||
{
|
||||
end_date: null,
|
||||
start_date: { [Op.lte]: startDate }
|
||||
},
|
||||
// Bestehender Eintrag hat Enddatum UND überlappt
|
||||
{
|
||||
end_date: { [Op.gte]: startDate }
|
||||
}
|
||||
]
|
||||
},
|
||||
// Fall 2: Neuer Eintrag hat Enddatum
|
||||
endDate ? {
|
||||
[Op.or]: [
|
||||
// Bestehender Eintrag hat kein Enddatum UND start_date <= neues end_date
|
||||
{
|
||||
end_date: null,
|
||||
start_date: { [Op.lte]: endDate }
|
||||
},
|
||||
// Bestehender Eintrag hat Enddatum UND überlappt
|
||||
{
|
||||
start_date: { [Op.lte]: endDate },
|
||||
end_date: { [Op.gte]: startDate }
|
||||
}
|
||||
]
|
||||
} : {}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (overlapping) {
|
||||
throw new Error(`Überschneidung mit bestehendem Zeitwunsch: ${overlapping.start_date} - ${overlapping.end_date || 'unbegrenzt'}`);
|
||||
}
|
||||
|
||||
const timewish = await Timewish.create({
|
||||
user_id: userId,
|
||||
day,
|
||||
wishtype,
|
||||
hours: wishtype === 2 ? hours : null,
|
||||
start_date: startDate,
|
||||
end_date: endDate || null,
|
||||
version: 0
|
||||
});
|
||||
|
||||
// Formatiere für Response
|
||||
const allTimewishes = await this.getAllTimewishes(userId);
|
||||
return allTimewishes.find(tw => tw.id === timewish.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht einen Zeitwunsch
|
||||
* @param {number} userId - Benutzer-ID
|
||||
* @param {number} timewishId - Timewish-ID
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async deleteTimewish(userId, timewishId) {
|
||||
const { Timewish } = database.getModels();
|
||||
|
||||
const timewish = await Timewish.findByPk(timewishId);
|
||||
|
||||
if (!timewish) {
|
||||
throw new Error('Zeitwunsch nicht gefunden');
|
||||
}
|
||||
|
||||
// Prüfe Berechtigung
|
||||
if (timewish.user_id !== userId) {
|
||||
throw new Error('Keine Berechtigung für diesen Eintrag');
|
||||
}
|
||||
|
||||
await timewish.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new TimewishService();
|
||||
|
||||
Reference in New Issue
Block a user