import React from 'react'; import { YStack, XStack } from '@tamagui/stacks'; import { SizableText as Text } from '@tamagui/text'; import { Button } from '@tamagui/button'; import { Sparkles, Trophy, Play } from 'lucide-react'; import AppShell from '../components/AppShell'; import { useEventData } from '../context/EventDataContext'; import { useTranslation } from '@/guest/i18n/useTranslation'; import { useLocale } from '@/guest/i18n/LocaleContext'; import { fetchTasks } from '../services/tasksApi'; import { fetchEmotions } from '../services/emotionsApi'; import { useAppearance } from '@/hooks/use-appearance'; import { useNavigate } from 'react-router-dom'; import { useGuestTaskProgress } from '@/guest/hooks/useGuestTaskProgress'; type TaskItem = { id: number; title: string; points?: number; description?: string | null; emotion?: string | null; }; export default function TasksScreen() { const { tasksEnabled, token } = useEventData(); const { t } = useTranslation(); const { locale } = useLocale(); const navigate = useNavigate(); const { completedCount } = useGuestTaskProgress(token ?? undefined); const { resolved } = useAppearance(); const isDark = resolved === 'dark'; const cardBorder = isDark ? 'rgba(255, 255, 255, 0.12)' : 'rgba(15, 23, 42, 0.12)'; const cardShadow = isDark ? '0 16px 32px rgba(2, 6, 23, 0.35)' : '0 14px 24px rgba(15, 23, 42, 0.12)'; const mutedButton = isDark ? 'rgba(255, 255, 255, 0.08)' : 'rgba(15, 23, 42, 0.06)'; const mutedButtonBorder = isDark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(15, 23, 42, 0.12)'; const [tasks, setTasks] = React.useState([]); const [highlight, setHighlight] = React.useState(null); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); const [emotions, setEmotions] = React.useState>({}); const progressTotal = tasks.length || 1; const progressPercent = Math.min(100, Math.round((completedCount / progressTotal) * 100)); React.useEffect(() => { if (!token) { setTasks([]); setHighlight(null); return; } let active = true; setLoading(true); setError(null); Promise.all([ fetchTasks(token, { locale, perPage: 12 }), fetchEmotions(token, locale), ]) .then(([taskList, emotionList]) => { if (!active) return; const emotionMap: Record = {}; for (const emotion of emotionList) { const record = emotion as Record; const slug = typeof record.slug === 'string' ? record.slug : ''; const title = typeof record.title === 'string' ? record.title : typeof record.name === 'string' ? record.name : ''; if (slug) { emotionMap[slug] = title || slug; } } setEmotions(emotionMap); const mapped = taskList .map((task) => { const record = task as Record; const id = Number(record.id ?? 0); const title = typeof record.title === 'string' ? record.title : typeof record.name === 'string' ? record.name : ''; if (!id || !title) return null; return { id, title, points: typeof record.points === 'number' ? record.points : undefined, description: typeof record.description === 'string' ? record.description : null, emotion: typeof record.emotion_slug === 'string' ? record.emotion_slug : null, } satisfies TaskItem; }) .filter(Boolean) as TaskItem[]; setTasks(mapped); setHighlight(mapped[0] ?? null); }) .catch((err) => { console.error('Failed to load tasks', err); if (active) { setError(t('tasks.error', 'Tasks could not be loaded.')); } }) .finally(() => { if (active) { setLoading(false); } }); return () => { active = false; }; }, [token, locale, t]); if (!tasksEnabled) { return ( {t('tasks.disabled.title', 'Tasks are disabled')} {t('tasks.disabled.subtitle', 'This event is set to photo-only mode.')} ); } return ( Prompt quest {highlight?.title ?? t('tasks.loading', 'Loading tasks...')} {highlight?.description ?? t('tasks.subtitle', 'Complete this quest to unlock new prompts.')} {t('tasks.page.progressLabel', 'Quest progress')} {highlight ? `${progressPercent}%` : '--'} {t('tasks.page.progressValue', { count: completedCount, total: tasks.length }, '{count}/{total} tasks completed')} {error ? ( {error} ) : null} {tasks.length === 0 && loading ? ( {t('tasks.loading', 'Loading tasks...')} ) : null} {tasks.map((task) => ( {task.title} {task.emotion ? ( {emotions[task.emotion] ?? task.emotion} ) : null} +{task.points ?? 0} ))} ); }