'use client'; import { useState, useEffect } from 'react'; import Link from 'next/link'; import Image from 'next/image'; import { useLanguage } from '@/context/LanguageContext'; import { eventsApi, Event } from '@/lib/api'; import { formatPrice } from '@/lib/utils'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import ShareButtons from '@/components/ShareButtons'; import { CalendarIcon, MapPinIcon, UserGroupIcon, ArrowLeftIcon, MinusIcon, PlusIcon, } from '@heroicons/react/24/outline'; interface EventDetailClientProps { eventId: string; initialEvent: Event; } export default function EventDetailClient({ eventId, initialEvent }: EventDetailClientProps) { const { t, locale } = useLanguage(); const [event, setEvent] = useState(initialEvent); const [mounted, setMounted] = useState(false); const [ticketQuantity, setTicketQuantity] = useState(1); // Ensure consistent hydration by only rendering dynamic content after mount useEffect(() => { setMounted(true); }, []); // Refresh event data on client for real-time availability useEffect(() => { eventsApi.getById(eventId) .then(({ event }) => setEvent(event)) .catch(console.error); }, [eventId]); // Spots left: never negative; sold out when confirmed >= capacity const spotsLeft = Math.max(0, event.capacity - (event.bookedCount ?? 0)); const isSoldOut = (event.bookedCount ?? 0) >= event.capacity; const maxTickets = isSoldOut ? 0 : Math.max(1, spotsLeft); const decreaseQuantity = () => { setTicketQuantity(prev => Math.max(1, prev - 1)); }; const increaseQuantity = () => { setTicketQuantity(prev => Math.min(maxTickets, prev + 1)); }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString(locale === 'es' ? 'es-ES' : 'en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }); }; const formatTime = (dateStr: string) => { return new Date(dateStr).toLocaleTimeString(locale === 'es' ? 'es-ES' : 'en-US', { hour: '2-digit', minute: '2-digit', }); }; const isCancelled = event.status === 'cancelled'; // Only calculate isPastEvent after mount to avoid hydration mismatch const isPastEvent = mounted ? new Date(event.startDatetime) < new Date() : false; const canBook = !isSoldOut && !isCancelled && !isPastEvent && event.status === 'published'; // Booking card content - reused for mobile and desktop positions const BookingCardContent = () => ( <>

{t('events.details.price')}

{event.price === 0 ? t('events.details.free') : formatPrice(event.price, event.currency)}

{event.price > 0 && (

{locale === 'es' ? 'por persona' : 'per person'}

)}
{/* Ticket Quantity Selector */} {canBook && !event.externalBookingEnabled && (
{ticketQuantity}
{ticketQuantity > 1 && event.price > 0 && (

{locale === 'es' ? 'Total' : 'Total'}: {formatPrice(event.price * ticketQuantity, event.currency)}

)}
)} {canBook ? ( event.externalBookingEnabled && event.externalBookingUrl ? ( ) : ( ) ) : ( )} {!event.externalBookingEnabled && (

{spotsLeft} / {event.capacity} {t('events.details.spotsLeft')}

)} ); return (
{t('common.back')}
{/* Event Details */}
{/* Top section: Image + Event Info side by side on desktop */}
{/* Image - smaller on desktop, side by side */} {event.bannerUrl ? (
{`${event.title}
) : (
)} {/* Event title and key info */}

{locale === 'es' && event.titleEs ? event.titleEs : event.title}

{isCancelled && ( {t('events.details.cancelled')} )} {isSoldOut && !isCancelled && ( {t('events.details.soldOut')} )}

{t('events.details.date')}

{formatDate(event.startDatetime)}

{t('events.details.time')}

{formatTime(event.startDatetime)} {event.endDatetime && ` - ${formatTime(event.endDatetime)}`}

{t('events.details.location')}

{event.location}

{event.locationUrl && ( View on map )}
{!event.externalBookingEnabled && (

{t('events.details.capacity')}

{spotsLeft} / {event.capacity} {t('events.details.spotsLeft')}

)}
{/* Mobile Booking Card - shown between event details and description on mobile */} {/* Description section - separate card below */}

About this event

{locale === 'es' && event.descriptionEs ? event.descriptionEs : event.description}

{/* Social Sharing */}
{/* Desktop Booking Card - hidden on mobile, shown in sidebar on desktop */}
); }