import React from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useQuery } from '@tanstack/react-query'; import { CalendarDays, Image as ImageIcon, ListTodo, QrCode, Settings, Users, Sparkles } from 'lucide-react'; import { YStack, XStack } from '@tamagui/stacks'; import { SizableText as Text } from '@tamagui/text'; import { Pressable } from '@tamagui/react-native-web-lite'; import { MobileShell, renderEventLocation } from './components/MobileShell'; import { MobileCard, CTAButton, KpiTile, ActionTile, PillBadge } from './components/Primitives'; import { adminPath } from '../constants'; import { useEventContext } from '../context/EventContext'; import { getEventStats, EventStats, TenantEvent } from '../api'; import { formatEventDate, resolveEventDisplayName } from '../lib/events'; export default function MobileDashboardPage() { const navigate = useNavigate(); const { t, i18n } = useTranslation('management'); const { events, activeEvent, hasEvents, hasMultipleEvents, isLoading } = useEventContext(); const { data: stats, isLoading: statsLoading } = useQuery({ queryKey: ['mobile', 'dashboard', 'stats', activeEvent?.slug], enabled: Boolean(activeEvent?.slug), queryFn: async () => { if (!activeEvent?.slug) return null; return await getEventStats(activeEvent.slug); }, }); const locale = i18n.language?.startsWith('en') ? 'en-GB' : 'de-DE'; if (isLoading) { return ( {Array.from({ length: 3 }).map((_, idx) => ( ))} ); } if (!hasEvents) { return ( ); } if (hasMultipleEvents && !activeEvent) { return ( ); } return ( activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}/photos`))} onManageTasks={() => activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}/tasks`))} onShowQr={() => activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}/qr`))} /> activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}/members`))} onPrint={() => activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}/qr`))} onInvites={() => activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}/members`))} onSettings={() => activeEvent?.slug && navigate(adminPath(`/mobile/events/${activeEvent.slug}`))} /> ); } function OnboardingEmptyState() { const { t } = useTranslation('management'); const navigate = useNavigate(); return ( {t('events.list.empty.title', 'Create your first event')} {t('events.list.empty.description', 'Start an event to manage tasks, QR posters and uploads.')} navigate(adminPath('/mobile/events/new'))} /> navigate(adminPath('/mobile/events'))} /> {t('events.list.empty.highlights', 'What you can do')} {[ t('events.quick.images', 'Review photos & uploads'), t('events.quick.tasks', 'Assign tasks & challenges'), t('events.quick.qr', 'Share QR posters'), t('events.quick.guests', 'Invite helpers & guests'), ].map((item) => ( {item} ))} ); } function EventPickerList({ events, locale }: { events: TenantEvent[]; locale: string }) { const { t } = useTranslation('management'); const { selectEvent } = useEventContext(); return ( {t('events.detail.pickEvent', 'Select an event')} {events.map((event) => ( selectEvent(event.slug ?? null)} > {resolveEventDisplayName(event)} {formatEventDate(event.event_date, locale) ?? t('events.status.draft', 'Draft')} {event.status === 'published' ? t('events.status.published', 'Live') : t('events.status.draft', 'Draft')} ))} ); } function FeaturedActions({ onReviewPhotos, onManageTasks, onShowQr, }: { onReviewPhotos: () => void; onManageTasks: () => void; onShowQr: () => void; }) { const { t } = useTranslation('management'); const cards = [ { key: 'photos', label: t('events.quick.images', 'Review Photos'), desc: t('events.quick.images.desc', 'Moderate uploads and highlights'), icon: ImageIcon, color: '#0ea5e9', action: onReviewPhotos, }, { key: 'tasks', label: t('events.quick.tasks', 'Manage Tasks & Challenges'), desc: t('events.quick.tasks.desc', 'Assign and track progress'), icon: ListTodo, color: '#22c55e', action: onManageTasks, }, { key: 'qr', label: t('events.quick.qr', 'Show / Share QR Code'), desc: t('events.quick.qr.desc', 'Posters, cards, and links'), icon: QrCode, color: '#f59e0b', action: onShowQr, }, ]; return ( {cards.map((card) => ( {card.label} {card.desc} ˃ ))} ); } function SecondaryGrid({ event, onGuests, onPrint, onInvites, onSettings, }: { event: TenantEvent | null; onGuests: () => void; onPrint: () => void; onInvites: () => void; onSettings: () => void; }) { const { t } = useTranslation('management'); const tiles = [ { icon: Users, label: t('events.quick.guests', 'Guest management'), color: '#60a5fa', action: onGuests, }, { icon: QrCode, label: t('events.quick.prints', 'Print & poster downloads'), color: '#fbbf24', action: onPrint, }, { icon: Sparkles, label: t('events.quick.invites', 'Team / helper invites'), color: '#a855f7', action: onInvites, }, { icon: Settings, label: t('events.quick.settings', 'Event settings'), color: '#10b981', action: onSettings, }, ]; return ( {t('events.quick.more', 'Shortcuts')} {tiles.map((tile) => ( ))} {event ? ( {resolveEventDisplayName(event)} {renderEventLocation(event)} ) : null} ); } function KpiStrip({ event, stats, loading, locale }: { event: TenantEvent | null; stats: EventStats | null | undefined; loading: boolean; locale: string }) { const { t } = useTranslation('management'); if (!event) return null; const kpis = [ { label: t('events.detail.kpi.tasks', 'Open tasks'), value: event.tasks_count ?? '—', icon: ListTodo, }, { label: t('events.detail.kpi.photos', 'Photos'), value: stats?.uploads_total ?? event.photo_count ?? '—', icon: ImageIcon, }, { label: t('events.detail.kpi.guests', 'Guests'), value: event.active_invites_count ?? event.total_invites_count ?? '—', icon: Users, }, ]; return ( {t('dashboard.kpis', 'Key Performance Indicators')} {loading ? ( {Array.from({ length: 3 }).map((_, idx) => ( ))} ) : ( {kpis.map((kpi) => ( ))} )} {formatEventDate(event.event_date, locale) ?? ''} ); } function AlertsAndHints({ event, stats }: { event: TenantEvent | null; stats: EventStats | null | undefined }) { const { t } = useTranslation('management'); if (!event) return null; const alerts: string[] = []; if (stats?.pending_photos) { alerts.push(t('events.alerts.pendingPhotos', '{{count}} new uploads awaiting moderation', { count: stats.pending_photos })); } if (event.tasks_count) { alerts.push(t('events.alerts.tasksOpen', '{{count}} tasks due or open', { count: event.tasks_count })); } if (alerts.length === 0) { return null; } return ( {t('alerts.title', 'Alerts')} {alerts.map((alert) => ( {alert} ))} ); }