'use client' import { useEffect, useState, useCallback } from 'react' import { useRouter } from 'next/navigation' import Link from 'next/link' import { ArrowLeft, Download, Search, Loader2, FileText, AlertTriangle } from 'lucide-react' import { useAuth } from '@/components/providers/auth-provider' interface Doc { id: string; type: string; version: string; title: string; url: string | null; isActive: boolean; publishedAt: string; contentHash: string; acceptanceCount: number } interface Miss { type: string; version: string; missing: number } interface Acc { id: string; email: string; name: string; documentType: string; documentVersion: string; context: string; acceptedAt: string; organizationId: string | null; ipAddress: string | null; userAgent: string | null; contentHash: string | null } export default function AdminLegalPage() { const { user, loading, isServerAdmin } = useAuth() const router = useRouter() const [data, setData] = useState<{ documents: Doc[]; totalActiveUsers: number; missing: Miss[] } | null>(null) const [q, setQ] = useState('') const [results, setResults] = useState(null) const [searching, setSearching] = useState(false) useEffect(() => { if (loading) return if (!user || !isServerAdmin()) { router.replace('/app'); return } fetch('/api/admin/legal').then(r => r.json()).then(setData).catch(() => setData(null)) }, [loading, user, isServerAdmin, router]) const search = useCallback(async () => { setSearching(true) try { const res = await fetch(`/api/admin/legal/acceptances?q=${encodeURIComponent(q)}`) const d = await res.json() setResults(d.acceptances || []) } catch { setResults([]) } finally { setSearching(false) } }, [q]) if (loading || !data) { return
} return (
Zur Administration

Rechtsdokumente & Zustimmungen

Aktive Benutzer: {data.totalActiveUsers}. Neue Versionen werden bewusst über src/config/legal.ts{' '} und die Migration veröffentlicht (löst Re-Consent aus).

{/* Fehlende Zustimmungen */} {data.missing.some(m => m.missing > 0) && (
Offene Pflicht-Zustimmungen:
    {data.missing.filter(m => m.missing > 0).map(m => (
  • {m.type} v{m.version}: {m.missing} Benutzer offen
  • ))}
)} {/* Dokumente */}

Dokumentversionen

{data.documents.map(d => ( ))}
Typ Version Veröffentlicht Status Zustimmungen Hash
{d.type} {d.version} {new Date(d.publishedAt).toLocaleDateString('de-CH')} {d.isActive ? aktiv : inaktiv} {d.acceptanceCount} {d.contentHash.slice(0, 12)}…
{/* Suche + Export */}

Zustimmungshistorie

CSV exportieren
{ e.preventDefault(); search() }} className="flex gap-2 mb-3"> setQ(e.target.value)} placeholder="Nach Benutzer (E-Mail/Name) suchen…" className="flex-1 rounded-lg border border-border bg-background px-3 py-2 text-sm" />
{results && ( results.length === 0 ?

Keine Zustimmungen gefunden.

: (
{results.map(a => ( ))}
Zeitpunkt Benutzer Dokument Kontext IP Gerät / Browser
{new Date(a.acceptedAt).toLocaleString('de-CH', { dateStyle: 'short', timeStyle: 'short' })} {a.name}
{a.email}
{a.documentType} v{a.documentVersion}{a.contentHash && <>
{a.contentHash.slice(0, 12)}…}
{a.context} {a.ipAddress || '—'} {a.userAgent || '—'}
) )}
) }