feat(kalender): Kalender mit Urlauben und Feiertagen fuer alle

Neuer Menuepunkt "Kalender" fuer alle Rollen: genehmigte Urlaube aller
Mitarbeiter, auch in der Zukunft, dazu Feiertage. Monatsansicht (Standard)
und Zeitleiste, filterbar nach Team und Name.

- Eigene Tabelle pulse_calendar_days, gefuellt von lib/calendarSync.js im
  HRworks-Lauf (Fenster bis 400 Tage voraus). Buchungen entstehen weiter
  erst am jeweiligen Tag.
- Nur validatedOk und nur freigegebene Arten (calendar_types, Haken in den
  HRworks-Einstellungen). Krankmeldungen werden dafuer nicht abgefragt.
- GET /api/calendar fuer alle Angemeldeten, ohne Mails und Profilbilder.
- Timer laeuft zusaetzlich um 12:00 Uhr.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
schakal00783
2026-09-25 11:37:26 +02:00
co-authored by Claude Opus 5.5
parent 6ae5a01bda
commit c0eb00faee
21 changed files with 996 additions and 33 deletions
+11
View File
@@ -162,6 +162,9 @@ export class Hrworks {
sick_leaves: (events.sickLeaves || []).map((e) => e?.id).filter(Boolean),
// Feiertage tragen keine id, nur das Vorhandensein zaehlt.
holiday: Array.isArray(events.holidays) && events.holidays.length > 0,
// Fuer den Kalender; wie der Eintrag genau aussieht, ist nicht
// dokumentiert - fehlt der Name, heisst er dort schlicht "Feiertag".
holiday_name: holidayName(events.holidays),
});
}
}
@@ -169,6 +172,14 @@ export class Hrworks {
}
}
export function holidayName(holidays) {
for (const h of Array.isArray(holidays) ? holidays : []) {
const name = typeof h === 'string' ? h : h?.name || h?.description || h?.title;
if (typeof name === 'string' && name.trim()) return name.trim().slice(0, 160);
}
return null;
}
/** { person: [{ absences: [...] }] } -> [{ person, ...absence }] */
function flatten(data, key) {
const out = [];