Agent-completed splits committed after agents hit rate limits before committing their work. All 4 pages now under 500 LOC: - consent-management: 1303 -> 193 LOC (+ 7 _components, _hooks, _data, _types) - control-library: 1210 -> 298 LOC (+ _components, _types) - incidents: 1150 -> 373 LOC (+ _components) - training: 1127 -> 366 LOC (+ _components) Verification: next build clean (142 pages generated). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
194 lines
6.3 KiB
TypeScript
194 lines
6.3 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'
|
|
|
|
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,
|
|
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' },
|
|
]
|
|
|
|
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}
|
|
/>
|
|
)}
|
|
|
|
{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} />}
|
|
</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>
|
|
)
|
|
}
|