import React from 'react'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; import { ArrowLeft, Loader2, PlusCircle, Sparkles } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Switch } from '@/components/ui/switch'; import { AdminLayout } from '../components/AdminLayout'; import { assignTasksToEvent, getEvent, getEventTasks, getTasks, updateEvent, TenantEvent, TenantTask, } from '../api'; import { isAuthError } from '../auth/tokens'; import { ADMIN_EVENTS_PATH } from '../constants'; export default function EventTasksPage() { const { t } = useTranslation(['management', 'dashboard']); const params = useParams<{ slug?: string }>(); const [searchParams] = useSearchParams(); const slug = params.slug ?? searchParams.get('slug') ?? null; const navigate = useNavigate(); const [event, setEvent] = React.useState(null); const [assignedTasks, setAssignedTasks] = React.useState([]); const [availableTasks, setAvailableTasks] = React.useState([]); const [selected, setSelected] = React.useState([]); const [loading, setLoading] = React.useState(true); const [saving, setSaving] = React.useState(false); const [modeSaving, setModeSaving] = React.useState(false); const [error, setError] = React.useState(null); const statusLabels = React.useMemo( () => ({ published: t('management.members.statuses.published', 'Veröffentlicht'), draft: t('management.members.statuses.draft', 'Entwurf'), }), [t] ); React.useEffect(() => { if (!slug) { setError(t('management.tasks.errors.missingSlug', 'Kein Event-Slug angegeben.')); setLoading(false); return; } let cancelled = false; (async () => { try { setLoading(true); const eventData = await getEvent(slug); const [eventTasksResponse, libraryTasks] = await Promise.all([ getEventTasks(eventData.id, 1), getTasks({ per_page: 50 }), ]); if (cancelled) return; setEvent(eventData); const assignedIds = new Set(eventTasksResponse.data.map((task) => task.id)); setAssignedTasks(eventTasksResponse.data); const eventTypeId = eventData.event_type_id ?? null; const filteredLibraryTasks = libraryTasks.data.filter((task) => { if (assignedIds.has(task.id)) { return false; } if (eventTypeId && task.event_type_id && task.event_type_id !== eventTypeId) { return false; } return true; }); setAvailableTasks(filteredLibraryTasks); setError(null); } catch (err) { if (!isAuthError(err)) { setError(t('management.tasks.errors.load', 'Event-Tasks konnten nicht geladen werden.')); } } finally { if (!cancelled) { setLoading(false); } } })(); return () => { cancelled = true; }; }, [slug, t]); async function handleAssign() { if (!event || selected.length === 0) return; setSaving(true); try { await assignTasksToEvent(event.id, selected); const refreshed = await getEventTasks(event.id, 1); const assignedIds = new Set(refreshed.data.map((task) => task.id)); setAssignedTasks(refreshed.data); setAvailableTasks((prev) => prev.filter((task) => !assignedIds.has(task.id))); setSelected([]); } catch (err) { if (!isAuthError(err)) { setError(t('management.tasks.errors.assign', 'Tasks konnten nicht zugewiesen werden.')); } } finally { setSaving(false); } } React.useEffect(() => { setSelected((current) => current.filter((taskId) => availableTasks.some((task) => task.id === taskId))); }, [availableTasks]); const isPhotoOnlyMode = event?.engagement_mode === 'photo_only'; async function handleModeChange(checked: boolean) { if (!event || !slug) return; setModeSaving(true); setError(null); try { const nextMode = checked ? 'photo_only' : 'tasks'; const updated = await updateEvent(slug, { settings: { engagement_mode: nextMode, }, }); setEvent(updated); } catch (err) { if (!isAuthError(err)) { setError( checked ? t('management.tasks.errors.photoOnlyEnable', 'Foto-Modus konnte nicht aktiviert werden.') : t('management.tasks.errors.photoOnlyDisable', 'Foto-Modus konnte nicht deaktiviert werden.'), ); } } finally { setModeSaving(false); } } const actions = ( ); return ( {error && ( {t('dashboard.alerts.errorTitle', 'Fehler')} {error} )} {loading ? ( ) : !event ? ( {t('management.tasks.alerts.notFoundTitle', 'Event nicht gefunden')} {t('management.tasks.alerts.notFoundDescription', 'Bitte kehre zur Eventliste zurück.')} ) : ( <> {renderName(event.name, t)} {t('management.tasks.eventStatus', { status: statusLabels[event.status as keyof typeof statusLabels] ?? event.status, })}

{t('management.tasks.modes.title', 'Aufgaben & Foto-Modus')}

{isPhotoOnlyMode ? t( 'management.tasks.modes.photoOnlyHint', 'Der Foto-Modus ist aktiv. Gäste können Fotos hochladen, sehen aber keine Aufgaben.', ) : t( 'management.tasks.modes.tasksHint', 'Aufgaben werden in der Gäste-App angezeigt. Deaktiviere sie für einen reinen Foto-Modus.', )}

{isPhotoOnlyMode ? t('management.tasks.modes.photoOnly', 'Foto-Modus') : t('management.tasks.modes.tasks', 'Aufgaben aktiv')}
{modeSaving ? (
{t('management.tasks.modes.updating', 'Einstellung wird gespeichert ...')}
) : null}

{t('management.tasks.sections.assigned.title', 'Zugeordnete Tasks')}

{assignedTasks.length === 0 ? ( ) : (
{assignedTasks.map((task) => (

{task.title}

{mapPriority(task.priority, t)}
{task.description &&

{task.description}

}
))}
)}

{t('management.tasks.sections.library.title', 'Tasks aus Bibliothek hinzufügen')}

{availableTasks.length === 0 ? ( ) : ( availableTasks.map((task) => ( )) )}
)}
); } function EmptyState({ message }: { message: string }) { return (

{message}

); } function TaskSkeleton() { return (
{Array.from({ length: 2 }).map((_, index) => (
))}
); } function mapPriority(priority: TenantTask['priority'], translate: (key: string, defaultValue: string) => string): string { switch (priority) { case 'low': return translate('management.tasks.priorities.low', 'Niedrig'); case 'high': return translate('management.tasks.priorities.high', 'Hoch'); case 'urgent': return translate('management.tasks.priorities.urgent', 'Dringend'); default: return translate('management.tasks.priorities.medium', 'Mittel'); } } function renderName(name: TenantEvent['name'], translate: (key: string, defaultValue: string) => string): string { if (typeof name === 'string') { return name; } return name?.de ?? name?.en ?? Object.values(name ?? {})[0] ?? translate('management.members.events.untitled', 'Unbenanntes Event'); }