import React from 'react'; import { Button } from '@/components/ui/button'; import { createBrowserRouter, Outlet, useParams, Link } from 'react-router-dom'; import Header from './components/Header'; import BottomNav from './components/BottomNav'; import { useEventData } from './hooks/useEventData'; import { AlertTriangle, Loader2 } from 'lucide-react'; import type { FetchEventErrorCode } from './services/eventApi'; import { EventStatsProvider } from './context/EventStatsContext'; import { GuestIdentityProvider } from './context/GuestIdentityContext'; import LandingPage from './pages/LandingPage'; import ProfileSetupPage from './pages/ProfileSetupPage'; import HomePage from './pages/HomePage'; import TaskPickerPage from './pages/TaskPickerPage'; import TaskDetailPage from './pages/TaskDetailPage'; import UploadPage from './pages/UploadPage'; import UploadQueuePage from './pages/UploadQueuePage'; import GalleryPage from './pages/GalleryPage'; import PhotoLightbox from './pages/PhotoLightbox'; import AchievementsPage from './pages/AchievementsPage'; import SlideshowPage from './pages/SlideshowPage'; import SettingsPage from './pages/SettingsPage'; import LegalPage from './pages/LegalPage'; import NotFoundPage from './pages/NotFoundPage'; import { LocaleProvider } from './i18n/LocaleContext'; import { DEFAULT_LOCALE, isLocaleCode } from './i18n/messages'; import { useTranslation, type TranslateFn } from './i18n/useTranslation'; function HomeLayout() { const { token } = useParams(); if (!token) { return (
); } return ( ); } export const router = createBrowserRouter([ { path: '/event', element: }, { path: '/setup/:token', element: , children: [ { index: true, element: }, ], }, { path: '/e/:token', element: , children: [ { index: true, element: }, { path: 'tasks', element: }, { path: 'tasks/:taskId', element: }, { path: 'upload', element: }, { path: 'queue', element: }, { path: 'gallery', element: }, { path: 'photo/:photoId', element: }, { path: 'achievements', element: }, { path: 'slideshow', element: }, ], }, { path: '/settings', element: }, { path: '/legal/:page', element: }, { path: '*', element: }, ]); function EventBoundary({ token }: { token: string }) { const { event, status, error, errorCode } = useEventData(); if (status === 'loading') { return ; } if (status === 'error' || !event) { return ; } const eventLocale = isLocaleCode(event.default_locale) ? event.default_locale : DEFAULT_LOCALE; const localeStorageKey = `guestLocale_event_${event.id ?? token}`; return (
); } function SetupLayout() { const { token } = useParams<{ token: string }>(); if (!token) return null; const { event } = useEventData(); const eventLocale = event && isLocaleCode(event.default_locale) ? event.default_locale : DEFAULT_LOCALE; const localeStorageKey = event ? `guestLocale_event_${event.id}` : `guestLocale_event_${token}`; return (
); } function EventLoadingView() { const { t } = useTranslation(); return (

{t('eventAccess.loading.title')}

{t('eventAccess.loading.subtitle')}

); } interface EventErrorViewProps { code: FetchEventErrorCode | null; message: string | null; } function EventErrorView({ code, message }: EventErrorViewProps) { const { t } = useTranslation(); const content = getErrorContent(t, code, message); return (

{content.title}

{content.description}

{content.hint && (

{content.hint}

)}
{content.ctaHref && content.ctaLabel && ( )}
); } function getErrorContent( t: TranslateFn, code: FetchEventErrorCode | null, message: string | null, ) { const build = (key: string, options?: { ctaHref?: string }) => { const ctaLabel = t(`eventAccess.error.${key}.ctaLabel`, ''); const hint = t(`eventAccess.error.${key}.hint`, ''); return { title: t(`eventAccess.error.${key}.title`), description: message ?? t(`eventAccess.error.${key}.description`), ctaLabel: ctaLabel.trim().length > 0 ? ctaLabel : undefined, ctaHref: options?.ctaHref, hint: hint.trim().length > 0 ? hint : null, }; }; switch (code) { case 'invalid_token': return build('invalid_token', { ctaHref: '/event' }); case 'token_revoked': return build('token_revoked', { ctaHref: '/event' }); case 'token_expired': return build('token_expired', { ctaHref: '/event' }); case 'token_rate_limited': return build('token_rate_limited'); case 'event_not_public': return build('event_not_public'); case 'network_error': return build('network_error'); case 'server_error': return build('server_error'); default: return build('default', { ctaHref: '/event' }); } } function SimpleLayout({ title, children }: { title: string; children: React.ReactNode }) { return (
{children}
); }