continued the kita-planer

This commit is contained in:
t.indorf
2026-05-08 14:32:14 +02:00
parent b686e714ff
commit 7aff691803
85 changed files with 9434 additions and 588 deletions
+22 -7
View File
@@ -37,7 +37,7 @@ export async function generatePlanAction() {
lt: new Date(targetYear, targetMonth, 1),
},
},
include: { child: true, user: true },
include: { child: { select: { familyId: true } } },
});
// 2. Werktage holen
@@ -63,8 +63,8 @@ export async function generatePlanAction() {
// Finde die Familie, die am wenigsten oft dran war
// Zufall einbauen bei Gleichstand
const sorted = availForDay.sort((a, b) => {
const countA = familyUsageCount[a.userId] || 0;
const countB = familyUsageCount[b.userId] || 0;
const countA = familyUsageCount[a.child.familyId] || 0;
const countB = familyUsageCount[b.child.familyId] || 0;
if (countA === countB) {
return Math.random() - 0.5; // Zufallsmischung
}
@@ -79,8 +79,8 @@ export async function generatePlanAction() {
});
// Usage-Counter erhöhen
familyUsageCount[selected.userId] =
(familyUsageCount[selected.userId] || 0) + 1;
familyUsageCount[selected.child.familyId] =
(familyUsageCount[selected.child.familyId] || 0) + 1;
}
// 4. In der DB speichern
@@ -161,6 +161,19 @@ export async function updateAssignmentAction(
// Neues anlegen, falls ausgewählt
if (newChildId) {
const child = await tx.child.findFirst({
where: {
id: newChildId,
kitaId,
active: true,
},
select: { id: true },
});
if (!child) {
throw new Error("Kind gehört nicht zu dieser Kita.");
}
await tx.notdienstAssignment.create({
data: {
kitaId,
@@ -174,7 +187,9 @@ export async function updateAssignmentAction(
revalidatePath("/dashboard/notdienst/plan");
return { success: true };
} catch (error: any) {
return { error: error.message || "Update fehlgeschlagen." };
} catch (error) {
return {
error: error instanceof Error ? error.message : "Update fehlgeschlagen.",
};
}
}
+27 -7
View File
@@ -19,9 +19,15 @@ export default async function PlanungsZentralePage() {
where: {
kitaId_year_month: { kitaId, year: targetYear, month: targetMonth },
},
include: {
select: {
id: true,
status: true,
assignments: {
include: { child: { include: { parentLinks: { include: { user: true } } } } },
select: {
id: true,
childId: true,
date: true,
},
},
},
});
@@ -34,16 +40,30 @@ export default async function PlanungsZentralePage() {
// aber für MVP reichen alle aktiven Kinder.
const allChildrenRaw = await prisma.child.findMany({
where: { kitaId, active: true },
include: {
parentLinks: { include: { user: true } },
select: {
id: true,
firstName: true,
lastName: true,
family: {
select: {
name: true,
users: {
select: {
firstName: true,
lastName: true,
},
},
},
},
},
orderBy: { lastName: "asc" },
});
const allChildren = allChildrenRaw.map((c) => {
// Einfachheit halber nehmen wir den ersten verknüpften Elternteil zur Anzeige
const parent = c.parentLinks[0]?.user;
const parentName = parent ? `${parent.firstName} ${parent.lastName}` : "Unbekannt";
const parentName =
c.family.users
.map((parent) => `${parent.firstName} ${parent.lastName}`)
.join(", ") || c.family.name;
return {
id: c.id,
name: `${c.firstName} ${c.lastName}`,
@@ -1,6 +1,6 @@
"use client";
import { useState, useTransition } from "react";
import { useTransition } from "react";
import { format } from "date-fns";
import { de } from "date-fns/locale";
import { NotdienstPlanStatus } from "@prisma/client";