'use client' /** * Einwilligungsverwaltung - User Consent Management * * Zentrale Uebersicht aller Nutzer-Einwilligungen aus: * - Website * - App * - PWA * * Kategorien: Marketing, Statistik, Cookies, Rechtliche Dokumente */ import { useState, useEffect } from 'react' import { PagePurpose } from '@/components/common/PagePurpose' const API_BASE = '/api/admin/consent' type Tab = 'overview' | 'documents' | 'cookies' | 'marketing' | 'audit' interface ConsentStats { total_users: number consented_users: number consent_rate: number pending_consents: number } interface AuditEntry { id: string user_id: string action: string entity_type: string entity_id: string details: Record ip_address: string created_at: string } interface ConsentSummary { category: string total: number accepted: number declined: number pending: number rate: number } export default function EinwilligungenPage() { const [activeTab, setActiveTab] = useState('overview') const [stats, setStats] = useState(null) const [auditLog, setAuditLog] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [authToken, setAuthToken] = useState('') useEffect(() => { const token = localStorage.getItem('bp_admin_token') if (token) { setAuthToken(token) } }, []) useEffect(() => { if (activeTab === 'overview') { loadStats() } else if (activeTab === 'audit') { loadAuditLog() } }, [activeTab, authToken]) async function loadStats() { setLoading(true) setError(null) try { const res = await fetch(`${API_BASE}/stats`, { headers: authToken ? { 'Authorization': `Bearer ${authToken}` } : {} }) if (res.ok) { const data = await res.json() setStats(data) } else { setError('Fehler beim Laden der Statistiken') } } catch { setError('Verbindungsfehler') } finally { setLoading(false) } } async function loadAuditLog() { setLoading(true) setError(null) try { const res = await fetch(`${API_BASE}/audit-log?limit=50`, { headers: authToken ? { 'Authorization': `Bearer ${authToken}` } : {} }) if (res.ok) { const data = await res.json() setAuditLog(data.entries || []) } else { setError('Fehler beim Laden des Audit-Logs') } } catch { setError('Verbindungsfehler') } finally { setLoading(false) } } // Mock data for consent summary (in production, this comes from API) const consentSummary: ConsentSummary[] = [ { category: 'AGB', total: 1250, accepted: 1248, declined: 0, pending: 2, rate: 99.8 }, { category: 'Datenschutz', total: 1250, accepted: 1245, declined: 3, pending: 2, rate: 99.6 }, { category: 'Cookies (Notwendig)', total: 1250, accepted: 1250, declined: 0, pending: 0, rate: 100 }, { category: 'Cookies (Analyse)', total: 1250, accepted: 892, declined: 358, pending: 0, rate: 71.4 }, { category: 'Cookies (Marketing)', total: 1250, accepted: 456, declined: 794, pending: 0, rate: 36.5 }, { category: 'Newsletter', total: 1250, accepted: 312, declined: 938, pending: 0, rate: 25.0 }, ] const tabs: { id: Tab; label: string }[] = [ { id: 'overview', label: 'Uebersicht' }, { id: 'documents', label: 'Dokumenten-Consents' }, { id: 'cookies', label: 'Cookie-Consents' }, { id: 'marketing', label: 'Marketing-Consents' }, { id: 'audit', label: 'Audit-Trail' }, ] const getActionLabel = (action: string) => { const labels: Record = { 'consent_given': 'Zustimmung erteilt', 'consent_withdrawn': 'Zustimmung widerrufen', 'cookie_consent_updated': 'Cookie-Einstellungen aktualisiert', 'data_access': 'Datenzugriff', 'data_export_requested': 'Datenexport angefordert', 'data_deletion_requested': 'Loeschung angefordert', 'account_suspended': 'Account gesperrt', 'account_restored': 'Account wiederhergestellt', } return labels[action] || action } const getActionColor = (action: string) => { if (action.includes('given') || action.includes('restored')) return 'bg-green-100 text-green-700' if (action.includes('withdrawn') || action.includes('deleted') || action.includes('suspended')) return 'bg-red-100 text-red-700' return 'bg-blue-100 text-blue-700' } return (
{/* Quick Stats */}
{stats?.total_users || 1250}
Registrierte Nutzer
{stats?.consented_users || 1245}
Mit Zustimmung
{stats?.pending_consents || 5}
Ausstehend
{stats?.consent_rate?.toFixed(1) || 99.6}%
Zustimmungsrate
{/* Tabs */}
{tabs.map((tab) => ( ))}
{error && (
{error}
)} {/* Content */}
{/* Overview Tab */} {activeTab === 'overview' && (

Consent-Uebersicht nach Kategorie

{consentSummary.map((item) => (

{item.category}

= 90 ? 'bg-green-100 text-green-700' : item.rate >= 50 ? 'bg-yellow-100 text-yellow-700' : 'bg-red-100 text-red-700' }`}> {item.rate}% Zustimmung
= 90 ? 'bg-green-500' : item.rate >= 50 ? 'bg-yellow-500' : 'bg-red-500'}`} style={{ width: `${item.rate}%` }} />
Gesamt: {item.total}
Akzeptiert: {item.accepted}
Abgelehnt: {item.declined}
Ausstehend: {item.pending}
))}
{/* Export Button */}
)} {/* Documents Tab */} {activeTab === 'documents' && (

Dokumenten-Einwilligungen

{/* Sample data - in production, this comes from API */} {[ { id: 'usr_123', doc: 'AGB', version: 'v2.1.0', status: 'active', date: '2024-12-15', source: 'Website' }, { id: 'usr_124', doc: 'Datenschutz', version: 'v3.0.0', status: 'active', date: '2024-12-15', source: 'App' }, { id: 'usr_125', doc: 'AGB', version: 'v2.1.0', status: 'withdrawn', date: '2024-12-14', source: 'PWA' }, ].map((consent, idx) => ( ))}
Nutzer-ID Dokument Version Status Datum Quelle
{consent.id} {consent.doc} {consent.version} {consent.status === 'active' ? 'Aktiv' : 'Widerrufen'} {consent.date} {consent.source}
)} {/* Cookies Tab */} {activeTab === 'cookies' && (

Cookie-Einwilligungen

{[ { name: 'Notwendige Cookies', key: 'necessary', mandatory: true, rate: 100, description: 'Erforderlich fuer Grundfunktionen' }, { name: 'Funktionale Cookies', key: 'functional', mandatory: false, rate: 82.3, description: 'Verbesserte Nutzererfahrung' }, { name: 'Analyse Cookies', key: 'analytics', mandatory: false, rate: 71.4, description: 'Anonyme Nutzungsstatistiken' }, { name: 'Marketing Cookies', key: 'marketing', mandatory: false, rate: 36.5, description: 'Personalisierte Werbung' }, ].map((category) => (

{category.name}

{category.description}

{category.mandatory && ( Pflicht )}
= 80 ? 'bg-green-500' : category.rate >= 50 ? 'bg-yellow-500' : 'bg-orange-500'}`} style={{ width: `${category.rate}%` }} />
{category.rate}%
))}

Cookie-Banner Einstellungen

Das Cookie-Banner wird auf allen Plattformen (Website, App, PWA) einheitlich angezeigt. Nutzer koennen ihre Praeferenzen jederzeit in den Einstellungen aendern.

)} {/* Marketing Tab */} {activeTab === 'marketing' && (

Marketing-Einwilligungen

{[ { name: 'E-Mail Newsletter', rate: 25.0, total: 1250, subscribed: 312 }, { name: 'Push-Benachrichtigungen', rate: 45.2, total: 1250, subscribed: 565 }, { name: 'Personalisierte Werbung', rate: 18.5, total: 1250, subscribed: 231 }, ].map((channel) => (

{channel.name}

{channel.rate}%
{channel.subscribed} von {channel.total} Nutzern
))}

Opt-Out Anfragen (letzte 30 Tage)

23
Newsletter
45
Push
12
Werbung
)} {/* Audit Tab */} {activeTab === 'audit' && (

Consent Audit-Trail

{loading ? (
Lade Audit-Log...
) : (
{(auditLog.length > 0 ? auditLog : [ // Sample data { id: '1', user_id: 'usr_123', action: 'consent_given', entity_type: 'document', entity_id: 'doc_agb', details: {}, ip_address: '192.168.1.1', created_at: '2024-12-15T10:30:00Z' }, { id: '2', user_id: 'usr_124', action: 'cookie_consent_updated', entity_type: 'cookie', entity_id: 'analytics', details: {}, ip_address: '192.168.1.2', created_at: '2024-12-15T10:25:00Z' }, { id: '3', user_id: 'usr_125', action: 'consent_withdrawn', entity_type: 'document', entity_id: 'doc_newsletter', details: {}, ip_address: '192.168.1.3', created_at: '2024-12-15T10:20:00Z' }, ]).map((entry) => (
{getActionLabel(entry.action)} {entry.user_id}
{new Date(entry.created_at).toLocaleString('de-DE')}
Entity: {entry.entity_type} / {entry.entity_id} | IP: {entry.ip_address}
))}
)}
)}
{/* GDPR Notice */}

DSGVO-Hinweis

Alle Einwilligungen werden revisionssicher gespeichert und koennen jederzeit nachgewiesen werden. Nutzer koennen ihre Einwilligungen gemaess Art. 7 Abs. 3 DSGVO jederzeit widerrufen.

) }