// ============================================================ // OSCILADOR — Servicios + Membresías (3 variantes c/u) // ============================================================ // ── Opciones del selector de reservas (BookingOverlay) ── const BOOKING_OPTIONS = [ { tag: "PRÁCTICA", title: "Práctica DJ · 1h", price: "Bs 100", unit: "/hora", detail: "1 hora · CDJ-3000 × 2 + DJM-A9", cta: "Reservar 1 hora", href: CAL_LINKS.practicaDj1h }, { tag: "PRÁCTICA", title: "Práctica DJ · 2h", price: "Bs 200", unit: "/sesión", detail: "2 horas continuas · ideal para sets largos", cta: "Reservar 2 horas", href: CAL_LINKS.practicaDj2h }, { tag: "PRÁCTICA", title: "Práctica DJ · 2 personas · 1h", price: "Bs 150", unit: "/hora", detail: "1 hora · 2 personas juntas · CDJ-3000 × 2 + DJM-A9", cta: "Reservar para 2", href: CAL_LINKS.practicaDj2p }, { tag: "CLASE", title: "Clase / Sesión guiada", price: "Bs 250", unit: "/hora", detail: "1 hora con instructor, técnica y feedback", cta: "Reservar clase", href: CAL_LINKS.claseSesionGuiada }, { tag: "GRABACIÓN", title: "Grabación de set + máster", price: "Bs 200", unit: "/set", detail: "Grabación audio profesional + mastering · máx 2h", cta: "Reservar grabación", href: CAL_LINKS.grabacionSet }, { tag: "MEMBRESÍA", title: "Membresía / Plan mensual", price: "Desde Bs 800", unit: "/mes", detail: "4–20 horas por mes · reserva con prioridad", cta: "Consultar por WhatsApp", href: "https://wa.me/59167165251?text=Hola%2C%20quiero%20consultar%20sobre%20membresías" }, ]; const SERVICIOS_DATA = [ { tag: "PRÁCTICA", bookingTag: "PRÁCTICA", price: "Bs 100", unit: "/hora", title: "Sala de práctica", body: "CDJ-3000 × 2 + DJM-A9. 1 persona Bs 100/h — 2 personas juntas Bs 150/h.", schedule: "LUN–VIE · 11:00–19:00", cta: "Reservar sala", }, { tag: "CLASES", bookingTag: "CLASE", price: "Bs 250", unit: "/hora", title: "Clase personal", body: "Una hora con el instructor. Trabajás tu set en vivo, identificás lo que suena mal y lo corregís en el momento.", schedule: "LUN–VIE · 11:00–19:00", cta: "Reservar clase", }, { tag: "GRUPO", bookingTag: null, price: "Bs 1.200", unit: "/mes", title: "Curso del Mes", body: "Cada mes, un instructor distinto. Grupos reducidos, cupos limitados. Precio de lanzamiento · 20% off.", schedule: "LUN · MIÉ · VIE — POR CONVOCATORIA", cta: "Consultar disponibilidad", }, { tag: "GRABACIÓN", bookingTag: "GRABACIÓN", price: "Bs 200", unit: "/set", title: "Grabación de set", body: "Grabación de audio profesional de tu set + mastering. Máximo 2 horas por sesión.", schedule: "LUN–VIE · CON RESERVA PREVIA", cta: "Reservar grabación", }, { tag: "ALQUILER", bookingTag: null, price: "Bs 2.100", unit: "/noche", title: "Equipos para evento", body: "Todo el equipo para tu evento. Entrega y retirada coordinada.", schedule: "JUE / VIE / SÁB · 20:00–03:00", cta: "Cotizar alquiler", }, ]; function SvcV1Cards() { return (
{SERVICIOS_DATA.map((s, i) => (
{s.tag} 0{i + 1}

{s.title}

{s.price} {s.unit}

{s.body}

{s.tag === "PRÁCTICA" && (

¿Practicas seguido?{" "} { e.preventDefault(); document.getElementById("membresias")?.scrollIntoView({ behavior: "smooth" }); }} style={{ color: "var(--white)", textDecoration: "underline" }} > Ver planes →

)}
))}
); } function SvcV2Rows() { // Rider-style horizontal rows — denser, more technical return (
{SERVICIOS_DATA.map((s, i) => ( ))}
); } function SvcV3Numbered() { // Numbered minimal: huge prices, sparse type return (
{SERVICIOS_DATA.map((s, i) => ( ))}
); } function Servicios({ variant }) { if (variant === "rows") return ; if (variant === "numbered") return ; return ; } // ============================================================ // MEMBRESÍAS // ============================================================ const MEMBERSHIP_DATA = [ { tag: "STARTER", price: "Bs 800", unit: "/mes", desc: "4 clases personales por mes.", bullets: [ "4× clases 1 a 1 (1h c/u)", "Acceso a sala con instructor", "Cancela cuando quieras", ], }, { tag: "BUILDER", price: "Bs 1.000", unit: "/mes", desc: "2 clases + 8 horas de sala por mes.", featured: true, bullets: [ "2× clases personales (1h c/u)", "8h de sala libre por mes", "Reserva con prioridad", "20% off el primer mes en sala", ], }, { tag: "RESIDENTE", price: "Bs 1.500", unit: "/mes", desc: "20 horas de sala por mes.", bullets: [ "20h de sala libre por mes", "Reserva con prioridad", "Acceso a horarios extendidos", ], }, ]; function MemCard({ plan, i }) { return (
{plan.featured && (
MÁS ELEGIDO
)}
{plan.tag} 0{i + 1}/03
{plan.price} {plan.unit}

{plan.desc}

    {plan.bullets.map((b) => (
  • {b}
  • ))}
Consultar {plan.tag}
); } function MemV1Grid() { return (
{MEMBERSHIP_DATA.map((plan, i) => ( ))}
); } function MemV2Stage() { // BUILDER center-stage bigger return (
{MEMBERSHIP_DATA.map((plan, i) => (
))}
); } function MemV3Table() { // Comparison-table rider return (
{/* spec col */}
{MEMBERSHIP_DATA.map((p) => (
{p.tag} {p.featured && MÁS ELEGIDO}
{p.price}{p.unit}
{p.desc}
))}
{["Clases personales", "Horas de sala", "Reserva prioritaria", "Cupo"].map((row, ri) => (
{row}
{MEMBERSHIP_DATA.map((p) => { let v = "—"; if (row === "Clases personales") v = p.tag === "STARTER" ? "4 / mes" : p.tag === "BUILDER" ? "2 / mes" : "—"; if (row === "Horas de sala") v = p.tag === "STARTER" ? "—" : p.tag === "BUILDER" ? "8h / mes" : "20h / mes"; if (row === "Reserva prioritaria") v = p.tag === "STARTER" ? "—" : "Sí"; if (row === "Cupo") v = "Limitado"; return (
{v}
); })}
))}
{MEMBERSHIP_DATA.map((p) => ( ))}
); } function Membresias({ variant }) { if (variant === "stage") return ; if (variant === "table") return ; return ; } // ============================================================ // BOOKING OVERLAY — Selector de reservas (CLA-37 + CLA-38) // ============================================================ function CalBookingPanel({ opt, onClose, onBack }) { const [bookingData, setBookingData] = React.useState(null); React.useEffect(() => { function handleMessage(e) { try { if (!e.origin.includes("cal.com")) return; const msg = typeof e.data === "string" ? JSON.parse(e.data) : e.data; if (!msg) return; console.log("[Cal.com postMessage]", msg.type || msg.action || "(sin type)", msg); const msgType = (msg.type || msg.action || "").toLowerCase(); const isBooking = msgType === "bookingsuccessful" || msgType === "bookingsuccessfulv2"; if (!isBooking) return; const booking = msg?.data?.booking || msg?.data || {}; console.log("[Cal booking object COMPLETO]", JSON.stringify(msg.data)); const startTime = booking.startTime || booking.start_time || booking.startAt || booking.start || msg?.data?.startTime || msg?.data?.start_time || ""; let formattedTime = ""; if (startTime) { try { formattedTime = new Date(startTime).toLocaleString("es-419", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit", }); } catch (_) { formattedTime = startTime; } } const waText = formattedTime ? `Hola, acabo de reservar ${opt.title} en Oscilador Academy para el ${formattedTime}. ¿Me enviás el QR de pago?` : `Hola, acabo de reservar ${opt.title} en Oscilador Academy. ¿Me enviás el QR de pago?`; setBookingData({ formattedTime, waText }); } catch (_) {} } window.addEventListener("message", handleMessage); return () => window.removeEventListener("message", handleMessage); }, []); const embedUrl = `${opt.href}?embed=true&layout=month_view`; const fallbackWaText = `Hola, acabo de reservar ${opt.title} en Oscilador. ¿Me enviás el QR de pago?`; if (bookingData) { return (
e.stopPropagation()}>
RESERVA CONFIRMADA ✓

{opt.title}

{bookingData.formattedTime && (

{bookingData.formattedTime}

)}

Tu hora quedó en el calendario. Ahora confirmá el cupo enviando este mensaje — te mandamos el QR de pago.

QR O TRANSFERENCIA · CONFIRMACIÓN EN MENOS DE 24H
); } return (
e.stopPropagation()}>
RESERVAR {opt.tag}

{opt.title} {opt.price}