import React from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { CheckCircle2, Circle, Loader2, Pencil, Plus, Trash2 } from 'lucide-react'; 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 { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { AdminLayout } from '../components/AdminLayout'; import { createTask, deleteTask, getTasks, PaginationMeta, TenantTask, TaskPayload, updateTask, } from '../api'; import { isAuthError } from '../auth/tokens'; import { buildEngagementTabPath } from '../constants'; type TaskFormState = { title: string; description: string; priority: TaskPayload['priority']; due_date: string; is_completed: boolean; }; const INITIAL_FORM: TaskFormState = { title: '', description: '', priority: 'medium', due_date: '', is_completed: false, }; export type TasksSectionProps = { embedded?: boolean; onNavigateToCollections?: () => void; }; export function TasksSection({ embedded = false, onNavigateToCollections }: TasksSectionProps) { const navigate = useNavigate(); const { t } = useTranslation('common'); const [tasks, setTasks] = React.useState([]); const [meta, setMeta] = React.useState(null); const [page, setPage] = React.useState(1); const [search, setSearch] = React.useState(''); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null); const [dialogOpen, setDialogOpen] = React.useState(false); const [editingTask, setEditingTask] = React.useState(null); const [form, setForm] = React.useState(INITIAL_FORM); const [saving, setSaving] = React.useState(false); React.useEffect(() => { let cancelled = false; setLoading(true); setError(null); getTasks({ page, search: search.trim() || undefined }) .then((result) => { if (cancelled) return; setTasks(result.data); setMeta(result.meta); }) .catch((err) => { if (!isAuthError(err)) { setError('Tasks konnten nicht geladen werden.'); } }) .finally(() => { if (!cancelled) { setLoading(false); } }); return () => { cancelled = true; }; }, [page, search]); const openCreate = React.useCallback(() => { setEditingTask(null); setForm(INITIAL_FORM); setDialogOpen(true); }, []); const openEdit = React.useCallback((task: TenantTask) => { setEditingTask(task); setForm({ title: task.title, description: task.description ?? '', priority: task.priority ?? 'medium', due_date: task.due_date ? task.due_date.slice(0, 10) : '', is_completed: task.is_completed, }); setDialogOpen(true); }, []); const handleNavigateToCollections = React.useCallback(() => { if (onNavigateToCollections) { onNavigateToCollections(); return; } navigate(buildEngagementTabPath('collections')); }, [navigate, onNavigateToCollections]); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); if (!form.title.trim()) { setError('Bitte gib einen Titel ein.'); return; } setSaving(true); setError(null); const payload: TaskPayload = { title: form.title.trim(), description: form.description.trim() || null, priority: form.priority ?? undefined, due_date: form.due_date || undefined, is_completed: form.is_completed, }; try { if (editingTask) { const updated = await updateTask(editingTask.id, payload); setTasks((prev) => prev.map((task) => (task.id === updated.id ? updated : task))); } else { const created = await createTask(payload); setTasks((prev) => [created, ...prev]); } setDialogOpen(false); } catch (err) { if (!isAuthError(err)) { setError('Task konnte nicht gespeichert werden.'); } } finally { setSaving(false); } } async function handleDelete(taskId: number) { if (!window.confirm('Task wirklich löschen?')) { return; } try { await deleteTask(taskId); setTasks((prev) => prev.filter((task) => task.id !== taskId)); } catch (err) { if (!isAuthError(err)) { setError('Task konnte nicht gelöscht werden.'); } } } async function toggleCompletion(task: TenantTask) { if (task.tenant_id === null) { return; } try { const updated = await updateTask(task.id, { is_completed: !task.is_completed }); setTasks((prev) => prev.map((entry) => (entry.id === updated.id ? updated : entry))); } catch (err) { if (!isAuthError(err)) { setError('Status konnte nicht aktualisiert werden.'); } } } const title = embedded ? 'Aufgaben' : 'Task Bibliothek'; const subtitle = embedded ? 'Plane Aufgaben, Aktionen und Highlights für deine Gäste.' : 'Weise Aufgaben zu und tracke Fortschritt rund um deine Events.'; return (
{error && ( Fehler {error} )}
{title} {subtitle}
{ setPage(1); setSearch(event.target.value); }} className="max-w-sm" /> {meta && meta.total > 0 ? (
Seite {meta.current_page} von {meta.last_page} · {meta.total} Einträge
) : null}
{loading ? ( ) : tasks.length === 0 ? ( ) : (
{tasks.map((task) => ( toggleCompletion(task)} onEdit={() => openEdit(task)} onDelete={() => handleDelete(task.id)} /> ))}
)} {meta && meta.last_page > 1 ? (
Insgesamt {meta.total} Aufgaben · Seite {meta.current_page} von {meta.last_page}
) : null}
{editingTask ? 'Task bearbeiten' : 'Neue Task erstellen'}
setForm((prev) => ({ ...prev, title: event.target.value }))} required />
setForm((prev) => ({ ...prev, description: event.target.value }))} placeholder="Was sollen Gäste machen?" />
setForm((prev) => ({ ...prev, due_date: event.target.value }))} />

Bereits erledigt?

Markiere Aufgaben als abgeschlossen, wenn sie nicht mehr sichtbar sein sollen.

setForm((prev) => ({ ...prev, is_completed: checked }))} />
); } export default function TasksPage() { const navigate = useNavigate(); const { t } = useTranslation('management'); const { t: tc } = useTranslation('common'); return ( navigate(buildEngagementTabPath('collections'))} /> ); } function TaskRow({ task, onToggle, onEdit, onDelete, }: { task: TenantTask; onToggle: () => void; onEdit: () => void; onDelete: () => void; }) { const isCompleted = task.is_completed; const statusIcon = isCompleted ? : ; return (
{task.title} {task.priority ? : null} {task.collection_id ? Vorlage #{task.collection_id} : null}
{task.description ?

{task.description}

: null}
); } function PriorityBadge({ priority }: { priority: NonNullable }) { const mapping: Record, { label: string; className: string }> = { low: { label: 'Niedrig', className: 'bg-emerald-50 text-emerald-600' }, medium: { label: 'Mittel', className: 'bg-amber-50 text-amber-600' }, high: { label: 'Hoch', className: 'bg-rose-50 text-rose-600' }, urgent: { label: 'Dringend', className: 'bg-red-50 text-red-600' }, }; const { label, className } = mapping[priority]; return {label}; } function TasksSkeleton() { return (
{Array.from({ length: 4 }).map((_, index) => (
))}
); } function EmptyState({ onCreate }: { onCreate: () => void }) { return (

Noch keine Tasks angelegt

Starte mit einer neuen Aufgabe oder importiere Aufgabenvorlagen, um deine Gäste zu inspirieren.

); }