Files
breakpilot-compliance/admin-compliance/components/sdk/tom-generator/steps/ReviewExportStep.tsx

153 lines
6.2 KiB
TypeScript

'use client'
// =============================================================================
// Step 6: Review & Export
// Summary, derived TOMs table, gap analysis, and export
// =============================================================================
import { useEffect, useState } from 'react'
import { useTOMGenerator } from '@/lib/sdk/tom-generator'
import { SummaryCard, TOMsTable, GapAnalysisPanel, ExportPanel } from './ReviewExportPanels'
export function ReviewExportStep() {
const { state, deriveTOMs, completeCurrentStep } = useTOMGenerator()
const [activeTab, setActiveTab] = useState<'summary' | 'toms' | 'gaps' | 'export'>('summary')
// Derive TOMs if not already done
useEffect(() => {
if (state.derivedTOMs.length === 0 && state.companyProfile && state.dataProfile) {
deriveTOMs()
}
}, [state, deriveTOMs])
// Mark step as complete when viewing
useEffect(() => {
completeCurrentStep({ reviewed: true })
}, [completeCurrentStep])
// Statistics
const stats = {
totalTOMs: state.derivedTOMs.length,
required: state.derivedTOMs.filter((t) => t.applicability === 'REQUIRED').length,
implemented: state.derivedTOMs.filter((t) => t.implementationStatus === 'IMPLEMENTED').length,
partial: state.derivedTOMs.filter((t) => t.implementationStatus === 'PARTIAL').length,
documents: state.documents.length,
score: state.gapAnalysis?.overallScore ?? 0,
}
const tabs = [
{ id: 'summary', label: 'Zusammenfassung' },
{ id: 'toms', label: 'TOMs-Tabelle' },
{ id: 'gaps', label: 'Lückenanalyse' },
{ id: 'export', label: 'Export' },
]
return (
<div className="space-y-6">
{/* Tabs */}
<div className="border-b">
<nav className="flex space-x-8">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as typeof activeTab)}
className={`py-3 px-1 border-b-2 font-medium text-sm transition-all ${
activeTab === tab.id
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
{tab.label}
</button>
))}
</nav>
</div>
{/* Tab Content */}
<div className="min-h-[400px]">
{activeTab === 'summary' && (
<div className="space-y-6">
{/* Stats Grid */}
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
<SummaryCard title="Gesamt TOMs" value={stats.totalTOMs} variant="default" />
<SummaryCard title="Erforderlich" value={stats.required} variant="danger" />
<SummaryCard title="Umgesetzt" value={stats.implemented} variant="success" />
<SummaryCard title="Teilweise" value={stats.partial} variant="warning" />
<SummaryCard title="Dokumente" value={stats.documents} variant="default" />
<SummaryCard
title="Score"
value={`${stats.score}%`}
variant={stats.score >= 80 ? 'success' : stats.score >= 50 ? 'warning' : 'danger'}
/>
</div>
{/* Profile Summaries */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Company */}
{state.companyProfile && (
<div className="bg-white border rounded-lg p-4">
<h4 className="font-medium text-gray-900 mb-3">Unternehmen</h4>
<dl className="space-y-2 text-sm">
<div className="flex justify-between">
<dt className="text-gray-500">Name:</dt>
<dd className="text-gray-900">{state.companyProfile.name}</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">Branche:</dt>
<dd className="text-gray-900">{state.companyProfile.industry}</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">Rolle:</dt>
<dd className="text-gray-900">{state.companyProfile.role}</dd>
</div>
</dl>
</div>
)}
{/* Risk */}
{state.riskProfile && (
<div className="bg-white border rounded-lg p-4">
<h4 className="font-medium text-gray-900 mb-3">Schutzbedarf</h4>
<dl className="space-y-2 text-sm">
<div className="flex justify-between">
<dt className="text-gray-500">Level:</dt>
<dd className={`font-medium ${
state.riskProfile.protectionLevel === 'VERY_HIGH' ? 'text-red-600' :
state.riskProfile.protectionLevel === 'HIGH' ? 'text-yellow-600' : 'text-green-600'
}`}>
{state.riskProfile.protectionLevel}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">DSFA erforderlich:</dt>
<dd className={state.riskProfile.dsfaRequired ? 'text-red-600 font-medium' : 'text-gray-900'}>
{state.riskProfile.dsfaRequired ? 'Ja' : 'Nein'}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-500">CIA (V/I/V):</dt>
<dd className="text-gray-900">
{state.riskProfile.ciaAssessment.confidentiality}/
{state.riskProfile.ciaAssessment.integrity}/
{state.riskProfile.ciaAssessment.availability}
</dd>
</div>
</dl>
</div>
)}
</div>
</div>
)}
{activeTab === 'toms' && <TOMsTable />}
{activeTab === 'gaps' && <GapAnalysisPanel />}
{activeTab === 'export' && <ExportPanel />}
</div>
</div>
)
}
export default ReviewExportStep