import { useState } from "react"; import { useMutation, useQuery } from "@tanstack/react-query"; import { queryClient } from "@/client/rpc-client"; export function BookingForm() { const [selectedTreatment, setSelectedTreatment] = useState(""); const [customerName, setCustomerName] = useState(""); const [customerEmail, setCustomerEmail] = useState(""); const [customerPhone, setCustomerPhone] = useState(""); const [appointmentDate, setAppointmentDate] = useState(""); const [selectedSlotId, setSelectedSlotId] = useState(""); const [notes, setNotes] = useState(""); const [agbAccepted, setAgbAccepted] = useState(false); const [inspirationPhoto, setInspirationPhoto] = useState(""); const [photoPreview, setPhotoPreview] = useState(""); const { data: treatments } = useQuery( queryClient.treatments.live.list.experimental_liveOptions() ); // Lade alle Slots live und filtere freie Slots const { data: allSlots } = useQuery( queryClient.availability.live.list.experimental_liveOptions() ); const freeSlots = (allSlots || []).filter((s) => s.status === "free"); const availableDates = Array.from(new Set(freeSlots.map((s) => s.date))).sort(); const slotsByDate = appointmentDate ? freeSlots.filter((s) => s.date === appointmentDate) : []; const { mutate: createBooking, isPending } = useMutation( queryClient.bookings.create.mutationOptions() ); const selectedTreatmentData = treatments?.find((t) => t.id === selectedTreatment); const availableSlots = (slotsByDate || []).filter((s) => s.status === "free"); const handlePhotoUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; // Check file size (max 5MB) if (file.size > 5 * 1024 * 1024) { alert("Das Foto ist zu groß. Bitte wähle ein Bild unter 5MB."); return; } // Check file type if (!file.type.startsWith('image/')) { alert("Bitte wähle nur Bilddateien aus."); return; } const reader = new FileReader(); reader.onload = (event) => { const result = event.target?.result as string; setInspirationPhoto(result); setPhotoPreview(result); }; reader.readAsDataURL(file); }; const removePhoto = () => { setInspirationPhoto(""); setPhotoPreview(""); // Reset file input const fileInput = document.getElementById('photo-upload') as HTMLInputElement; if (fileInput) fileInput.value = ''; }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!selectedTreatment || !customerName || !customerEmail || !customerPhone || !appointmentDate || !selectedSlotId) { alert("Bitte fülle alle erforderlichen Felder aus"); return; } if (!agbAccepted) { alert("Bitte bestätige die Kenntnisnahme der Allgemeinen Geschäftsbedingungen"); return; } const slot = availableSlots.find((s) => s.id === selectedSlotId); const appointmentTime = slot?.time || ""; createBooking( { treatmentId: selectedTreatment, customerName, customerEmail, customerPhone, appointmentDate, appointmentTime, notes, inspirationPhoto, slotId: selectedSlotId, }, { onSuccess: () => { setSelectedTreatment(""); setCustomerName(""); setCustomerEmail(""); setCustomerPhone(""); setAppointmentDate(""); setSelectedSlotId(""); setNotes(""); setAgbAccepted(false); setInspirationPhoto(""); setPhotoPreview(""); // Reset file input const fileInput = document.getElementById('photo-upload') as HTMLInputElement; if (fileInput) fileInput.value = ''; alert("Buchung erfolgreich erstellt! Wir werden dich kontaktieren, um deinen Termin zu bestätigen."); }, } ); }; // Get minimum date (today) – nicht mehr genutzt, Datumsauswahl erfolgt aus freien Slots const today = new Date().toISOString().split("T")[0]; return (

Buche deine Nagelbehandlung

{/* Treatment Selection */}
{selectedTreatmentData && (

{selectedTreatmentData.description}

)}
{/* Customer Information */}
setCustomerName(e.target.value)} className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500" required />
setCustomerEmail(e.target.value)} className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500" required />
setCustomerPhone(e.target.value)} className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500" required />
{/* Date and Time Selection */}
{availableDates.length === 0 && (

Aktuell keine freien Termine verfügbar.

)}
{/* Notes */}