feat: Betreuung, Kinderprofile und Aufnahmeverwaltung implementieren

Dashboard mit Abholslots und Filter-Scrolling, Anwesenheit mit Audit-Verlauf sowie Elternanmeldung, Warteliste und bestätigte Aufnahme ergänzen.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Paul SchoeneckandCopilot committed 2026-11-03 08:01:25 +01:00
1 parent 10af6159b4
commit c1513c040b
36 files changed
+2593

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
"use client";
import { useState, useTransition } from "react";
import { Clock3, Plus } from "lucide-react";
import { addSlot, toggleSlot } from "@/app/admission-actions";
import type { PickupSlot } from "@/lib/slots";
import type { ActionResult } from "@/lib/validation";
export function SlotManager({ slots }: { slots: PickupSlot[] }) {
const [message, setMessage] = useState<ActionResult>({});
const [pending, startTransition] = useTransition();
function run(action: () => Promise<ActionResult>) {
setMessage({});
startTransition(async () => {
try { setMessage(await action()); }
catch (error) { console.error("Slot speichern", error); setMessage({ error: "Speichern fehlgeschlagen. Bitte erneut versuchen." }); }
});
}
return <><div className="section-title"><div><span className="eyebrow">GEMEINSAM GUT ORGANISIERT</span><h1>Abholslots</h1><p>Feste Zeitfenster für einen entspannten Abschied.</p></div><Clock3 size={30} /></div>
<div className="info-box"><p>Slots haben keine Kapazitätsgrenze. Ein deaktivierter Slot bleibt in bestehenden Plänen erhalten, wird aber nicht mehr neu angeboten. Für andere Zeiten einen neuen Slot anlegen; individuelle Abholzeiten bleiben möglich.</p></div>
{message.error && <p className="form-error" role="alert">{message.error}</p>}
{message.success && <p className="form-success" role="status">Abholslots gespeichert.</p>}
<section className="slots-management">{slots.map((slot) => <article className="profile-panel slot-management-card" key={slot.id}><Clock3 size={21} />
<div><h2>{slot.start}–{slot.end} Uhr</h2><p className="muted small">{slot.active ? "Für neue Pläne verfügbar" : "Inaktiv · bestehende Pläne bleiben erhalten"}</p></div>
<button className="button secondary" disabled={pending} onClick={() => run(() => toggleSlot({ id: slot.id, active: !slot.active }))}>{slot.active ? "Deaktivieren" : "Aktivieren"}</button></article>)}</section>
<section className="profile-panel"><h2>Neues Abholfenster</h2><form className="inline-form stack" onSubmit={(event) => {
event.preventDefault(); const form = new FormData(event.currentTarget);
run(() => addSlot({ start: form.get("start"), end: form.get("end") }));
}}><label>Beginn<input name="start" type="time" required defaultValue="14:00" /></label><label>Ende<input name="end" type="time" required defaultValue="14:15" /></label>
<button className="button primary" disabled={pending}><Plus size={16} />Slot anlegen</button></form></section>
</>;
}