Files
breakpilot-compliance/admin-compliance/app/sdk/gci/_components/NIS2Tab.tsx
Sharang Parnerkar 7907b3f25b refactor(admin): split evidence, import, portfolio pages
Extract components and hooks from oversized pages into colocated
_components/ and _hooks/ subdirectories to enforce the 500-LOC hard cap.
page.tsx files reduced to 205, 121, and 136 LOC respectively.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 13:07:04 +02:00

57 lines
2.5 KiB
TypeScript

'use client'
import { NIS2Score, getScoreColor, getScoreRingColor } from '@/lib/sdk/gci/types'
import { ScoreCircle, AreaScoreBar, LoadingSpinner } from './GCIHelpers'
export function NIS2Tab({ nis2 }: { nis2: NIS2Score | null }) {
if (!nis2) return <LoadingSpinner />
return (
<div className="space-y-6">
<div className="bg-white rounded-xl border border-gray-200 p-6">
<div className="flex items-center gap-6">
<ScoreCircle score={nis2.overall_score} size={120} label="NIS2" />
<div>
<h3 className="text-lg font-semibold text-gray-900">NIS2 Compliance Score</h3>
<p className="text-sm text-gray-500 mt-1">Network and Information Security Directive 2 (EU 2022/2555)</p>
</div>
</div>
</div>
<div className="bg-white rounded-xl border border-gray-200 p-6">
<h3 className="text-base font-semibold text-gray-900 mb-4">NIS2 Bereiche</h3>
<div className="space-y-3">
{nis2.areas.map(area => (
<AreaScoreBar key={area.area_id} name={area.area_name} score={area.score} weight={area.weight} />
))}
</div>
</div>
{nis2.role_scores && nis2.role_scores.length > 0 && (
<div className="bg-white rounded-xl border border-gray-200 p-6">
<h3 className="text-base font-semibold text-gray-900 mb-4">Rollen-Compliance</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{nis2.role_scores.map(role => (
<div key={role.role_id} className="border border-gray-200 rounded-lg p-3">
<div className="font-medium text-gray-900 text-sm">{role.role_name}</div>
<div className="flex items-center justify-between mt-2">
<span className={`text-lg font-bold ${getScoreColor(role.completion_rate * 100)}`}>
{(role.completion_rate * 100).toFixed(0)}%
</span>
<span className="text-xs text-gray-500">{role.modules_completed}/{role.modules_required} Module</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-1.5 mt-2">
<div
className="h-1.5 rounded-full"
style={{ width: `${Math.min(role.completion_rate * 100, 100)}%`, backgroundColor: getScoreRingColor(role.completion_rate * 100) }}
/>
</div>
</div>
))}
</div>
</div>
)}
</div>
)
}