"use client"; import { useEffect, useState } from "react"; import { MonthCalendar, type CalendarMarker } from "./MonthCalendar"; import { ResendVerificationButton } from "@/components/auth/ResendVerificationButton"; type SlotsResponse = { durationMinutes: number; slots: Record }; function dateKey(d: Date) { return d.toISOString().slice(0, 10); } function fmtTime(iso: string) { return new Date(iso).toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }); } function fmtDate(iso: string) { return new Date(iso).toLocaleDateString("de-DE", { weekday: "long", day: "2-digit", month: "long" }); } export function BookingWidget({ offerSlug, isLoggedIn, isVerified, }: { offerSlug: string; isLoggedIn: boolean; isVerified: boolean; }) { const [slotsByDay, setSlotsByDay] = useState({}); const [loading, setLoading] = useState(true); const [selectedDay, setSelectedDay] = useState(null); const [selectedSlot, setSelectedSlot] = useState(null); const [appointmentType, setAppointmentType] = useState<"onsite" | "online">("onsite"); const [message, setMessage] = useState(""); const [submitting, setSubmitting] = useState(false); const [result, setResult] = useState<{ ok: boolean; error?: string } | null>(null); useEffect(() => { 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()) .then((data: SlotsResponse) => setSlotsByDay(data.slots ?? {})) .finally(() => setLoading(false)); }, [offerSlug]); if (result?.ok) { return (

Deine Anfrage

{selectedSlot && (

{fmtDate(selectedSlot)}, {fmtTime(selectedSlot)} Uhr

)}

Status: Termin vorgeschlagen

Der Termin ist noch nicht verbindlich. Du erhältst eine E-Mail, sobald Anna den Termin bestätigt.

); } if (!isLoggedIn) { return (

Melde dich an oder erstelle ein Konto, um einen Termin anzufragen.

); } if (!isVerified) { return (

Bitte bestätige zuerst deine E-Mail-Adresse.

Erst danach kannst du einen Termin anfragen.

); } const markers: CalendarMarker[] = Object.keys(slotsByDay).map((key) => ({ date: new Date(key), status: "public" })); const daySlots = selectedDay ? (slotsByDay[dateKey(selectedDay)] ?? []) : []; async function submit() { if (!selectedSlot) return; setSubmitting(true); setResult(null); try { const res = await fetch("/api/booking/request", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ offerSlug, start: selectedSlot, appointmentType, message }), }); const data = await res.json().catch(() => ({})); if (!res.ok) { setResult({ ok: false, error: data.error || "Anfrage fehlgeschlagen." }); setSubmitting(false); return; } setResult({ ok: true }); } catch { setResult({ ok: false, error: "Verbindung fehlgeschlagen." }); setSubmitting(false); } } if (loading) { return

Verfügbare Termine werden geladen …

; } return (
{!selectedDay &&

Wähle einen markierten Tag, um freie Zeiten zu sehen.

} {selectedDay && daySlots.length === 0 && (

An diesem Tag ist leider kein Termin frei.

)} {selectedDay && daySlots.length > 0 && (

{fmtDate(daySlots[0].start)}

{daySlots.map((slot) => ( ))}
)}
{selectedSlot && (

Ausgewählt: {fmtDate(selectedSlot)}, {fmtTime(selectedSlot)} Uhr

Terminart