import React from 'react'; import { Link, useParams } from 'react-router-dom'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import EmotionPicker from '../components/EmotionPicker'; import GalleryPreview from '../components/GalleryPreview'; import { useGuestIdentity } from '../context/GuestIdentityContext'; import { useEventStats } from '../context/EventStatsContext'; import { useEventData } from '../hooks/useEventData'; import { useGuestTaskProgress } from '../hooks/useGuestTaskProgress'; import { Sparkles, UploadCloud, X, Camera, RefreshCw } from 'lucide-react'; import { useTranslation, type TranslateFn } from '../i18n/useTranslation'; import { useEventBranding } from '../context/EventBrandingContext'; import type { EventBranding } from '../types/event-branding'; export default function HomePage() { const { token } = useParams<{ token: string }>(); const { name, hydrated } = useGuestIdentity(); const stats = useEventStats(); const { event } = useEventData(); const { completedCount } = useGuestTaskProgress(token); const { t, locale } = useTranslation(); const { branding } = useEventBranding(); const heroStorageKey = token ? `guestHeroDismissed_${token}` : 'guestHeroDismissed'; const [heroVisible, setHeroVisible] = React.useState(() => { if (typeof window === 'undefined') { return true; } try { return window.sessionStorage.getItem(heroStorageKey) !== '1'; } catch { return true; } }); React.useEffect(() => { if (typeof window === 'undefined') { return; } try { setHeroVisible(window.sessionStorage.getItem(heroStorageKey) !== '1'); } catch { setHeroVisible(true); } }, [heroStorageKey]); const dismissHero = React.useCallback(() => { setHeroVisible(false); if (typeof window === 'undefined') { return; } try { window.sessionStorage.setItem(heroStorageKey, '1'); } catch { // ignore storage exceptions (e.g. private mode) } }, [heroStorageKey]); const displayName = hydrated && name ? name : t('home.fallbackGuestName'); const eventNameDisplay = event?.name ?? t('home.hero.defaultEventName'); const accentColor = branding.primaryColor; const secondaryAccent = branding.secondaryColor; const [missionPreview, setMissionPreview] = React.useState(null); const [missionLoading, setMissionLoading] = React.useState(false); const missionPoolRef = React.useRef([]); const shuffleMissionPreview = React.useCallback(() => { const pool = missionPoolRef.current; if (!pool.length) { setMissionPreview(null); return; } const choice = pool[Math.floor(Math.random() * pool.length)]; setMissionPreview(choice); }, []); React.useEffect(() => { if (!token) return; let cancelled = false; async function loadMissions() { setMissionLoading(true); try { const response = await fetch( `/api/v1/events/${encodeURIComponent(token)}/tasks?locale=${encodeURIComponent(locale)}`, { headers: { Accept: 'application/json', 'X-Locale': locale, }, } ); if (!response.ok) throw new Error('Aufgaben konnten nicht geladen werden.'); const payload = await response.json(); if (cancelled) return; if (Array.isArray(payload) && payload.length) { missionPoolRef.current = payload.map((task: any) => ({ id: Number(task.id), title: task.title ?? 'Mission', description: task.description ?? '', duration: typeof task.duration === 'number' ? task.duration : 3, emotion: task.emotion ?? null, })); shuffleMissionPreview(); } else { missionPoolRef.current = []; setMissionPreview(null); } } catch (err) { if (!cancelled) { console.warn('Mission preview failed', err); missionPoolRef.current = []; setMissionPreview(null); } } finally { if (!cancelled) { setMissionLoading(false); } } } loadMissions(); return () => { cancelled = true; }; }, [shuffleMissionPreview, token, locale]); if (!token) { return null; } return (
{heroVisible && ( )}

Starte dein Fotospiel

Wähle, wie du den nächsten Moment einfängst.

); } function HeroCard({ name, eventName, tasksCompleted, t, branding, onDismiss, ctaLabel, ctaHref, }: { name: string; eventName: string; tasksCompleted: number; t: TranslateFn; branding: EventBranding; onDismiss: () => void; ctaLabel?: string; ctaHref?: string; }) { const heroTitle = t('home.hero.title').replace('{name}', name); const heroDescription = t('home.hero.description').replace('{eventName}', eventName); const progressMessage = tasksCompleted > 0 ? t('home.hero.progress.some').replace('{count}', `${tasksCompleted}`) : t('home.hero.progress.none'); const style = React.useMemo(() => ({ background: `linear-gradient(135deg, ${branding.primaryColor}, ${branding.secondaryColor})`, color: '#ffffff', fontFamily: branding.fontFamily ?? undefined, }), [branding.fontFamily, branding.primaryColor, branding.secondaryColor]); return ( {t('home.hero.subtitle')} {heroTitle}

{heroDescription}

{progressMessage}

{ctaHref && ctaLabel && ( )}
); } type MissionPreview = { id: number; title: string; description?: string; duration?: number; emotion?: { name?: string; slug?: string } | null; }; function MissionActionCard({ token, mission, loading, onShuffle, }: { token: string; mission: MissionPreview | null; loading: boolean; onShuffle: () => void; }) { return (
Mission starten Wir haben bereits eine Aufgabe für dich vorbereitet. Tippe, um direkt loszulegen.
{mission ? ( <>

{mission.title}

{mission.description && (

{mission.description}

)}
{mission.duration ?? 3} Min {mission.emotion?.name && {mission.emotion.name}}
) : (

Ziehe deine erste Mission im Aufgaben-Tab oder lade deine Stimmung hoch.

)}
); } function EmotionActionCard() { return ( Foto nach Gefühlslage Wähle deine Stimmung, wir schlagen dir passende Missionen vor. ); } function UploadActionCard({ token, accentColor, secondaryAccent, }: { token: string; accentColor: string; secondaryAccent: string; }) { return (

Direkt hochladen

Kamera öffnen oder ein Foto aus deiner Galerie wählen.

); }