feat(sdk): Replace mock data with real API calls in consent, DSR, and consent-management
- /sdk/consent: Replace hardcoded mockDocuments with GET /api/admin/consent/documents - /sdk/dsr: Replace createMockDSRList with fetchSDKDSRList via /api/sdk/v1/dsgvo/dsr - /sdk/dsr/new: Replace console.log mock with real POST to create DSR requests - /sdk/dsr/[requestId]: Replace mock lookup with real GET/PUT for DSR details and status updates - /sdk/consent-management: Add real stats, GDPR process counts, and email template editor - lib/sdk/dsr/api.ts: Add transformBackendDSR adapter (flat backend → nested frontend types) Prepares for removal of /dsgvo and /compliance pages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useSDK } from '@/lib/sdk'
|
||||
import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader'
|
||||
|
||||
@@ -21,84 +21,47 @@ interface LegalDocument {
|
||||
changes: string[]
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// MOCK DATA
|
||||
// =============================================================================
|
||||
interface ApiDocument {
|
||||
id: string
|
||||
type: string
|
||||
name: string
|
||||
description: string
|
||||
mandatory: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
const mockDocuments: LegalDocument[] = [
|
||||
{
|
||||
id: 'doc-1',
|
||||
type: 'privacy-policy',
|
||||
name: 'Datenschutzerklaerung',
|
||||
version: '2.3',
|
||||
// Map API document type to UI type
|
||||
function mapDocumentType(apiType: string): LegalDocument['type'] {
|
||||
const mapping: Record<string, LegalDocument['type']> = {
|
||||
'privacy_policy': 'privacy-policy',
|
||||
'privacy-policy': 'privacy-policy',
|
||||
'terms': 'terms',
|
||||
'terms_of_service': 'terms',
|
||||
'cookie_policy': 'cookie-policy',
|
||||
'cookie-policy': 'cookie-policy',
|
||||
'imprint': 'imprint',
|
||||
'dpa': 'dpa',
|
||||
'avv': 'dpa',
|
||||
}
|
||||
return mapping[apiType] || 'terms'
|
||||
}
|
||||
|
||||
// Transform API response to UI format
|
||||
function transformApiDocument(doc: ApiDocument): LegalDocument {
|
||||
return {
|
||||
id: doc.id,
|
||||
type: mapDocumentType(doc.type),
|
||||
name: doc.name,
|
||||
version: '1.0',
|
||||
language: 'de',
|
||||
status: 'active',
|
||||
lastUpdated: new Date('2024-01-15'),
|
||||
publishedAt: new Date('2024-01-15'),
|
||||
author: 'DSB Mueller',
|
||||
changes: ['KI-Verarbeitungen ergaenzt', 'Cookie-Abschnitt aktualisiert'],
|
||||
},
|
||||
{
|
||||
id: 'doc-2',
|
||||
type: 'terms',
|
||||
name: 'Allgemeine Geschaeftsbedingungen',
|
||||
version: '1.8',
|
||||
language: 'de',
|
||||
status: 'active',
|
||||
lastUpdated: new Date('2023-12-01'),
|
||||
publishedAt: new Date('2023-12-01'),
|
||||
author: 'Rechtsabteilung',
|
||||
changes: ['Widerrufsrecht angepasst'],
|
||||
},
|
||||
{
|
||||
id: 'doc-3',
|
||||
type: 'cookie-policy',
|
||||
name: 'Cookie-Richtlinie',
|
||||
version: '1.5',
|
||||
language: 'de',
|
||||
status: 'active',
|
||||
lastUpdated: new Date('2024-01-10'),
|
||||
publishedAt: new Date('2024-01-10'),
|
||||
author: 'DSB Mueller',
|
||||
changes: ['Analytics-Cookies aktualisiert', 'Neue Cookie-Kategorien'],
|
||||
},
|
||||
{
|
||||
id: 'doc-4',
|
||||
type: 'privacy-policy',
|
||||
name: 'Privacy Policy (EN)',
|
||||
version: '2.3',
|
||||
language: 'en',
|
||||
status: 'draft',
|
||||
lastUpdated: new Date('2024-01-20'),
|
||||
publishedAt: null,
|
||||
author: 'DSB Mueller',
|
||||
changes: ['Uebersetzung der deutschen Version'],
|
||||
},
|
||||
{
|
||||
id: 'doc-5',
|
||||
type: 'dpa',
|
||||
name: 'Auftragsverarbeitungsvertrag (AVV)',
|
||||
version: '1.2',
|
||||
language: 'de',
|
||||
status: 'active',
|
||||
lastUpdated: new Date('2024-01-05'),
|
||||
publishedAt: new Date('2024-01-05'),
|
||||
author: 'Rechtsabteilung',
|
||||
changes: ['Subunternehmer aktualisiert', 'TOMs ergaenzt'],
|
||||
},
|
||||
{
|
||||
id: 'doc-6',
|
||||
type: 'imprint',
|
||||
name: 'Impressum',
|
||||
version: '1.1',
|
||||
language: 'de',
|
||||
status: 'active',
|
||||
lastUpdated: new Date('2023-11-01'),
|
||||
publishedAt: new Date('2023-11-01'),
|
||||
author: 'Admin',
|
||||
changes: ['Neue Geschaeftsadresse'],
|
||||
},
|
||||
]
|
||||
lastUpdated: new Date(doc.updated_at),
|
||||
publishedAt: new Date(doc.created_at),
|
||||
author: 'System',
|
||||
changes: doc.description ? [doc.description] : [],
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// COMPONENTS
|
||||
@@ -198,9 +161,37 @@ function DocumentCard({ document }: { document: LegalDocument }) {
|
||||
|
||||
export default function ConsentPage() {
|
||||
const { state } = useSDK()
|
||||
const [documents] = useState<LegalDocument[]>(mockDocuments)
|
||||
const [documents, setDocuments] = useState<LegalDocument[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [filter, setFilter] = useState<string>('all')
|
||||
|
||||
useEffect(() => {
|
||||
loadDocuments()
|
||||
}, [])
|
||||
|
||||
async function loadDocuments() {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
try {
|
||||
const token = localStorage.getItem('bp_admin_token')
|
||||
const res = await fetch('/api/admin/consent/documents', {
|
||||
headers: token ? { 'Authorization': `Bearer ${token}` } : {}
|
||||
})
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
const apiDocs: ApiDocument[] = data.documents || []
|
||||
setDocuments(apiDocs.map(transformApiDocument))
|
||||
} else {
|
||||
setError('Fehler beim Laden der Dokumente')
|
||||
}
|
||||
} catch {
|
||||
setError('Verbindungsfehler zum Server')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const filteredDocuments = filter === 'all'
|
||||
? documents
|
||||
: documents.filter(d => d.type === filter || d.status === filter)
|
||||
@@ -250,6 +241,16 @@ export default function ConsentPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Loading / Error */}
|
||||
{loading && (
|
||||
<div className="text-center py-8 text-gray-500">Lade Dokumente...</div>
|
||||
)}
|
||||
{error && (
|
||||
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div className="bg-gradient-to-r from-purple-50 to-blue-50 rounded-xl border border-purple-200 p-6">
|
||||
<h3 className="font-semibold text-gray-900 mb-4">Schnellaktionen</h3>
|
||||
|
||||
Reference in New Issue
Block a user