Files
breakpilot-compliance/admin-compliance/app/sdk/consent-management/page.tsx
Benjamin Admin 5ff65b3402 feat: Consent Migration Phasen 3-6 — Cookie Banner, Deadlines, Public DSR, Integrations
Phase 3 (Cookie Banner): Backend + Frontend existierten bereits —
keine Aenderungen noetig.

Phase 4 (Deadlines): DeadlineTab mit Fristen-Timeline (30 Tage,
4 Erinnerungen, Auto-Sperrung). Backend-Cron in Production via Core.

Phase 5 (Public DSR): PublicFormConfig im DSR Settings-Tab —
konfigurierbare Anfragetypen, Identitaetspflicht, Embed-Code.

Phase 6 (Integrations): IntegrationStubs fuer Matrix, Jitsi, OAuth,
2FA, Notifications — vorbereitet fuer Core-Service-Anbindung.

Consent Management: 2 neue Tabs (Fristen, Integrationen).
DSR: Settings-Tab mit Public Form statt Platzhalter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 00:43:34 +02:00

207 lines
6.8 KiB
TypeScript

'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 } from 'react'
import { useRouter } from 'next/navigation'
import { useSDK } from '@/lib/sdk'
import StepHeader from '@/components/sdk/StepHeader/StepHeader'
import type { Tab, EmailTemplateData } from './_types'
import { useConsentData } from './_hooks/useConsentData'
import { DocumentsTab } from './_components/DocumentsTab'
import { VersionsTab } from './_components/VersionsTab'
import { EmailsTab } from './_components/EmailsTab'
import { GdprTab } from './_components/GdprTab'
import { StatsTab } from './_components/StatsTab'
import { ConsentTemplateCreateModal } from './_components/ConsentTemplateCreateModal'
import { EmailTemplateEditModal, EmailTemplatePreviewModal } from './_components/EmailTemplateModals'
import { DeadlineTab } from './_components/DeadlineTab'
import { IntegrationStubs } from './_components/IntegrationStubs'
export default function ConsentManagementPage() {
const { state } = useSDK()
const router = useRouter()
const [activeTab, setActiveTab] = useState<Tab>('documents')
const [showCreateTemplateModal, setShowCreateTemplateModal] = useState(false)
const [selectedDocument, setSelectedDocument] = useState<string>('')
const [editingTemplate, setEditingTemplate] = useState<EmailTemplateData | null>(null)
const [previewTemplate, setPreviewTemplate] = useState<EmailTemplateData | null>(null)
const {
documents, versions, loading, error, setError,
consentStats, dsrCounts, dsrOverview,
savedTemplates, saveEmailTemplate,
apiEmailTemplates, apiGdprProcesses,
templatesLoading, gdprLoading,
savingTemplateId, savingProcessId,
saveApiEmailTemplate, saveApiGdprProcess,
loadApiEmailTemplates,
submitVersionForReview, approveVersion, rejectVersion, publishVersion,
authToken, setAuthToken,
} = useConsentData(activeTab, selectedDocument)
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' },
{ id: 'deadlines', label: 'Fristen' },
{ id: 'integrations', label: 'Integrationen' },
]
return (
<div className="space-y-6">
<StepHeader stepId="consent-management" showProgress={true} />
{/* Token Input */}
{!authToken && (
<div className="bg-white rounded-xl border border-slate-200 p-4">
<label className="block text-sm font-medium text-slate-700 mb-2">
Admin Token
</label>
<input
type="password"
placeholder="JWT Token eingeben..."
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm"
onChange={(e) => {
setAuthToken(e.target.value)
localStorage.setItem('bp_admin_token', e.target.value)
}}
/>
</div>
)}
{/* Tabs */}
<div>
<div className="flex gap-1 bg-slate-100 p-1 rounded-lg w-fit">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
activeTab === tab.id
? 'bg-white text-slate-900 shadow-sm'
: 'text-slate-600 hover:text-slate-900'
}`}
>
{tab.label}
</button>
))}
</div>
</div>
{/* Content */}
<div>
{error && (
<div className="mb-4 p-4 bg-red-50 border border-red-200 text-red-700 rounded-lg">
{error}
<button
onClick={() => setError(null)}
className="ml-4 text-red-500 hover:text-red-700"
>
X
</button>
</div>
)}
<div className="bg-white rounded-xl border border-slate-200 shadow-sm">
{activeTab === 'documents' && (
<DocumentsTab
loading={loading}
documents={documents}
setSelectedDocument={setSelectedDocument}
setActiveTab={setActiveTab}
/>
)}
{activeTab === 'versions' && (
<VersionsTab
loading={loading}
documents={documents}
versions={versions}
selectedDocument={selectedDocument}
setSelectedDocument={setSelectedDocument}
onSubmitReview={submitVersionForReview}
onApprove={approveVersion}
onReject={rejectVersion}
onPublish={publishVersion}
/>
)}
{activeTab === 'emails' && (
<EmailsTab
apiEmailTemplates={apiEmailTemplates}
templatesLoading={templatesLoading}
savingTemplateId={savingTemplateId}
savedTemplates={savedTemplates}
setShowCreateTemplateModal={setShowCreateTemplateModal}
saveApiEmailTemplate={saveApiEmailTemplate}
setPreviewTemplate={setPreviewTemplate}
setEditingTemplate={setEditingTemplate}
/>
)}
{activeTab === 'gdpr' && (
<GdprTab
router={router}
apiGdprProcesses={apiGdprProcesses}
gdprLoading={gdprLoading}
savingProcessId={savingProcessId}
saveApiGdprProcess={saveApiGdprProcess}
dsrCounts={dsrCounts}
dsrOverview={dsrOverview}
/>
)}
{activeTab === 'stats' && <StatsTab consentStats={consentStats} />}
{activeTab === 'deadlines' && <DeadlineTab />}
{activeTab === 'integrations' && <IntegrationStubs />}
</div>
</div>
{/* Email Template Edit Modal */}
{editingTemplate && (
<EmailTemplateEditModal
editingTemplate={editingTemplate}
onChange={setEditingTemplate}
onClose={() => setEditingTemplate(null)}
onSave={(tpl) => {
saveEmailTemplate(tpl)
setEditingTemplate(null)
}}
/>
)}
{/* Consent Template Create Modal */}
{showCreateTemplateModal && (
<ConsentTemplateCreateModal
onClose={() => setShowCreateTemplateModal(false)}
onSuccess={() => { setShowCreateTemplateModal(false); loadApiEmailTemplates() }}
/>
)}
{/* Email Template Preview Modal */}
{previewTemplate && (
<EmailTemplatePreviewModal
previewTemplate={previewTemplate}
onClose={() => setPreviewTemplate(null)}
/>
)}
</div>
)
}