'use client' import { useEffect, useState } from 'react' import Image from 'next/image' import dynamic from 'next/dynamic' import { useBack } from '@/hooks/useBack' import { useVisitor } from '@/context/VisitorContext' import { t, tPlain, ui } from '@/lib/i18n' import type { SectionDTO, EventAgendaDTO } from '@/lib/api/types' import AppBar from '@/components/ui/AppBar' import { trackEvent } from '@/lib/stats' import { getAgendaEvents } from '@/lib/api/client' const EventMiniMap = dynamic(() => import('./agenda/EventMiniMap'), { ssr: false, loading: () => (
Chargement…
), }) interface Props { section: SectionDTO slug: string configId: string languages: string[] apiKey: string } function formatMonthHeader(year: number, month: number, lang: string): string { const name = new Date(year, month, 1).toLocaleDateString(lang.toLowerCase(), { month: 'long' }) return name.charAt(0).toUpperCase() + name.slice(1) + ' ' + year } function eventImage(e: EventAgendaDTO): string | undefined { return e.resource?.url } function eventCoords(e: EventAgendaDTO): { lat: number; lng: number } | null { const c = e.address?.geometry?.coordinates if (!Array.isArray(c) || c.length < 2) return null return { lat: c[1], lng: c[0] } } function fullAddress(e: EventAgendaDTO): string { const a = e.address if (!a) return '' return [ [a.streetNumber, a.streetName].filter(Boolean).join(' '), [a.postCode, a.city].filter(Boolean).join(' '), a.country, ].filter(Boolean).join(', ') } function youtubeEmbedUrl(idOrUrl: string): string { if (idOrUrl.includes('youtube.com') || idOrUrl.includes('youtu.be')) { const m = idOrUrl.match(/(?:v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/) if (m) return `https://www.youtube.com/embed/${m[1]}` return idOrUrl } return `https://www.youtube.com/embed/${idOrUrl}` } export default function AgendaSection({ section, configId, languages, apiKey }: Props) { const { language, setAvailableLanguages, instanceId } = useVisitor() const back = useBack() const [events, setEvents] = useState([]) useEffect(() => { setAvailableLanguages([]) }, [languages]) useEffect(() => { getAgendaEvents(section.id, language, apiKey).then(setEvents).catch(() => setEvents([])) }, [section.id, language, apiKey]) const now = new Date() const [selectedMonth, setSelectedMonth] = useState(now.getMonth()) const [selectedYear, setSelectedYear] = useState(now.getFullYear()) const [selected, setSelected] = useState(null) const filtered = events .filter((e) => { if (!e.dateFrom) return false const d = new Date(e.dateFrom) return d.getMonth() === selectedMonth && d.getFullYear() === selectedYear }) .sort((a, b) => new Date(a.dateFrom!).getTime() - new Date(b.dateFrom!).getTime()) function prevMonth() { if (selectedMonth === 0) { setSelectedMonth(11); setSelectedYear(y => y - 1) } else setSelectedMonth(m => m - 1) } function nextMonth() { if (selectedMonth === 11) { setSelectedMonth(0); setSelectedYear(y => y + 1) } else setSelectedMonth(m => m + 1) } return (
{/* Month selector */}
{formatMonthHeader(selectedYear, selectedMonth, language)}
{/* Events grid */}
{filtered.length === 0 ? (

{ui('noEventsThisMonth', language)}

) : (
{filtered.map((event) => { const img = eventImage(event) return ( ) })}
)}
{/* Event detail popup */} {selected && ( setSelected(null)} /> )}
) } function EventDetail({ event, language, onClose, }: { event: EventAgendaDTO language: string onClose: () => void }) { useEffect(() => { document.body.style.overflow = 'hidden' return () => { document.body.style.overflow = '' } }, []) const img = eventImage(event) const coords = eventCoords(event) const address = fullAddress(event) const yt = event.idVideoYoutube const videoLink = event.videoLink const videoResource = event.videoResource?.url const cardStyle = { background: '#fff', border: '1px solid #EFEAE2', borderRadius: 16, boxShadow: '0 6px 16px -12px rgba(0,0,0,0.3)', } return (
{img && (

{tPlain(event.label, language)}

)}
{!img && (

{tPlain(event.label, language)}

)} {event.dateFrom && (
{new Date(event.dateFrom).toLocaleDateString(language.toLowerCase(), { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })}
{event.dateTo && event.dateTo !== event.dateFrom && (
→ {new Date(event.dateTo).toLocaleDateString(language.toLowerCase(), { day: 'numeric', month: 'long', year: 'numeric' })}
)}
)} {t(event.description, language) && (
)} {/* Video */} {(yt || videoLink || videoResource) && (
{yt ? (