feat: show family assignment counts in notdienst planning dropdown and support editing unassigned days in published plans
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useTransition } from "react";
|
||||
import { useMemo, useState, useTransition } from "react";
|
||||
import { format } from "date-fns";
|
||||
import { de } from "date-fns/locale";
|
||||
import { NotdienstPlanStatus } from "@prisma/client";
|
||||
@@ -41,11 +41,13 @@ interface PlanViewProps {
|
||||
date: string;
|
||||
assignmentId: string | null;
|
||||
childId: string | null;
|
||||
isOriginallyUnassigned?: boolean;
|
||||
}[];
|
||||
allChildren: {
|
||||
id: string;
|
||||
name: string;
|
||||
parentName: string;
|
||||
familyId: string;
|
||||
}[];
|
||||
familyStatuses: {
|
||||
id: string;
|
||||
@@ -140,7 +142,7 @@ export function PlanView({
|
||||
};
|
||||
|
||||
const handleAssignmentChange = (date: string, newChildId: string) => {
|
||||
if (!planId || status !== "DRAFT") return;
|
||||
if (!planId || (status !== "DRAFT" && status !== "PUBLISHED")) return;
|
||||
const valueToSet = newChildId === "empty" ? null : newChildId;
|
||||
|
||||
startTransition(async () => {
|
||||
@@ -567,6 +569,31 @@ function ManualAssignmentTable({
|
||||
isPending: boolean;
|
||||
onAssignmentChange: (date: string, newChildId: string) => void;
|
||||
}) {
|
||||
// Map childId to familyId for quick lookup
|
||||
const childFamilyMap = useMemo(() => {
|
||||
const map = new Map<string, string>();
|
||||
allChildren.forEach((child) => {
|
||||
if (child.familyId) {
|
||||
map.set(child.id, child.familyId);
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}, [allChildren]);
|
||||
|
||||
// Compute family assignment counts in real-time based on current selections
|
||||
const familyAssignmentCounts = useMemo(() => {
|
||||
const counts = new Map<string, number>();
|
||||
days.forEach((day) => {
|
||||
if (day.childId) {
|
||||
const famId = childFamilyMap.get(day.childId);
|
||||
if (famId) {
|
||||
counts.set(famId, (counts.get(famId) ?? 0) + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
return counts;
|
||||
}, [days, childFamilyMap]);
|
||||
|
||||
return (
|
||||
<Card className="overflow-hidden p-0">
|
||||
<div className="grid grid-cols-[1fr_2fr] border-b border-[var(--hairline-soft)] bg-[var(--surface-2)] p-4 text-[11px] font-semibold uppercase text-[var(--ink-muted)] [letter-spacing:0.12em]">
|
||||
@@ -590,22 +617,33 @@ function ManualAssignmentTable({
|
||||
{format(dateObj, "EE, dd.MM.", { locale: de })}
|
||||
</div>
|
||||
<div>
|
||||
{isDraft ? (
|
||||
<select
|
||||
className="w-full max-w-sm rounded-lg border border-[var(--hairline)] bg-[var(--surface)] px-3 py-1.5 text-sm text-[var(--ink)] ring-offset-[var(--surface)] hover:border-[var(--accent-mid)] focus-visible:border-[var(--accent)] focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-[var(--focus-ring)]"
|
||||
value={day.childId || "empty"}
|
||||
disabled={isPending}
|
||||
onChange={(event) =>
|
||||
onAssignmentChange(day.date, event.target.value)
|
||||
}
|
||||
>
|
||||
<option value="empty">-- Unbesetzt --</option>
|
||||
{allChildren.map((child) => (
|
||||
<option key={child.id} value={child.id}>
|
||||
{child.parentName} ({child.name})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{isDraft || day.isOriginallyUnassigned ? (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<select
|
||||
className="w-full max-w-sm rounded-lg border border-[var(--hairline)] bg-[var(--surface)] px-3 py-1.5 text-sm text-[var(--ink)] ring-offset-[var(--surface)] hover:border-[var(--accent-mid)] focus-visible:border-[var(--accent)] focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-[var(--focus-ring)]"
|
||||
value={day.childId || "empty"}
|
||||
disabled={isPending}
|
||||
onChange={(event) =>
|
||||
onAssignmentChange(day.date, event.target.value)
|
||||
}
|
||||
>
|
||||
<option value="empty">-- Unbesetzt --</option>
|
||||
{allChildren.map((child) => {
|
||||
const famId = child.familyId;
|
||||
const count = famId ? (familyAssignmentCounts.get(famId) ?? 0) : 0;
|
||||
return (
|
||||
<option key={child.id} value={child.id}>
|
||||
{child.parentName} ({child.name}) — {count}x
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
{!isDraft && (
|
||||
<span className="text-[11px] font-semibold text-[oklch(0.60_0.18_45)] bg-[oklch(0.95_0.02_45)] border border-[oklch(0.85_0.05_45)] px-2 py-0.5 rounded-md shrink-0">
|
||||
Nachträglich änderbar
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
) : assignedChild ? (
|
||||
<span className="text-sm text-[var(--ink)]">
|
||||
{assignedChild.parentName}{" "}
|
||||
|
||||
Reference in New Issue
Block a user