Add Stargil Nails logo and favicon
- Replace emoji icons with Stargil Nails logo in header and loading spinner - Add favicon.png to public directory - Copy logo to public/assets for browser access - Update vite.config.ts to serve public directory - Add favicon link to HTML head section
This commit is contained in:
@@ -14,18 +14,23 @@ export function BookingForm() {
|
||||
const { data: treatments } = useQuery(
|
||||
queryClient.treatments.live.list.experimental_liveOptions()
|
||||
);
|
||||
const { data: slotsByDate } = useQuery(
|
||||
appointmentDate
|
||||
? queryClient.availability.live.byDate.experimental_liveOptions(appointmentDate)
|
||||
: queryClient.availability.live.byDate.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 selectedTreatmentData = treatments?.find((t) => t.id === selectedTreatment);
|
||||
const availableSlots = (slotsByDate || []).filter((s) => s.status === "free");
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -33,33 +38,36 @@ export function BookingForm() {
|
||||
alert("Bitte fülle alle erforderlichen Felder aus");
|
||||
return;
|
||||
}
|
||||
const slot = availableSlots.find(s => s.id === selectedSlotId);
|
||||
const slot = availableSlots.find((s) => s.id === selectedSlotId);
|
||||
const appointmentTime = slot?.time || "";
|
||||
createBooking({
|
||||
treatmentId: selectedTreatment,
|
||||
customerName,
|
||||
customerEmail,
|
||||
customerPhone,
|
||||
appointmentDate,
|
||||
appointmentTime,
|
||||
notes,
|
||||
slotId: selectedSlotId,
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
setSelectedTreatment("");
|
||||
setCustomerName("");
|
||||
setCustomerEmail("");
|
||||
setCustomerPhone("");
|
||||
setAppointmentDate("");
|
||||
setSelectedSlotId("");
|
||||
setNotes("");
|
||||
alert("Buchung erfolgreich erstellt! Wir werden dich kontaktieren, um deinen Termin zu bestätigen.");
|
||||
createBooking(
|
||||
{
|
||||
treatmentId: selectedTreatment,
|
||||
customerName,
|
||||
customerEmail,
|
||||
customerPhone,
|
||||
appointmentDate,
|
||||
appointmentTime,
|
||||
notes,
|
||||
slotId: selectedSlotId,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
setSelectedTreatment("");
|
||||
setCustomerName("");
|
||||
setCustomerEmail("");
|
||||
setCustomerPhone("");
|
||||
setAppointmentDate("");
|
||||
setSelectedSlotId("");
|
||||
setNotes("");
|
||||
alert("Buchung erfolgreich erstellt! Wir werden dich kontaktieren, um deinen Termin zu bestätigen.");
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
// Get minimum date (today)
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
// Get minimum date (today) – nicht mehr genutzt, Datumsauswahl erfolgt aus freien Slots
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-6">
|
||||
@@ -134,16 +142,22 @@ export function BookingForm() {
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Gewünschtes Datum *
|
||||
Datum (nur freie Termine) *
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
<select
|
||||
value={appointmentDate}
|
||||
onChange={(e) => setAppointmentDate(e.target.value)}
|
||||
min={today}
|
||||
onChange={(e) => { setAppointmentDate(e.target.value); setSelectedSlotId(""); }}
|
||||
className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500"
|
||||
required
|
||||
/>
|
||||
>
|
||||
<option value="">Datum auswählen</option>
|
||||
{availableDates.map((d) => (
|
||||
<option key={d} value={d}>{d}</option>
|
||||
))}
|
||||
</select>
|
||||
{availableDates.length === 0 && (
|
||||
<p className="mt-2 text-sm text-gray-500">Aktuell keine freien Termine verfügbar.</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
|
Reference in New Issue
Block a user