'use client' import React, { useState, useCallback, useMemo, useEffect } from 'react' import { useRouter } from 'next/navigation' import { useSDK } from '@/lib/sdk' import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader' import { useTOMGenerator } from '@/lib/sdk/tom-generator/context' import { DerivedTOM } from '@/lib/sdk/tom-generator/types' import { TOMOverviewTab, TOMEditorTab, TOMGapExportTab, TOMDocumentTab } from '@/components/sdk/tom-dashboard' import { runTOMComplianceCheck, type TOMComplianceCheckResult } from '@/lib/sdk/tom-compliance' // ============================================================================= // TYPES // ============================================================================= type Tab = 'uebersicht' | 'editor' | 'generator' | 'gap-export' | 'tom-dokument' interface TabDefinition { key: Tab label: string } const TABS: TabDefinition[] = [ { key: 'uebersicht', label: 'Uebersicht' }, { key: 'editor', label: 'Detail-Editor' }, { key: 'generator', label: 'Generator' }, { key: 'gap-export', label: 'Gap-Analyse & Export' }, { key: 'tom-dokument', label: 'TOM-Dokument' }, ] // ============================================================================= // PAGE COMPONENT // ============================================================================= export default function TOMPage() { const router = useRouter() const sdk = useSDK() const { state, dispatch, runGapAnalysis } = useTOMGenerator() // --------------------------------------------------------------------------- // Local state // --------------------------------------------------------------------------- const [tab, setTab] = useState('uebersicht') const [selectedTOMId, setSelectedTOMId] = useState(null) const [complianceResult, setComplianceResult] = useState(null) const [vendorControls, setVendorControls] = useState>([]) // --------------------------------------------------------------------------- // Compliance check (auto-run when derivedTOMs change) // --------------------------------------------------------------------------- useEffect(() => { if (state?.derivedTOMs && Array.isArray(state.derivedTOMs) && state.derivedTOMs.length > 0) { setComplianceResult(runTOMComplianceCheck(state)) } }, [state?.derivedTOMs]) // --------------------------------------------------------------------------- // Vendor controls cross-reference (fetch when overview tab is active) // --------------------------------------------------------------------------- useEffect(() => { if (tab !== 'uebersicht') return Promise.all([ fetch('/api/sdk/v1/vendor-compliance/control-instances?limit=500').then(r => r.ok ? r.json() : null), fetch('/api/sdk/v1/vendor-compliance/vendors?limit=500').then(r => r.ok ? r.json() : null), ]).then(([ciData, vendorData]) => { const instances = ciData?.data?.items || [] const vendors = vendorData?.data?.items || [] const vendorMap = new Map() for (const v of vendors) { vendorMap.set(v.id, v.name) } // Filter for TOM-domain controls const tomControls = instances .filter((ci: any) => ci.domain === 'TOM' || ci.controlId?.startsWith('VND-TOM')) .map((ci: any) => ({ vendorId: ci.vendorId || ci.vendor_id, vendorName: vendorMap.get(ci.vendorId || ci.vendor_id) || 'Unbekannt', controlId: ci.controlId || ci.control_id, controlName: ci.controlName || ci.control_name || ci.controlId || ci.control_id, domain: ci.domain || 'TOM', status: ci.status || 'UNKNOWN', lastTestedAt: ci.lastTestedAt || ci.last_tested_at, })) setVendorControls(tomControls) }).catch(() => {}) }, [tab]) // --------------------------------------------------------------------------- // Computed / memoised values // --------------------------------------------------------------------------- const tomCount = useMemo(() => { if (!state?.derivedTOMs) return 0 return Array.isArray(state.derivedTOMs) ? state.derivedTOMs.length : Object.keys(state.derivedTOMs).length }, [state?.derivedTOMs]) const lastModifiedFormatted = useMemo(() => { if (!state?.metadata?.lastModified) return null try { const date = new Date(state.metadata.lastModified) return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } catch { return null } }, [state?.metadata?.lastModified]) // --------------------------------------------------------------------------- // Handlers // --------------------------------------------------------------------------- const handleSelectTOM = useCallback((tomId: string) => { setSelectedTOMId(tomId) setTab('editor') }, []) const handleUpdateTOM = useCallback( (tomId: string, updates: Partial) => { dispatch({ type: 'UPDATE_DERIVED_TOM', payload: { id: tomId, data: updates }, }) }, [dispatch], ) const handleStartGenerator = useCallback(() => { router.push('/sdk/tom-generator') }, [router]) const handleBackToOverview = useCallback(() => { setSelectedTOMId(null) setTab('uebersicht') }, []) const handleRunGapAnalysis = useCallback(() => { if (typeof runGapAnalysis === 'function') { runGapAnalysis() } }, [runGapAnalysis]) const handleTabChange = useCallback((newTab: Tab) => { setTab(newTab) }, []) // --------------------------------------------------------------------------- // Render helpers // --------------------------------------------------------------------------- const renderTabBar = () => (
{TABS.map((t) => { const isActive = tab === t.key return ( ) })}
) // --------------------------------------------------------------------------- // Tab 1 – Uebersicht // --------------------------------------------------------------------------- const renderUebersicht = () => ( ) // --------------------------------------------------------------------------- // Tab 2 – Detail-Editor // --------------------------------------------------------------------------- const renderEditor = () => ( ) // --------------------------------------------------------------------------- // Tab 3 – Generator // --------------------------------------------------------------------------- const renderGenerator = () => (
{/* Info card */}
{/* Icon */}

TOM Generator – 6-Schritte-Assistent

Der TOM Generator fuehrt Sie in 6 Schritten durch die systematische Ableitung Ihrer technischen und organisatorischen Massnahmen. Sie beantworten gezielte Fragen zu Ihrem Unternehmen, Ihrer IT-Infrastruktur und Ihren Verarbeitungstaetigkeiten. Daraus werden passende TOMs automatisch abgeleitet und priorisiert.

Die 6 Schritte im Ueberblick:

  1. Unternehmenskontext erfassen
  2. IT-Infrastruktur beschreiben
  3. Verarbeitungstaetigkeiten zuordnen
  4. Risikobewertung durchfuehren
  5. TOM-Ableitung und Priorisierung
  6. Ergebnis pruefen und uebernehmen
{/* Quick stats – only rendered when derivedTOMs exist */} {tomCount > 0 && (

Aktueller Stand

{/* TOM count */}

Abgeleitete TOMs

{tomCount}

{/* Last generated date */} {lastModifiedFormatted && (

Zuletzt generiert

{lastModifiedFormatted}

)} {/* Status */}

Status

TOMs vorhanden

Sie koennen den Generator jederzeit erneut ausfuehren, um Ihre TOMs zu aktualisieren oder zu erweitern.

)} {/* Empty state when no TOMs exist yet */} {tomCount === 0 && (

Noch keine TOMs vorhanden

Starten Sie den Generator, um Ihre ersten technischen und organisatorischen Massnahmen abzuleiten.

)}
) // --------------------------------------------------------------------------- // Tab 4 – Gap-Analyse & Export // --------------------------------------------------------------------------- const renderGapExport = () => ( ) // --------------------------------------------------------------------------- // Tab 5 – TOM-Dokument // --------------------------------------------------------------------------- const renderTOMDokument = () => ( ) // --------------------------------------------------------------------------- // Tab content router // --------------------------------------------------------------------------- const renderActiveTab = () => { switch (tab) { case 'uebersicht': return renderUebersicht() case 'editor': return renderEditor() case 'generator': return renderGenerator() case 'gap-export': return renderGapExport() case 'tom-dokument': return renderTOMDokument() default: return renderUebersicht() } } // --------------------------------------------------------------------------- // Main render // --------------------------------------------------------------------------- return (
{/* Step header */} {/* Tab bar */}
{renderTabBar()}
{/* Active tab content */}
{renderActiveTab()}
{/* Vendor-Controls cross-reference (only on overview tab) */} {tab === 'uebersicht' && vendorControls.length > 0 && (

Auftragsverarbeiter-Controls (Art. 28)

TOM-relevante Controls aus dem Vendor Register

Zum Vendor Register →
{vendorControls.map((vc, i) => ( ))}
Vendor Control Status Letzte Pruefung
{vc.vendorName} {vc.controlId} {vc.controlName !== vc.controlId ? vc.controlName : ''} {vc.status === 'PASS' ? 'Bestanden' : vc.status === 'PARTIAL' ? 'Teilweise' : vc.status === 'FAIL' ? 'Nicht bestanden' : vc.status} {vc.lastTestedAt ? new Date(vc.lastTestedAt).toLocaleDateString('de-DE') : '\u2014'}
)}
) }