fix: harden booking and meeting flows

This commit is contained in:
2026-09-17 02:42:27 +02:00
parent cb30ecade9
commit 66710fc65c
42 changed files with 683 additions and 608 deletions
+9 -4
View File
@@ -27,6 +27,7 @@ export function BookingWidget({
}) {
const [slotsByDay, setSlotsByDay] = useState<SlotsResponse["slots"]>({});
const [loading, setLoading] = useState(true);
const [loadError, setLoadError] = useState(false);
const [selectedDay, setSelectedDay] = useState<Date | null>(null);
const [selectedSlot, setSelectedSlot] = useState<string | null>(null);
const [appointmentType, setAppointmentType] = useState<"onsite" | "online">("onsite");
@@ -35,12 +36,15 @@ export function BookingWidget({
const [result, setResult] = useState<{ ok: boolean; error?: string } | null>(null);
useEffect(() => {
const controller = new AbortController();
const from = new Date();
const to = new Date(from.getTime() + 28 * 24 * 60 * 60 * 1000);
fetch(`/api/booking/slots?offer=${encodeURIComponent(offerSlug)}&from=${dateKey(from)}&to=${dateKey(to)}`)
.then((res) => res.json())
fetch(`/api/booking/slots?offer=${encodeURIComponent(offerSlug)}&from=${dateKey(from)}&to=${dateKey(to)}`, { signal: controller.signal })
.then((res) => { if (!res.ok) throw new Error("Slots unavailable"); return res.json(); })
.then((data: SlotsResponse) => setSlotsByDay(data.slots ?? {}))
.finally(() => setLoading(false));
.catch(() => { if (!controller.signal.aborted) setLoadError(true); })
.finally(() => { if (!controller.signal.aborted) setLoading(false); });
return () => controller.abort();
}, [offerSlug]);
if (result?.ok) {
@@ -126,11 +130,12 @@ export function BookingWidget({
if (loading) {
return <p className="text-sm text-anouma-plum/70">Verfügbare Termine werden geladen …</p>;
}
if (loadError) return <FormError>Verfügbare Termine konnten nicht geladen werden. Bitte lade die Seite erneut.</FormError>;
return (
<div className="space-y-6">
<div className="grid gap-6 lg:grid-cols-[minmax(0,340px)_1fr]">
<MonthCalendar markers={markers} onSelectDay={setSelectedDay} selectedDay={selectedDay} />
<MonthCalendar markers={markers} onSelectDay={(day) => { setSelectedDay(day); setSelectedSlot(null); }} selectedDay={selectedDay} />
<div>
{!selectedDay && <p className="text-sm text-anouma-plum/70">Wähle einen markierten Tag, um freie Zeiten zu sehen.</p>}
{selectedDay && daySlots.length === 0 && (