'use client' import { useState, useMemo } from 'react' import { useVendorCompliance, ReportType, ExportFormat, ProcessingActivity, Vendor, } from '@/lib/sdk/vendor-compliance' interface ExportConfig { reportType: ReportType format: ExportFormat scope: { vendorIds: string[] processingActivityIds: string[] includeFindings: boolean includeControls: boolean includeRiskAssessment: boolean dateRange?: { from: string to: string } } } const REPORT_TYPE_META: Record< ReportType, { title: string description: string icon: string formats: ExportFormat[] defaultFormat: ExportFormat } > = { VVT_EXPORT: { title: 'Verarbeitungsverzeichnis (VVT)', description: 'Vollständiges Verarbeitungsverzeichnis gemäß Art. 30 DSGVO mit allen Pflichtangaben', icon: '📋', formats: ['PDF', 'DOCX', 'XLSX'], defaultFormat: 'DOCX', }, ROPA: { title: 'Records of Processing Activities (RoPA)', description: 'Processor-Perspektive: Alle Verarbeitungen als Auftragsverarbeiter', icon: '📝', formats: ['PDF', 'DOCX', 'XLSX'], defaultFormat: 'DOCX', }, VENDOR_AUDIT: { title: 'Vendor Audit Pack', description: 'Vollständige Dokumentation eines Vendors inkl. Verträge, Findings und Risikobewertung', icon: '🔍', formats: ['PDF', 'DOCX'], defaultFormat: 'PDF', }, MANAGEMENT_SUMMARY: { title: 'Management Summary', description: 'Übersicht für die Geschäftsführung: Risiken, offene Findings, Compliance-Status', icon: '📊', formats: ['PDF', 'DOCX', 'XLSX'], defaultFormat: 'PDF', }, DPIA_INPUT: { title: 'DSFA-Input', description: 'Vorbereitete Daten für eine Datenschutz-Folgenabschätzung (DSFA/DPIA)', icon: '⚠️', formats: ['PDF', 'DOCX'], defaultFormat: 'DOCX', }, } const FORMAT_META: Record = { PDF: { label: 'PDF', icon: '📄' }, DOCX: { label: 'Word (DOCX)', icon: '📝' }, XLSX: { label: 'Excel (XLSX)', icon: '📊' }, JSON: { label: 'JSON', icon: '🔧' }, } export default function ReportsPage() { const { processingActivities, vendors, contracts, findings, riskAssessments, isLoading, } = useVendorCompliance() const [selectedReportType, setSelectedReportType] = useState('VVT_EXPORT') const [selectedFormat, setSelectedFormat] = useState('DOCX') const [selectedVendors, setSelectedVendors] = useState([]) const [selectedActivities, setSelectedActivities] = useState([]) const [includeFindings, setIncludeFindings] = useState(true) const [includeControls, setIncludeControls] = useState(true) const [includeRiskAssessment, setIncludeRiskAssessment] = useState(true) const [isGenerating, setIsGenerating] = useState(false) const [generatedReports, setGeneratedReports] = useState< { id: string; type: ReportType; format: ExportFormat; generatedAt: Date; filename: string }[] >([]) const reportMeta = REPORT_TYPE_META[selectedReportType] // Update format when report type changes const handleReportTypeChange = (type: ReportType) => { setSelectedReportType(type) setSelectedFormat(REPORT_TYPE_META[type].defaultFormat) // Reset selections setSelectedVendors([]) setSelectedActivities([]) } // Calculate statistics const stats = useMemo(() => { const openFindings = findings.filter((f) => f.status === 'OPEN').length const criticalFindings = findings.filter( (f) => f.status === 'OPEN' && f.severity === 'CRITICAL' ).length const highRiskVendors = vendors.filter((v) => v.inherentRiskScore >= 70).length return { totalActivities: processingActivities.length, approvedActivities: processingActivities.filter((a) => a.status === 'APPROVED').length, totalVendors: vendors.length, activeVendors: vendors.filter((v) => v.status === 'ACTIVE').length, totalContracts: contracts.length, openFindings, criticalFindings, highRiskVendors, } }, [processingActivities, vendors, contracts, findings]) // Handle export const handleExport = async () => { setIsGenerating(true) try { const config: ExportConfig = { reportType: selectedReportType, format: selectedFormat, scope: { vendorIds: selectedVendors, processingActivityIds: selectedActivities, includeFindings, includeControls, includeRiskAssessment, }, } // Call API to generate report const response = await fetch('/api/sdk/v1/vendor-compliance/export', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config), }) if (!response.ok) { throw new Error('Export fehlgeschlagen') } const result = await response.json() // Add to generated reports setGeneratedReports((prev) => [ { id: result.id, type: selectedReportType, format: selectedFormat, generatedAt: new Date(), filename: result.filename, }, ...prev, ]) // Download the file if (result.downloadUrl) { window.open(result.downloadUrl, '_blank') } } catch (error) { console.error('Export error:', error) // Show error notification } finally { setIsGenerating(false) } } // Toggle vendor selection const toggleVendor = (vendorId: string) => { setSelectedVendors((prev) => prev.includes(vendorId) ? prev.filter((id) => id !== vendorId) : [...prev, vendorId] ) } // Toggle activity selection const toggleActivity = (activityId: string) => { setSelectedActivities((prev) => prev.includes(activityId) ? prev.filter((id) => id !== activityId) : [...prev, activityId] ) } // Select all vendors const selectAllVendors = () => { setSelectedVendors(vendors.map((v) => v.id)) } // Select all activities const selectAllActivities = () => { setSelectedActivities(processingActivities.map((a) => a.id)) } if (isLoading) { return (
) } return (
{/* Header */}

Reports & Export

Berichte erstellen und Daten exportieren

{/* Quick Stats */}
0 ? 'red' : 'yellow'} />
{/* Report Type Selection */}
{/* Report Type Cards */}

Report-Typ wählen

{(Object.entries(REPORT_TYPE_META) as [ReportType, typeof REPORT_TYPE_META[ReportType]][]).map( ([type, meta]) => ( ) )}
{/* Scope Selection */} {(selectedReportType === 'VVT_EXPORT' || selectedReportType === 'ROPA' || selectedReportType === 'DPIA_INPUT') && (

Verarbeitungen auswählen

{processingActivities.length === 0 ? (

Keine Verarbeitungen vorhanden

) : (
{processingActivities.map((activity) => ( ))}
)}
)} {selectedReportType === 'VENDOR_AUDIT' && (

Vendor auswählen

{vendors.length === 0 ? (

Keine Vendors vorhanden

) : (
{vendors.map((vendor) => ( ))}
)}
)} {/* Include Options */}

Optionen

{/* Export Panel */}
{/* Format & Export */}

Export

{/* Selected Report Info */}
{reportMeta.icon} {reportMeta.title}

{reportMeta.description}

{/* Format Selection */}
{reportMeta.formats.map((format) => ( ))}
{/* Scope Summary */}

{selectedReportType === 'VENDOR_AUDIT' ? `${selectedVendors.length || 'Alle'} Vendor(s) ausgewählt` : selectedReportType === 'MANAGEMENT_SUMMARY' ? 'Gesamtübersicht' : `${selectedActivities.length || 'Alle'} Verarbeitung(en) ausgewählt`}

{/* Export Button */}
{/* Recent Reports */}

Letzte Reports

{generatedReports.length === 0 ? (

Noch keine Reports generiert

) : (
{generatedReports.slice(0, 5).map((report) => (
{REPORT_TYPE_META[report.type].icon}

{report.filename}

{report.generatedAt.toLocaleString('de-DE')}

))}
)}
{/* Help / Templates */}

Hilfe

📋

VVT Export

Art. 30 DSGVO konformes Verzeichnis aller Verarbeitungstätigkeiten

🔍

Vendor Audit

Komplette Dokumentation für Due Diligence und Audits

📊

Management Summary

Übersicht für Geschäftsführung und DSB

) } // Helper Components function StatCard({ label, value, subtext, color, }: { label: string value: number subtext: string color: 'blue' | 'purple' | 'green' | 'yellow' | 'red' }) { const colors = { blue: 'bg-blue-50 dark:bg-blue-900/20', purple: 'bg-purple-50 dark:bg-purple-900/20', green: 'bg-green-50 dark:bg-green-900/20', yellow: 'bg-yellow-50 dark:bg-yellow-900/20', red: 'bg-red-50 dark:bg-red-900/20', } return (

{label}

{value}

{subtext}

) } function StatusBadge({ status }: { status: string }) { const statusStyles: Record = { DRAFT: 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300', REVIEW: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300', APPROVED: 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300', ARCHIVED: 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400', } return ( {status} ) } function RiskBadge({ score }: { score: number }) { let colorClass = 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300' if (score >= 70) { colorClass = 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300' } else if (score >= 50) { colorClass = 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300' } return ( {score} ) }