/* booking.jsx — Interactive booking flow for D'SHINE 4 steps: service → date → time → contact */ const { useState: bkUseState, useMemo: bkUseMemo, useEffect: bkUseEffect } = React; const BK_SERVICES = [ { id: "facial", icn: "✦", name: "Cuidado facial", desc: "Limpieza profunda · DermaPen · Hidratación", dur: "60 min", pr: "$180k", }, { id: "laser", icn: "❀", name: "Depilación láser", desc: "Bikini, axilas, piernas y más", dur: "45 min", pr: "Desde $90k", }, { id: "makeup", icn: "✺", name: "Maquillaje social", desc: "Eventos, novias, sesión fotográfica", dur: "75 min", pr: "$150k", }, ]; const BK_SLOTS = [ "08:00", "09:00", "10:00", "11:00", "13:00", "14:00", "15:00", "16:00", "17:00", ]; const MONTHS_ES = [ "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre", ]; const DAY_NAMES = ["L", "M", "M", "J", "V", "S", "D"]; function buildMonthGrid(year, month /* 0-indexed */) { const first = new Date(year, month, 1); // Make Monday the first column. JS getDay: Sun=0..Sat=6 → shift so Mon=0..Sun=6 const firstCol = (first.getDay() + 6) % 7; const daysInMonth = new Date(year, month + 1, 0).getDate(); const cells = []; for (let i = 0; i < firstCol; i++) cells.push({ muted: true }); for (let d = 1; d <= daysInMonth; d++) { cells.push({ day: d, date: new Date(year, month, d) }); } while (cells.length % 7 !== 0) cells.push({ muted: true }); return cells; } function sameDay(a, b) { return a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); } function fmtLongDate(d) { if (!d) return "—"; const wk = ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"][d.getDay()]; return `${wk}, ${d.getDate()} de ${MONTHS_ES[d.getMonth()].toLowerCase()}`; } function Booking() { const today = bkUseMemo(() => { const t = new Date(); t.setHours(0, 0, 0, 0); return t; }, []); const [step, setStep] = bkUseState(1); const [svc, setSvc] = bkUseState(null); const [viewYM, setViewYM] = bkUseState({ y: today.getFullYear(), m: today.getMonth() }); const [date, setDate] = bkUseState(null); const [time, setTime] = bkUseState(null); const [form, setForm] = bkUseState({ name: "", phone: "", notes: "" }); const [done, setDone] = bkUseState(false); // Pre-compute disabled slots for a given date so the UI feels populated but realistic const slotsForDate = bkUseMemo(() => { if (!date) return []; // Seed disabled slots based on date so it's stable & realistic-looking const seed = date.getDate() * 7 + (date.getMonth() + 1) * 13; return BK_SLOTS.map((s, i) => ({ time: s, disabled: ((seed + i * 5) % 7) === 0, })); }, [date]); const grid = bkUseMemo(() => buildMonthGrid(viewYM.y, viewYM.m), [viewYM]); const monthLabel = `${MONTHS_ES[viewYM.m]} ${viewYM.y}`; // Disable months strictly in the past const canPrev = !(viewYM.y === today.getFullYear() && viewYM.m === today.getMonth()); const movePrev = () => { if (!canPrev) return; setViewYM(({ y, m }) => (m === 0 ? { y: y - 1, m: 11 } : { y, m: m - 1 })); }; const moveNext = () => { setViewYM(({ y, m }) => (m === 11 ? { y: y + 1, m: 0 } : { y, m: m + 1 })); }; const isAvailable = (d) => { if (!d) return false; if (d < today) return false; // Sundays unavailable if (d.getDay() === 0) return false; return true; }; const canStep2 = !!svc; const canStep3 = !!date; const canStep4 = !!time; const canFinish = form.name.trim() && form.phone.trim(); const goNext = () => { if (step === 1 && canStep2) setStep(2); else if (step === 2 && canStep3) setStep(3); else if (step === 3 && canStep4) setStep(4); }; const goBack = () => setStep((s) => Math.max(1, s - 1)); const submit = () => { if (!canFinish) return; setDone(true); }; const waUrl = bkUseMemo(() => { const lines = [ "Hola D'SHINE ✨ quiero confirmar mi reserva:", svc ? `• Servicio: ${svc.name}` : "", date ? `• Fecha: ${fmtLongDate(date)}` : "", time ? `• Hora: ${time}` : "", form.name ? `• Nombre: ${form.name}` : "", form.phone ? `• Tel: ${form.phone}` : "", form.notes ? `• Nota: ${form.notes}` : "", ].filter(Boolean).join("\n"); return "https://wa.me/573002031782?text=" + encodeURIComponent(lines); }, [svc, date, time, form]); if (done) { return (
Gracias {form.name.split(" ")[0]}. Para confirmar tu cita de {svc.name.toLowerCase()} el {fmtLongDate(date)} a las {time}, envíanos un toque por WhatsApp.
Confirmar por WhatsAppSelecciona el servicio que quieres reservar
Elige una fecha para tu cita
Atendemos de lunes a sábado, 8:00 am – 7:00 pm. Los puntos dorados indican días con cupos disponibles.
Horarios disponibles · {fmtLongDate(date)}
Cuéntanos un poco sobre ti