'use client' import React, { useState, useEffect } from 'react' import { useSDK } from '@/lib/sdk' import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader' // ============================================================================= // TYPES // ============================================================================= interface Obligation { id: string title: string description: string source: string sourceArticle: string deadline: Date | null status: 'pending' | 'in-progress' | 'completed' | 'overdue' priority: 'critical' | 'high' | 'medium' | 'low' responsible: string linkedSystems: string[] } // ============================================================================= // COMPONENTS // ============================================================================= function ObligationCard({ obligation }: { obligation: Obligation }) { const priorityColors = { critical: 'bg-red-100 text-red-700', high: 'bg-orange-100 text-orange-700', medium: 'bg-yellow-100 text-yellow-700', low: 'bg-green-100 text-green-700', } const statusColors = { pending: 'bg-gray-100 text-gray-600 border-gray-200', 'in-progress': 'bg-blue-100 text-blue-700 border-blue-200', completed: 'bg-green-100 text-green-700 border-green-200', overdue: 'bg-red-100 text-red-700 border-red-200', } const statusLabels = { pending: 'Ausstehend', 'in-progress': 'In Bearbeitung', completed: 'Abgeschlossen', overdue: 'Ueberfaellig', } const daysUntilDeadline = obligation.deadline ? Math.ceil((obligation.deadline.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)) : null return (
{obligation.priority === 'critical' ? 'Kritisch' : obligation.priority === 'high' ? 'Hoch' : obligation.priority === 'medium' ? 'Mittel' : 'Niedrig'} {statusLabels[obligation.status]} {obligation.source} {obligation.sourceArticle}

{obligation.title}

{obligation.description}

Verantwortlich: {obligation.responsible}
{obligation.deadline && (
Frist: {obligation.deadline.toLocaleDateString('de-DE')} {daysUntilDeadline !== null && ( ({daysUntilDeadline < 0 ? `${Math.abs(daysUntilDeadline)} Tage ueberfaellig` : `${daysUntilDeadline} Tage`}) )}
)}
{obligation.linkedSystems.length > 0 && (
Betroffene Systeme: {obligation.linkedSystems.map(sys => ( {sys} ))}
)}
{obligation.status !== 'completed' && ( )}
) } // ============================================================================= // HELPERS // ============================================================================= function mapControlsToObligations(assessments: Array<{ id: string title?: string domain?: string result?: { required_controls?: Array<{ id: string title: string description: string gdpr_ref?: string effort?: string }> triggered_rules?: Array<{ rule_code: string title: string severity: string gdpr_ref: string }> risk_level?: string } }>): Obligation[] { const obligations: Obligation[] = [] for (const assessment of assessments) { // Map triggered rules to obligations const rules = assessment.result?.triggered_rules || [] for (const rule of rules) { const severity = rule.severity obligations.push({ id: `${assessment.id}-${rule.rule_code}`, title: rule.title, description: `Aus Assessment: ${assessment.title || assessment.id.slice(0, 8)}`, source: rule.gdpr_ref?.includes('AI Act') ? 'AI Act' : 'DSGVO', sourceArticle: rule.gdpr_ref || '', deadline: null, status: 'pending', priority: severity === 'BLOCK' ? 'critical' : severity === 'WARN' ? 'high' : 'medium', responsible: 'Compliance Team', linkedSystems: assessment.title ? [assessment.title] : [], }) } // Map required controls to obligations const controls = assessment.result?.required_controls || [] for (const control of controls) { obligations.push({ id: `${assessment.id}-ctrl-${control.id}`, title: control.title, description: control.description, source: control.gdpr_ref?.includes('AI Act') ? 'AI Act' : 'DSGVO', sourceArticle: control.gdpr_ref || '', deadline: null, status: 'pending', priority: assessment.result?.risk_level === 'HIGH' || assessment.result?.risk_level === 'UNACCEPTABLE' ? 'high' : 'medium', responsible: 'IT / Compliance', linkedSystems: assessment.title ? [assessment.title] : [], }) } } return obligations } // ============================================================================= // MAIN PAGE // ============================================================================= export default function ObligationsPage() { const { state } = useSDK() const [obligations, setObligations] = useState([]) const [filter, setFilter] = useState('all') const [loading, setLoading] = useState(true) const [backendAvailable, setBackendAvailable] = useState(false) const [backendError, setBackendError] = useState(null) useEffect(() => { async function loadObligations() { try { const response = await fetch('/api/sdk/v1/ucca/assessments') if (response.ok) { const data = await response.json() const assessments = data.assessments || [] if (assessments.length > 0) { const mapped = mapControlsToObligations(assessments) setObligations(mapped) setBackendAvailable(true) setLoading(false) return } } } catch { setBackendError('Backend nicht erreichbar — Pflichten aus lokalem State geladen (Offline-Modus)') } // Fallback: use obligations from SDK state if (state.obligations && state.obligations.length > 0) { setObligations(state.obligations.map(o => ({ id: o.id, title: o.title, description: o.description || '', source: o.source || 'DSGVO', sourceArticle: o.sourceArticle || '', deadline: o.deadline ? new Date(o.deadline) : null, status: (o.status as Obligation['status']) || 'pending', priority: (o.priority as Obligation['priority']) || 'medium', responsible: o.responsible || 'Compliance Team', linkedSystems: o.linkedSystems || [], }))) } setLoading(false) } loadObligations() }, [state.obligations]) const filteredObligations = filter === 'all' ? obligations : obligations.filter(o => o.status === filter || o.priority === filter || o.source.toLowerCase().includes(filter)) const pendingCount = obligations.filter(o => o.status === 'pending').length const inProgressCount = obligations.filter(o => o.status === 'in-progress').length const overdueCount = obligations.filter(o => o.status === 'overdue').length const completedCount = obligations.filter(o => o.status === 'completed').length const stepInfo = STEP_EXPLANATIONS['obligations'] return (
{/* Step Header */} {/* Backend Status */} {backendAvailable && (
Pflichten aus UCCA-Assessments geladen (Live-Daten)
)} {backendError && !backendAvailable && (
{backendError}
)} {/* Loading */} {loading && (
Lade Pflichten...
)} {/* Stats */}
Ausstehend
{pendingCount}
In Bearbeitung
{inProgressCount}
Ueberfaellig
{overdueCount}
Abgeschlossen
{completedCount}
{/* Urgent Alert */} {overdueCount > 0 && (

Achtung: {overdueCount} ueberfaellige Pflicht(en)

Diese Pflichten erfordern sofortige Aufmerksamkeit.

)} {/* Filter */}
Filter: {['all', 'overdue', 'pending', 'in-progress', 'completed', 'critical', 'ai'].map(f => ( ))}
{/* Obligations List */}
{filteredObligations .sort((a, b) => { const statusOrder = { overdue: 0, 'in-progress': 1, pending: 2, completed: 3 } return statusOrder[a.status] - statusOrder[b.status] }) .map(obligation => ( ))}
{filteredObligations.length === 0 && !loading && (

Keine Pflichten gefunden

Erstellen Sie zuerst ein Use Case Assessment, um automatisch Pflichten abzuleiten.

)}
) }