'use client' import { useState } from 'react' import { useVendorCompliance } from '@/lib/sdk/vendor-compliance' import Link from 'next/link' // ============================================================================= // VENDOR CREATE MODAL // ============================================================================= function VendorCreateModal({ onClose, onSuccess }: { onClose: () => void onSuccess: () => void }) { const [name, setName] = useState('') const [serviceDescription, setServiceDescription] = useState('') const [category, setCategory] = useState('data_processor') const [country, setCountry] = useState('Germany') const [riskLevel, setRiskLevel] = useState('MEDIUM') const [dpaStatus, setDpaStatus] = useState('PENDING') const [contractUrl, setContractUrl] = useState('') const [isSaving, setIsSaving] = useState(false) const [error, setError] = useState(null) const handleSave = async () => { if (!name.trim()) { setError('Name ist erforderlich.') return } setIsSaving(true) setError(null) try { const res = await fetch('/api/sdk/v1/vendor-compliance/vendors', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, serviceDescription, category, country, riskLevel, dpaStatus, contractUrl }) }) if (!res.ok) { const data = await res.json().catch(() => ({})) throw new Error(data.detail || data.message || `Fehler: ${res.status}`) } onSuccess() } catch (err: unknown) { setError(err instanceof Error ? err.message : 'Unbekannter Fehler') } finally { setIsSaving(false) } } return (
{/* Backdrop */}
{/* Modal */}

Neuen Vendor anlegen

{error && (
{error}
)}
{/* Name */}
setName(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm" placeholder="Name des Vendors / Dienstleisters" />
{/* Service Description */}
setServiceDescription(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm" placeholder="Kurze Beschreibung der erbrachten Leistung" />
{/* Category */}
{/* Country */}
setCountry(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm" placeholder="z.B. Germany, USA, Netherlands" />
{/* Risk Level */}
{/* DPA Status */}
{/* Contract URL */}
setContractUrl(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm" placeholder="https://..." />
{/* Buttons */}
) } // ============================================================================= // MAIN PAGE // ============================================================================= export default function VendorComplianceDashboard() { const { vendors, processingActivities, contracts, findings, vendorStats, complianceStats, riskOverview, isLoading, } = useVendorCompliance() const [showVendorCreate, setShowVendorCreate] = useState(false) if (isLoading) { return (
) } return (
{/* Header */}

Vendor & Contract Compliance

Übersicht über Verarbeitungsverzeichnis, Vendor Register und Vertragsprüfung

{/* Quick Stats */}
c.reviewStatus === 'COMPLETED').length} geprüft`} href="/sdk/vendor-compliance/contracts" color="green" />
{/* Risk Overview */}
{/* Vendor Risk Distribution */}

Vendor Risiko-Verteilung

Durchschn. Inherent Risk {Math.round(riskOverview.averageInherentRisk)}%
Durchschn. Residual Risk {Math.round(riskOverview.averageResidualRisk)}%
{/* Compliance Score */}

Compliance Status

{Math.round(complianceStats.averageComplianceScore)}%
{complianceStats.resolvedFindings}
Behoben
{complianceStats.openFindings}
Offen
Control Pass Rate {Math.round(complianceStats.controlPassRate)}%
{/* Quick Actions */}
} /> setShowVendorCreate(true)} icon={ } /> } />
{/* Recent Activity */}

Fällige Reviews

{vendors .filter((v) => v.nextReviewDate && new Date(v.nextReviewDate) <= new Date()) .slice(0, 5) .map((vendor) => (

{vendor.name}

{vendor.serviceDescription}

Review fällig
))} {vendors.filter((v) => v.nextReviewDate && new Date(v.nextReviewDate) <= new Date()).length === 0 && (
Keine fälligen Reviews
)}
{/* Vendor Create Modal */} {showVendorCreate && ( setShowVendorCreate(false)} onSuccess={() => { setShowVendorCreate(false); window.location.reload() }} /> )}
) } function StatCard({ title, value, description, href, color, }: { title: string value: number description: string href: string color: 'blue' | 'purple' | 'green' | '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', red: 'bg-red-50 dark:bg-red-900/20', } return (

{title}

{value}

{description}

) } function RiskBar({ label, count, total, color, }: { label: string count: number total: number color: string }) { const percentage = total > 0 ? (count / total) * 100 : 0 return (
{label} {count}
) } function QuickActionCard({ title, description, href, onClick, icon, }: { title: string description: string href?: string onClick?: () => void icon: React.ReactNode }) { const inner = ( <>
{icon}

{title}

{description}

) if (onClick) { return ( ) } return ( {inner} ) }