Add cleaning-calendar and cleaning-absences endpoints

This commit is contained in:
Giuseppe Lombardo 2026-08-12 19:37:04 +00:00
parent dbf670a0b3
commit 9c99d3b631

View File

@ -160,3 +160,121 @@ cleaningTasksRouter.patch(
} }
}, },
); );
// ----------------------------------------------------------------------------
// KALENDERÜBERSICHT (Putz-Zuständigkeiten + Abwesenheiten)
//
// Wer wann für welchen Bereich zuständig ist, ist eine gemeinschaftliche
// Organisationsinfo und daher für ALLE eingeloggten Nutzer (auch Mieter)
// sichtbar — anders als z. B. Miethöhe oder private Zimmer-Tickets.
// ----------------------------------------------------------------------------
const ABSENCE_SELECT = {
id: true,
startDate: true,
endDate: true,
note: true,
user: { select: { id: true, fullName: true } },
};
// GET /cleaning-calendar?from=YYYY-MM-DD&to=YYYY-MM-DD
// Liefert alle Putzaufgaben + alle Abwesenheiten im Zeitraum (für alle Rollen sichtbar).
cleaningTasksRouter.get(
'/cleaning-calendar',
requireAuth,
async (req: AuthedRequest, res: Response) => {
const { from, to } = req.query;
const fromDate = typeof from === 'string' && !Number.isNaN(Date.parse(from)) ? new Date(from) : undefined;
const toDate = typeof to === 'string' && !Number.isNaN(Date.parse(to)) ? new Date(to) : undefined;
const taskWhere: Record<string, unknown> = {};
if (fromDate || toDate) {
taskWhere.dueDate = {
...(fromDate ? { gte: fromDate } : {}),
...(toDate ? { lte: toDate } : {}),
};
}
const absenceWhere: Record<string, unknown> = {};
if (fromDate || toDate) {
// Überlappung: Abwesenheit endet nicht vor "from" und beginnt nicht nach "to"
absenceWhere.AND = [
fromDate ? { endDate: { gte: fromDate } } : {},
toDate ? { startDate: { lte: toDate } } : {},
];
}
const [tasks, absences] = await Promise.all([
prisma.cleaningTask.findMany({
where: taskWhere,
orderBy: [{ dueDate: 'asc' }],
select: TASK_SELECT,
}),
prisma.cleaningAbsence.findMany({
where: absenceWhere,
orderBy: [{ startDate: 'asc' }],
select: ABSENCE_SELECT,
}),
]);
res.status(200).json({ tasks, absences });
},
);
// POST /cleaning-absences — Mieter trägt eigene Abwesenheit ein (Urlaub, "kann nicht" ...).
// Vermieter/Admin können Abwesenheiten für jeden Mieter anlegen (z. B. auf Zuruf).
cleaningTasksRouter.post(
'/cleaning-absences',
requireAuth,
async (req: AuthedRequest, res: Response) => {
const isLandlord = req.user!.role === 'LANDLORD' || req.user!.role === 'ADMIN';
const { startDate, endDate, note } = req.body || {};
let { userId } = req.body || {};
if (!isLandlord) {
userId = req.user!.id; // Mieter dürfen nur für sich selbst eintragen
} else if (!userId || typeof userId !== 'string') {
return res.status(400).json({ error: 'userId ist erforderlich' });
}
if (!startDate || Number.isNaN(Date.parse(startDate))) {
return res.status(400).json({ error: 'startDate (Datum) ist erforderlich' });
}
if (!endDate || Number.isNaN(Date.parse(endDate))) {
return res.status(400).json({ error: 'endDate (Datum) ist erforderlich' });
}
if (new Date(endDate) < new Date(startDate)) {
return res.status(400).json({ error: 'endDate darf nicht vor startDate liegen' });
}
const absence = await prisma.cleaningAbsence.create({
data: {
userId,
startDate: new Date(startDate),
endDate: new Date(endDate),
note: typeof note === 'string' && note.trim() ? note.trim().slice(0, 280) : null,
},
select: ABSENCE_SELECT,
});
res.status(201).json({ absence });
},
);
// DELETE /cleaning-absences/:id — eigener Eintrag löschbar, oder Vermieter/Admin jederzeit.
cleaningTasksRouter.delete(
'/cleaning-absences/:id',
requireAuth,
async (req: AuthedRequest, res: Response) => {
const absence = await prisma.cleaningAbsence.findUnique({ where: { id: req.params.id } });
if (!absence) return res.status(404).json({ error: 'Abwesenheit nicht gefunden' });
const isLandlord = req.user!.role === 'LANDLORD' || req.user!.role === 'ADMIN';
if (!isLandlord && absence.userId !== req.user!.id) {
return res.status(403).json({ error: 'Du kannst nur deine eigenen Abwesenheiten löschen' });
}
await prisma.cleaningAbsence.delete({ where: { id: req.params.id } });
res.status(204).send();
},
);