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>
This commit is contained in:
56
admin-compliance/app/sdk/gci/_components/NIS2Tab.tsx
Normal file
56
admin-compliance/app/sdk/gci/_components/NIS2Tab.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
'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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user