feat: complete notdienst planning, quick wins and notifications

This commit is contained in:
t.indorf
2026-10-12 15:34:09 +02:00
parent b915857951
commit 00f602a7aa
50 changed files with 2443 additions and 513 deletions
+8 -3
View File
@@ -11,6 +11,8 @@ import { requireRole } from "@/lib/auth-utils";
import { getAppEmailConfigError, sendAppEmail } from "@/lib/mail";
import { rateLimit } from "@/lib/rate-limit";
import { prisma } from "@/lib/prisma";
import { assertChildrenRemovable } from "@/lib/notdienst-planning";
import { UserFacingError, publicActionError } from "@/lib/action-error";
const INVITE_TOKEN_TTL_DAYS = 7;
const BASE_URL =
@@ -387,6 +389,9 @@ export async function updateFamilyAction(rawPayload: unknown) {
}
await prisma.$transaction(async (tx) => {
await assertChildrenRemovable(tx, kitaId, familyId, removedChildIds);
const removed = await tx.child.count({ where: { kitaId, familyId, id: { in: removedChildIds } } });
if (removed !== removedChildIds.length) throw new UserFacingError("Mindestens ein Kind gehört nicht zu dieser Familie.");
await tx.family.update({
where: { id: familyId },
data: { name: familyName },
@@ -460,7 +465,7 @@ export async function updateFamilyAction(rawPayload: unknown) {
},
});
}
});
}, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable });
} catch (error) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
@@ -469,8 +474,8 @@ export async function updateFamilyAction(rawPayload: unknown) {
return { error: "Mindestens eine E-Mail-Adresse existiert bereits." };
}
console.error("Fehler beim Aktualisieren der Familie:", error);
return { error: "Familie konnte nicht aktualisiert werden." };
if (!(error instanceof UserFacingError)) console.error("Fehler beim Aktualisieren der Familie:", error);
return { error: publicActionError(error, "Familie konnte nicht aktualisiert werden.") };
}
const emailError = await sendInviteJobs(kita.name, inviteJobs);