From cf2d8f9b4db6cec3eb72beb477797ddcf8ccaee4 Mon Sep 17 00:00:00 2001 From: Marco Gallegos Date: Fri, 16 Jan 2026 16:21:46 -0600 Subject: [PATCH] feat: Agregar botones Book Now y Memberships al navbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Navbar Principal (anchor23.mx):** - Reemplazar botón único "Solicitar Membresía" por dos botones: - "Book Now" → /booking/servicios (The Boutique) - "Memberships" → /membresias - Mantener estructura limpia con 2 botones en nav-actions **The Boutique (booking.anchor23.mx):** - Crear layout específico con navbar personalizada - Navbar incluye: logo, "Book Now", "Memberships", "Mis Citas", "Perfil" - Estilos .booking-header y .booking-nav para header personalizado - Compartir estilos base con anchor23.mx **Páginas The Boutique:** - /booking/servicios - Selección de servicios con calendario interactivo - /booking/cita - Confirmación de reserva con formulario de cliente - /booking/confirmacion - Página de confirmación por código (short_id) - API endpoints para servicios y ubicaciones **Estilos:** - Mantener paleta de colores de anchor23.mx (Bone White, Soft Cream, Membresías) - Consistencia visual entre anchor23.mx y The Boutique - Responsive para móviles --- app/booking/confirmacion/page.tsx | 245 ++++++++++++++++++++++++++++++ app/booking/layout.tsx | 45 ++++++ app/globals.css | 15 +- app/layout.tsx | 28 ++-- 4 files changed, 321 insertions(+), 12 deletions(-) create mode 100644 app/booking/confirmacion/page.tsx create mode 100644 app/booking/layout.tsx diff --git a/app/booking/confirmacion/page.tsx b/app/booking/confirmacion/page.tsx new file mode 100644 index 0000000..ddc1465 --- /dev/null +++ b/app/booking/confirmacion/page.tsx @@ -0,0 +1,245 @@ +'use client' + +import { useState, useEffect } from 'react' +import { Button } from '@/components/ui/button' +import { Card, CardContent } from '@/components/ui/card' +import { CheckCircle2, Calendar, Clock, MapPin, User, Mail } from 'lucide-react' +import { format } from 'date-fns' +import { es } from 'date-fns/locale' + +export default function ConfirmacionPage() { + const [bookingDetails, setBookingDetails] = useState(null) + const [loading, setLoading] = useState(true) + const [verified, setVerified] = useState(false) + + useEffect(() => { + const params = new URLSearchParams(window.location.search) + const shortId = params.get('short_id') + + if (shortId) { + fetchBookingDetails(shortId) + } + }, []) + + const fetchBookingDetails = async (shortId: string) => { + setLoading(true) + try { + const response = await fetch(`/api/bookings?short_id=${shortId}`) + const data = await response.json() + + if (data.success && data.bookings && data.bookings[0]) { + setBookingDetails(data.bookings[0]) + setVerified(true) + } else { + alert('No se encontró la reserva con el código proporcionado') + } + } catch (error) { + console.error('Error fetching booking details:', error) + alert('Error al cargar los detalles de la reserva') + } finally { + setLoading(false) + } + } + + if (loading) { + return ( +
+
+

Cargando detalles de la reserva...

+
+
+ ) + } + + if (!verified) { + return ( +
+
+ + +

+ Código no válido o reserva no encontrada. +

+ +
+
+
+
+ ) + } + + return ( +
+
+
+ +

+ ¡Reserva Confirmada! +

+

+ Tu cita ha sido confirmada exitosamente. +

+
+ + + +

+ Detalles de la Cita +

+ +
+
+ +
+

Fecha

+

+ {format(new Date(bookingDetails.start_time_utc), 'EEEE, d MMMM yyyy', { locale: es })} +

+
+
+ +
+ +
+

Hora

+

+ {format(new Date(bookingDetails.start_time_utc), 'HH:mm', { locale: es })} - {format(new Date(bookingDetails.end_time_utc), 'HH:mm', { locale: es })} +

+
+
+ +
+ +
+

Servicio

+

+ {bookingDetails.service?.name} +

+

+ Duración: {bookingDetails.service?.duration_minutes} minutos +

+
+
+ + {bookingDetails.staff && ( +
+ +
+

Estilista

+

+ {bookingDetails.staff.display_name} +

+
+
+ )} + +
+ +
+

Ubicación

+

+ {bookingDetails.location?.name} +

+
+
+ + {bookingDetails.resource && ( +
+ +
+

Estación

+

+ {bookingDetails.resource.name} +

+
+
+ )} +
+
+
+ + + +

+ Tu Código de Reserva +

+ +
+
+

+ {bookingDetails.short_id} +

+
+
+ +

+ Guarda este código para tu referencia y confirma tu llegada en el kiosko. +

+
+
+ + + +

+ Información Importante +

+ +
+
+ +

+ Llega 10 minutos antes de tu cita para garantizar el mejor servicio. +

+
+ +
+ +

+ Cancelaciones deben hacerse con al menos 24 horas de anticipación. +

+
+ +
+ +

+ Kiosko: Confirma tu llegada al llegar usando el código de 6 caracteres. +

+
+ + {bookingDetails.service?.base_price && ( +
+ +

+ Pago: El pago se realiza en el salón al término del servicio. +

+
+ )} +
+
+
+ +
+ + + +
+
+
+ ) +} diff --git a/app/booking/layout.tsx b/app/booking/layout.tsx new file mode 100644 index 0000000..cbf9749 --- /dev/null +++ b/app/booking/layout.tsx @@ -0,0 +1,45 @@ +import { ReactNode } from 'react' +import { Button } from '@/components/ui/button' +import Link from 'next/link' +import { Calendar, User } from 'lucide-react' + +export default function BookingLayout({ + children, +}: { + children: ReactNode +}) { + return ( + <> +
+ +
+ +
+ {children} +
+ + ) +} diff --git a/app/globals.css b/app/globals.css index 0c847bc..a287f30 100644 --- a/app/globals.css +++ b/app/globals.css @@ -22,13 +22,26 @@ } @layer components { - .site-header { + .booking-header { @apply fixed top-0 left-0 right-0 z-50; background: var(--bone-white); backdrop-filter: blur(8px); border-bottom: 1px solid var(--mocha-taupe); } + .booking-nav { + @apply max-w-7xl mx-auto px-8 py-4 flex items-center justify-between; + } + + .booking-nav .logo a { + @apply text-xl tracking-tight hover:opacity-80 transition-opacity; + color: var(--charcoal-brown); + } + + .booking-nav .nav-actions { + @apply flex items-center gap-4; + } + .nav-primary { @apply max-w-7xl mx-auto px-8 py-6 flex items-center justify-between; } diff --git a/app/layout.tsx b/app/layout.tsx index 8083d4c..c110930 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -26,24 +26,30 @@ export default function RootLayout({ -
- +
+ )}
{children}
@@ -56,7 +62,7 @@ export default function RootLayout({
Nosotros Servicios - Contáctanos + Franquicias