'use client'
import React, { useState, useEffect } from 'react'
import Link from 'next/link'
import { useParams, useRouter } from 'next/navigation'
import {
DSRRequest,
DSR_TYPE_INFO,
DSR_STATUS_INFO,
getDaysRemaining,
isOverdue,
isUrgent,
DSRCommunication,
DSRVerifyIdentityRequest
} from '@/lib/sdk/dsr/types'
import { fetchSDKDSR, updateSDKDSRStatus } from '@/lib/sdk/dsr/api'
import {
DSRWorkflowStepper,
DSRIdentityModal,
DSRCommunicationLog,
DSRErasureChecklistComponent,
DSRDataExportComponent
} from '@/components/sdk/dsr'
// =============================================================================
// MOCK COMMUNICATIONS
// =============================================================================
const mockCommunications: DSRCommunication[] = [
{
id: 'comm-001',
dsrId: 'dsr-001',
type: 'outgoing',
channel: 'email',
subject: 'Eingangsbestaetigung Ihrer Anfrage',
content: 'Sehr geehrte(r) Antragsteller(in),\n\nwir bestaetigen den Eingang Ihrer Anfrage und werden diese innerhalb der gesetzlichen Frist bearbeiten.\n\nMit freundlichen Gruessen\nIhr Datenschutz-Team',
sentAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),
sentBy: 'System',
createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),
createdBy: 'System'
},
{
id: 'comm-002',
dsrId: 'dsr-001',
type: 'outgoing',
channel: 'email',
subject: 'Identitaetspruefung erforderlich',
content: 'Sehr geehrte(r) Antragsteller(in),\n\nbitte senden Sie uns zur Bearbeitung Ihrer Anfrage einen Identitaetsnachweis zu.\n\nMit freundlichen Gruessen',
sentAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(),
sentBy: 'DSB Mueller',
createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(),
createdBy: 'DSB Mueller'
}
]
// =============================================================================
// COMPONENTS
// =============================================================================
function StatusBadge({ status }: { status: string }) {
const info = DSR_STATUS_INFO[status as keyof typeof DSR_STATUS_INFO]
if (!info) return null
return (
{info.label}
)
}
function DeadlineDisplay({ request }: { request: DSRRequest }) {
const daysRemaining = getDaysRemaining(request.deadline.currentDeadline)
const overdue = isOverdue(request)
const urgent = isUrgent(request)
const isTerminal = request.status === 'completed' || request.status === 'rejected' || request.status === 'cancelled'
if (isTerminal) {
return (
Abgeschlossen am
{request.completedAt
? new Date(request.completedAt).toLocaleDateString('de-DE')
: '-'
}
)
}
return (
Frist
{overdue
? `${Math.abs(daysRemaining)} Tage ueberfaellig`
: `${daysRemaining} Tage`
}
bis {new Date(request.deadline.currentDeadline).toLocaleDateString('de-DE')}
{request.deadline.extended && (
(Verlaengert)
)}
)
}
function ActionButtons({
request,
onVerifyIdentity,
onExtendDeadline,
onComplete,
onReject,
onAssign
}: {
request: DSRRequest
onVerifyIdentity: () => void
onExtendDeadline: () => void
onComplete: () => void
onReject: () => void
onAssign: () => void
}) {
const isTerminal = request.status === 'completed' || request.status === 'rejected' || request.status === 'cancelled'
if (isTerminal) {
return (
)
}
return (
{!request.identityVerification.verified && (
)}
)
}
function AuditLog({ request }: { request: DSRRequest }) {
type AuditEvent = { action: string; timestamp: string; user: string }
const events: AuditEvent[] = [
{ action: 'Erstellt', timestamp: request.createdAt, user: request.createdBy }
]
if (request.assignment.assignedAt) {
events.push({
action: `Zugewiesen an ${request.assignment.assignedTo}`,
timestamp: request.assignment.assignedAt,
user: request.assignment.assignedBy || 'System'
})
}
if (request.identityVerification.verifiedAt) {
events.push({
action: 'Identitaet verifiziert',
timestamp: request.identityVerification.verifiedAt,
user: request.identityVerification.verifiedBy || 'System'
})
}
if (request.completedAt) {
events.push({
action: request.status === 'rejected' ? 'Abgelehnt' : 'Abgeschlossen',
timestamp: request.completedAt,
user: request.updatedBy || 'System'
})
}
return (
Aktivitaeten
{events.map((event, idx) => (
{event.action}
{new Date(event.timestamp).toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
})}
{' - '}
{event.user}
))}
)
}
// =============================================================================
// MAIN PAGE
// =============================================================================
export default function DSRDetailPage() {
const params = useParams()
const router = useRouter()
const requestId = params.requestId as string
const [request, setRequest] = useState(null)
const [communications, setCommunications] = useState([])
const [isLoading, setIsLoading] = useState(true)
const [showIdentityModal, setShowIdentityModal] = useState(false)
const [activeContentTab, setActiveContentTab] = useState<'details' | 'communication' | 'type-specific'>('details')
// Load data from SDK backend
useEffect(() => {
const loadData = async () => {
setIsLoading(true)
try {
const found = await fetchSDKDSR(requestId)
if (found) {
setRequest(found)
// Communications are loaded as mock for now (no backend API yet)
setCommunications(mockCommunications.filter(c => c.dsrId === requestId))
}
} catch (error) {
console.error('Failed to load DSR:', error)
} finally {
setIsLoading(false)
}
}
loadData()
}, [requestId])
const handleVerifyIdentity = async (verification: DSRVerifyIdentityRequest) => {
if (!request) return
try {
await updateSDKDSRStatus(request.id, 'verified')
setRequest({
...request,
identityVerification: {
verified: true,
method: verification.method,
verifiedAt: new Date().toISOString(),
verifiedBy: 'Current User',
notes: verification.notes
},
status: request.status === 'identity_verification' ? 'processing' : request.status
})
} catch (err) {
console.error('Failed to verify identity:', err)
// Still update locally as fallback
setRequest({
...request,
identityVerification: {
verified: true,
method: verification.method,
verifiedAt: new Date().toISOString(),
verifiedBy: 'Current User',
notes: verification.notes
},
status: request.status === 'identity_verification' ? 'processing' : request.status
})
}
}
const handleSendCommunication = async (message: any) => {
const newComm: DSRCommunication = {
id: `comm-${Date.now()}`,
dsrId: requestId,
...message,
createdAt: new Date().toISOString(),
createdBy: 'Current User',
sentAt: message.type === 'outgoing' ? new Date().toISOString() : undefined,
sentBy: message.type === 'outgoing' ? 'Current User' : undefined
}
setCommunications(prev => [newComm, ...prev])
}
if (isLoading) {
return (
)
}
if (!request) {
return (
Anfrage nicht gefunden
Die angeforderte DSR-Anfrage existiert nicht oder wurde geloescht.
Zurueck zur Uebersicht
)
}
const typeInfo = DSR_TYPE_INFO[request.type]
const overdue = isOverdue(request)
const urgent = isUrgent(request)
return (
{/* Header */}
{request.referenceNumber}
{typeInfo.article} {typeInfo.label}
{request.requester.name}
{/* Workflow Stepper */}
{/* Main Content: 2/3 + 1/3 Layout */}
{/* Left Column - 2/3 */}
{/* Content Tabs */}
{/* Details Tab */}
{activeContentTab === 'details' && (
{/* Request Info */}
Antragsteller
{request.requester.name}
{request.requester.email}
{request.requester.phone && (
{request.requester.phone}
)}
Eingereicht
{new Date(request.receivedAt).toLocaleDateString('de-DE', {
day: '2-digit',
month: 'long',
year: 'numeric'
})}
Quelle: {request.source === 'web_form' ? 'Kontaktformular' :
request.source === 'email' ? 'E-Mail' :
request.source === 'letter' ? 'Brief' :
request.source === 'phone' ? 'Telefon' : request.source}
{/* Identity Verification */}
{request.identityVerification.verified ? (
) : (
)}
{request.identityVerification.verified
? 'Identitaet verifiziert'
: 'Identitaetspruefung ausstehend'
}
{request.identityVerification.verified && (
Methode: {request.identityVerification.method === 'id_document' ? 'Ausweisdokument' :
request.identityVerification.method === 'email' ? 'E-Mail' :
request.identityVerification.method === 'existing_account' ? 'Bestehendes Konto' :
request.identityVerification.method}
{' | '}
{new Date(request.identityVerification.verifiedAt!).toLocaleDateString('de-DE')}
)}
{!request.identityVerification.verified && (
)}
{/* Request Text */}
{request.requestText && (
Anfragetext
{request.requestText}
)}
{/* Notes */}
{request.notes && (
)}
)}
{/* Communication Tab */}
{activeContentTab === 'communication' && (
)}
{/* Type-Specific Tab */}
{activeContentTab === 'type-specific' && (
{/* Art. 17 - Erasure */}
{request.type === 'erasure' && (
setRequest({ ...request, erasureChecklist: checklist })}
/>
)}
{/* Art. 15/20 - Data Export */}
{(request.type === 'access' || request.type === 'portability') && (
{
// Mock generation
setRequest({
...request,
dataExport: {
format,
generatedAt: new Date().toISOString(),
generatedBy: 'Current User',
fileName: `datenexport_${request.referenceNumber}.${format}`,
fileSize: 125000,
includesThirdPartyData: true
}
})
}}
/>
)}
{/* Art. 16 - Rectification */}
{request.type === 'rectification' && request.rectificationDetails && (
Zu korrigierende Daten
{request.rectificationDetails.fieldsToCorrect.map((field, idx) => (
{field.field}
Aktueller Wert
{field.currentValue}
Angeforderter Wert
{field.requestedValue}
{field.corrected && (
Korrigiert am {new Date(field.correctedAt!).toLocaleDateString('de-DE')}
)}
))}
)}
{/* Art. 21 - Objection */}
{request.type === 'objection' && request.objectionDetails && (
Widerspruchsdetails
Verarbeitungszweck
{request.objectionDetails.processingPurpose}
Rechtsgrundlage
{request.objectionDetails.legalBasis}
Widerspruchsgruende
{request.objectionDetails.objectionGrounds}
{request.objectionDetails.decision !== 'pending' && (
Widerspruch {request.objectionDetails.decision === 'accepted' ? 'angenommen' : 'abgelehnt'}
{request.objectionDetails.decisionReason && (
{request.objectionDetails.decisionReason}
)}
)}
)}
{/* Default for restriction */}
{request.type === 'restriction' && (
Einschraenkung der Verarbeitung
Markieren Sie die betroffenen Daten im System als eingeschraenkt.
Die Daten duerfen nur noch gespeichert, aber nicht mehr verarbeitet werden.
)}
)}
{/* Right Column - 1/3 Sidebar */}
{/* Status Card */}
Status
{/* Priority */}
Prioritaet
{request.priority === 'critical' ? 'Kritisch' :
request.priority === 'high' ? 'Hoch' :
request.priority === 'normal' ? 'Normal' : 'Niedrig'}
{/* Assignment */}
Zugewiesen an
{request.assignment.assignedTo || 'Nicht zugewiesen'}
{/* Actions Card */}
Aktionen
setShowIdentityModal(true)}
onExtendDeadline={() => alert('Fristverlaengerung - Coming soon')}
onComplete={() => alert('Abschliessen - Coming soon')}
onReject={() => alert('Ablehnen - Coming soon')}
onAssign={() => alert('Zuweisen - Coming soon')}
/>
{/* Audit Log Card */}
{/* Identity Modal */}
setShowIdentityModal(false)}
onVerify={handleVerifyIdentity}
requesterName={request.requester.name}
requesterEmail={request.requester.email}
/>
)
}