import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import EventDetailClient from './EventDetailClient'; const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://spanglish.com.py'; const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'; interface Event { id: string; title: string; titleEs?: string; description: string; descriptionEs?: string; shortDescription?: string; shortDescriptionEs?: string; startDatetime: string; endDatetime?: string; location: string; locationUrl?: string; price: number; currency: string; capacity: number; status: 'draft' | 'published' | 'unlisted' | 'cancelled' | 'completed' | 'archived'; bannerUrl?: string; availableSeats?: number; bookedCount?: number; createdAt: string; updatedAt: string; } async function getEvent(id: string): Promise { try { const response = await fetch(`${apiUrl}/api/events/${id}`, { next: { revalidate: 60 }, }); if (!response.ok) return null; const data = await response.json(); return data.event || null; } catch { return null; } } export async function generateMetadata({ params }: { params: { id: string } }): Promise { const event = await getEvent(params.id); if (!event) { return { title: 'Event Not Found' }; } const title = event.title; // Use short description if available, otherwise fall back to truncated full description const description = event.shortDescription ? event.shortDescription : (event.description.length > 155 ? event.description.slice(0, 152).trim() + '...' : event.description); // Convert relative banner URL to absolute URL for SEO const imageUrl = event.bannerUrl ? (event.bannerUrl.startsWith('http') ? event.bannerUrl : `${siteUrl}${event.bannerUrl}`) : `${siteUrl}/images/og-image.jpg`; return { title, description, openGraph: { title, description, type: 'website', url: `${siteUrl}/events/${event.id}`, images: [{ url: imageUrl, width: 1200, height: 630, alt: event.title }], }, twitter: { card: 'summary_large_image', title, description, images: [imageUrl], }, alternates: { canonical: `${siteUrl}/events/${event.id}`, }, }; } function generateEventJsonLd(event: Event) { const isPastEvent = new Date(event.startDatetime) < new Date(); const isCancelled = event.status === 'cancelled'; return { '@context': 'https://schema.org', '@type': 'Event', name: event.title, description: event.description, startDate: event.startDatetime, endDate: event.endDatetime || event.startDatetime, eventAttendanceMode: 'https://schema.org/OfflineEventAttendanceMode', eventStatus: isCancelled ? 'https://schema.org/EventCancelled' : 'https://schema.org/EventScheduled', location: { '@type': 'Place', name: event.location, address: { '@type': 'PostalAddress', addressLocality: 'Asunción', addressCountry: 'PY', }, }, organizer: { '@type': 'Organization', name: 'Spanglish', url: siteUrl, }, offers: { '@type': 'Offer', price: event.price, priceCurrency: event.currency, availability: Math.max(0, (event.capacity ?? 0) - (event.bookedCount ?? 0)) > 0 ? 'https://schema.org/InStock' : 'https://schema.org/SoldOut', url: `${siteUrl}/events/${event.id}`, validFrom: new Date().toISOString(), }, image: event.bannerUrl || `${siteUrl}/images/og-image.jpg`, url: `${siteUrl}/events/${event.id}`, }; } export default async function EventDetailPage({ params }: { params: { id: string } }) { const event = await getEvent(params.id); if (!event) { notFound(); } const jsonLd = generateEventJsonLd(event); return ( <>