'use client' /** * Consent Management Page (SDK Version) * * Admin interface for managing: * - Documents (AGB, Privacy, etc.) * - Document Versions * - Email Templates * - GDPR Processes (Art. 15-21) * - Statistics */ import { useState, useEffect } from 'react' import Link from 'next/link' import { useSDK } from '@/lib/sdk' import StepHeader from '@/components/sdk/StepHeader/StepHeader' // API Proxy URL (avoids CORS issues) const API_BASE = '/api/admin/consent' type Tab = 'documents' | 'versions' | 'emails' | 'gdpr' | 'stats' interface Document { id: string type: string name: string description: string mandatory: boolean created_at: string updated_at: string } interface Version { id: string document_id: string version: string language: string title: string content: string status: string created_at: string } // Email template editor types interface EmailTemplateData { key: string subject: string body: string } export default function ConsentManagementPage() { const { state } = useSDK() const [activeTab, setActiveTab] = useState('documents') const [documents, setDocuments] = useState([]) const [versions, setVersions] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [selectedDocument, setSelectedDocument] = useState('') // Stats state const [consentStats, setConsentStats] = useState<{ activeConsents: number; documentCount: number; openDSRs: number }>({ activeConsents: 0, documentCount: 0, openDSRs: 0 }) // GDPR tab state const [dsrCounts, setDsrCounts] = useState>({}) const [dsrOverview, setDsrOverview] = useState<{ open: number; completed: number; in_progress: number; overdue: number }>({ open: 0, completed: 0, in_progress: 0, overdue: 0 }) // Email template editor state const [editingTemplate, setEditingTemplate] = useState(null) const [previewTemplate, setPreviewTemplate] = useState(null) const [savedTemplates, setSavedTemplates] = useState>({}) // Auth token (in production, get from auth context) const [authToken, setAuthToken] = useState('') useEffect(() => { const token = localStorage.getItem('bp_admin_token') if (token) { setAuthToken(token) } // Load saved email templates from localStorage try { const saved = localStorage.getItem('sdk-email-templates') if (saved) { setSavedTemplates(JSON.parse(saved)) } } catch { /* ignore */ } }, []) useEffect(() => { if (activeTab === 'documents') { loadDocuments() } else if (activeTab === 'versions' && selectedDocument) { loadVersions(selectedDocument) } else if (activeTab === 'stats') { loadStats() } else if (activeTab === 'gdpr') { loadGDPRData() } }, [activeTab, selectedDocument, authToken]) async function loadDocuments() { setLoading(true) setError(null) try { const res = await fetch(`${API_BASE}/documents`, { headers: authToken ? { 'Authorization': `Bearer ${authToken}` } : {} }) if (res.ok) { const data = await res.json() setDocuments(data.documents || []) } else { const errorData = await res.json().catch(() => ({})) setError(errorData.error || 'Fehler beim Laden der Dokumente') } } catch { setError('Verbindungsfehler zum Server') } finally { setLoading(false) } } async function loadVersions(docId: string) { setLoading(true) setError(null) try { const res = await fetch(`${API_BASE}/documents/${docId}/versions`, { headers: authToken ? { 'Authorization': `Bearer ${authToken}` } : {} }) if (res.ok) { const data = await res.json() setVersions(data.versions || []) } else { const errorData = await res.json().catch(() => ({})) setError(errorData.error || 'Fehler beim Laden der Versionen') } } catch { setError('Verbindungsfehler zum Server') } finally { setLoading(false) } } async function loadStats() { try { const token = localStorage.getItem('bp_admin_token') const [statsRes, docsRes] = await Promise.all([ fetch(`${API_BASE}/stats`, { headers: token ? { 'Authorization': `Bearer ${token}` } : {} }), fetch(`${API_BASE}/documents`, { headers: token ? { 'Authorization': `Bearer ${token}` } : {} }), ]) let activeConsents = 0 let documentCount = 0 let openDSRs = 0 if (statsRes.ok) { const statsData = await statsRes.json() activeConsents = statsData.total_consents || statsData.active_consents || 0 } if (docsRes.ok) { const docsData = await docsRes.json() documentCount = (docsData.documents || []).length } // Try to get DSR count try { const dsrRes = await fetch('/api/sdk/v1/dsgvo/dsr', { headers: { 'X-Tenant-ID': localStorage.getItem('bp_tenant_id') || '', 'X-User-ID': localStorage.getItem('bp_user_id') || '', } }) if (dsrRes.ok) { const dsrData = await dsrRes.json() const dsrs = dsrData.dsrs || [] const now = new Date() openDSRs = dsrs.filter((r: any) => r.status !== 'completed' && r.status !== 'rejected').length } } catch { /* DSR endpoint might not be available */ } setConsentStats({ activeConsents, documentCount, openDSRs }) } catch (err) { console.error('Failed to load stats:', err) } } async function loadGDPRData() { try { const res = await fetch('/api/sdk/v1/dsgvo/dsr', { headers: { 'X-Tenant-ID': localStorage.getItem('bp_tenant_id') || '', 'X-User-ID': localStorage.getItem('bp_user_id') || '', } }) if (!res.ok) return const data = await res.json() const dsrs = data.dsrs || [] const now = new Date() // Count per article type const counts: Record = {} const typeMapping: Record = { 'access': '15', 'rectification': '16', 'erasure': '17', 'restriction': '18', 'portability': '20', 'objection': '21', } for (const dsr of dsrs) { if (dsr.status === 'completed' || dsr.status === 'rejected') continue const article = typeMapping[dsr.request_type] if (article) { counts[article] = (counts[article] || 0) + 1 } } setDsrCounts(counts) // Calculate overview const open = dsrs.filter((r: any) => r.status === 'received' || r.status === 'verified').length const completed = dsrs.filter((r: any) => r.status === 'completed').length const in_progress = dsrs.filter((r: any) => r.status === 'in_progress').length const overdue = dsrs.filter((r: any) => { if (r.status === 'completed' || r.status === 'rejected') return false const deadline = r.extended_deadline_at ? new Date(r.extended_deadline_at) : new Date(r.deadline_at) return deadline < now }).length setDsrOverview({ open, completed, in_progress, overdue }) } catch (err) { console.error('Failed to load GDPR data:', err) } } function saveEmailTemplate(template: EmailTemplateData) { const updated = { ...savedTemplates, [template.key]: template } setSavedTemplates(updated) localStorage.setItem('sdk-email-templates', JSON.stringify(updated)) setEditingTemplate(null) } const tabs: { id: Tab; label: string }[] = [ { id: 'documents', label: 'Dokumente' }, { id: 'versions', label: 'Versionen' }, { id: 'emails', label: 'E-Mail Vorlagen' }, { id: 'gdpr', label: 'DSGVO Prozesse' }, { id: 'stats', label: 'Statistiken' }, ] // 16 Lifecycle Email Templates const emailTemplates = [ { name: 'Willkommens-E-Mail', key: 'welcome', category: 'onboarding', description: 'Wird bei Registrierung versendet' }, { name: 'E-Mail Bestaetigung', key: 'email_verification', category: 'onboarding', description: 'Bestaetigungslink fuer E-Mail-Adresse' }, { name: 'Konto aktiviert', key: 'account_activated', category: 'onboarding', description: 'Bestaetigung der Kontoaktivierung' }, { name: 'Passwort zuruecksetzen', key: 'password_reset', category: 'security', description: 'Link zum Zuruecksetzen des Passworts' }, { name: 'Passwort geaendert', key: 'password_changed', category: 'security', description: 'Bestaetigung der Passwortaenderung' }, { name: 'Neue Anmeldung', key: 'new_login', category: 'security', description: 'Benachrichtigung ueber Anmeldung von neuem Geraet' }, { name: '2FA aktiviert', key: '2fa_enabled', category: 'security', description: 'Bestaetigung der 2FA-Aktivierung' }, { name: 'Neue Dokumentversion', key: 'new_document_version', category: 'consent', description: 'Info ueber neue Dokumentversion zur Zustimmung' }, { name: 'Zustimmung erteilt', key: 'consent_given', category: 'consent', description: 'Bestaetigung der erteilten Zustimmung' }, { name: 'Zustimmung widerrufen', key: 'consent_withdrawn', category: 'consent', description: 'Bestaetigung des Widerrufs' }, { name: 'DSR Anfrage erhalten', key: 'dsr_received', category: 'gdpr', description: 'Bestaetigung des Eingangs einer DSGVO-Anfrage' }, { name: 'Datenexport bereit', key: 'export_ready', category: 'gdpr', description: 'Benachrichtigung ueber fertigen Datenexport' }, { name: 'Daten geloescht', key: 'data_deleted', category: 'gdpr', description: 'Bestaetigung der Datenloeschung' }, { name: 'Daten berichtigt', key: 'data_rectified', category: 'gdpr', description: 'Bestaetigung der Datenberichtigung' }, { name: 'Konto deaktiviert', key: 'account_deactivated', category: 'lifecycle', description: 'Konto wurde deaktiviert' }, { name: 'Konto geloescht', key: 'account_deleted', category: 'lifecycle', description: 'Bestaetigung der Kontoloeschung' }, ] // GDPR Article 15-21 Processes const gdprProcesses = [ { article: '15', title: 'Auskunftsrecht', description: 'Recht auf Bestaetigung und Auskunft ueber verarbeitete personenbezogene Daten', actions: ['Datenexport generieren', 'Verarbeitungszwecke auflisten', 'Empfaenger auflisten'], sla: '30 Tage', }, { article: '16', title: 'Recht auf Berichtigung', description: 'Recht auf Berichtigung unrichtiger personenbezogener Daten', actions: ['Daten bearbeiten', 'Aenderungshistorie fuehren', 'Benachrichtigung senden'], sla: '30 Tage', }, { article: '17', title: 'Recht auf Loeschung ("Vergessenwerden")', description: 'Recht auf Loeschung personenbezogener Daten unter bestimmten Voraussetzungen', actions: ['Loeschantrag pruefen', 'Daten loeschen', 'Aufbewahrungsfristen pruefen', 'Loeschbestaetigung senden'], sla: '30 Tage', }, { article: '18', title: 'Recht auf Einschraenkung der Verarbeitung', description: 'Recht auf Markierung von Daten zur eingeschraenkten Verarbeitung', actions: ['Daten markieren', 'Verarbeitung einschraenken', 'Benachrichtigung bei Aufhebung'], sla: '30 Tage', }, { article: '19', title: 'Mitteilungspflicht', description: 'Pflicht zur Mitteilung von Berichtigung, Loeschung oder Einschraenkung an Empfaenger', actions: ['Empfaenger ermitteln', 'Mitteilungen versenden', 'Protokollierung'], sla: 'Unverzueglich', }, { article: '20', title: 'Recht auf Datenuebertragbarkeit', description: 'Recht auf Erhalt der Daten in strukturiertem, maschinenlesbarem Format', actions: ['JSON/CSV Export', 'API-Schnittstelle', 'Direkte Uebertragung'], sla: '30 Tage', }, { article: '21', title: 'Widerspruchsrecht', description: 'Recht auf Widerspruch gegen Verarbeitung aus berechtigtem Interesse oder Direktwerbung', actions: ['Widerspruch erfassen', 'Verarbeitung stoppen', 'Marketing-Opt-out'], sla: 'Unverzueglich', }, ] const emailCategories = [ { key: 'onboarding', label: 'Onboarding', color: 'bg-blue-100 text-blue-700' }, { key: 'security', label: 'Sicherheit', color: 'bg-red-100 text-red-700' }, { key: 'consent', label: 'Zustimmung', color: 'bg-green-100 text-green-700' }, { key: 'gdpr', label: 'DSGVO', color: 'bg-purple-100 text-purple-700' }, { key: 'lifecycle', label: 'Lifecycle', color: 'bg-orange-100 text-orange-700' }, ] return (
{/* Token Input */} {!authToken && (
{ setAuthToken(e.target.value) localStorage.setItem('bp_admin_token', e.target.value) }} />
)} {/* Tabs */}
{tabs.map((tab) => ( ))}
{/* Content */}
{error && (
{error}
)}
{/* Documents Tab */} {activeTab === 'documents' && (

Dokumente verwalten

{loading ? (
Lade Dokumente...
) : documents.length === 0 ? (
Keine Dokumente vorhanden
) : (
{documents.map((doc) => ( ))}
Typ Name Beschreibung Pflicht Erstellt Aktionen
{doc.type} {doc.name} {doc.description} {doc.mandatory ? ( Ja ) : ( Nein )} {new Date(doc.created_at).toLocaleDateString('de-DE')}
)}
)} {/* Versions Tab */} {activeTab === 'versions' && (

Versionen

{selectedDocument && ( )}
{!selectedDocument ? (
Bitte waehlen Sie ein Dokument aus
) : loading ? (
Lade Versionen...
) : versions.length === 0 ? (
Keine Versionen vorhanden
) : (
{versions.map((version) => (
v{version.version} {version.language.toUpperCase()} {version.status}

{version.title}

Erstellt: {new Date(version.created_at).toLocaleDateString('de-DE')}

{version.status === 'draft' && ( )}
))}
)}
)} {/* Emails Tab - 16 Lifecycle Templates */} {activeTab === 'emails' && (

E-Mail Vorlagen

16 Lifecycle-Vorlagen fuer automatisierte Kommunikation

{/* Category Filter */}
Filter: {emailCategories.map((cat) => ( {cat.label} ))}
{/* Templates grouped by category */} {emailCategories.map((category) => (

{category.label}

{emailTemplates .filter((t) => t.category === category.key) .map((template) => (

{template.name}

{template.description}

{savedTemplates[template.key] ? 'Angepasst' : 'Aktiv'}
))}
))}
)} {/* GDPR Processes Tab - Articles 15-21 */} {activeTab === 'gdpr' && (

DSGVO Betroffenenrechte

Artikel 15-21 Prozesse und Vorlagen

{/* Info Banner */}
*

Data Subject Rights (DSR)

Hier verwalten Sie alle DSGVO-Anfragen. Jeder Artikel hat definierte Prozesse, SLAs und automatisierte Workflows.

{/* GDPR Process Cards */}
{gdprProcesses.map((process) => (
{process.article}

{process.title}

Aktiv

{process.description}

{/* Actions */}
{process.actions.map((action, idx) => ( {action} ))}
{/* SLA */}
SLA: {process.sla} | Offene Anfragen: 0 ? 'text-orange-600' : 'text-slate-700'}`}>{dsrCounts[process.article] || 0}
Anfragen
))}
{/* DSR Request Statistics */}

DSR Uebersicht

0 ? 'text-blue-600' : 'text-slate-900'}`}>{dsrOverview.open}
Offen
{dsrOverview.completed}
Erledigt
{dsrOverview.in_progress}
In Bearbeitung
0 ? 'text-red-700' : 'text-slate-400'}`}>{dsrOverview.overdue}
Ueberfaellig
)} {/* Stats Tab */} {activeTab === 'stats' && (

Statistiken

{consentStats.activeConsents}
Aktive Zustimmungen
{consentStats.documentCount}
Dokumente
0 ? 'text-orange-600' : 'text-slate-900'}`}> {consentStats.openDSRs}
Offene DSR-Anfragen

Zustimmungsrate nach Dokument

Diagramm wird in einer zukuenftigen Version verfuegbar sein
)}
{/* Email Template Edit Modal */} {editingTemplate && (

E-Mail Vorlage bearbeiten

setEditingTemplate({ ...editingTemplate, subject: e.target.value })} className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm" />