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:
91
admin-compliance/app/sdk/gci/_components/OverviewTab.tsx
Normal file
91
admin-compliance/app/sdk/gci/_components/OverviewTab.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
'use client'
|
||||
|
||||
import { GCIResult, GCIHistoryResponse, WeightProfile, MATURITY_INFO, getScoreRingColor } from '@/lib/sdk/gci/types'
|
||||
import { ScoreCircle, MaturityBadge, AreaScoreBar } from './GCIHelpers'
|
||||
|
||||
export function OverviewTab({ gci, history, profiles, selectedProfile, onProfileChange }: {
|
||||
gci: GCIResult
|
||||
history: GCIHistoryResponse | null
|
||||
profiles: WeightProfile[]
|
||||
selectedProfile: string
|
||||
onProfileChange: (p: string) => void
|
||||
}) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{profiles.length > 0 && (
|
||||
<div className="flex items-center gap-3">
|
||||
<label className="text-sm font-medium text-gray-700">Gewichtungsprofil:</label>
|
||||
<select
|
||||
value={selectedProfile}
|
||||
onChange={e => onProfileChange(e.target.value)}
|
||||
className="rounded-md border-gray-300 shadow-sm text-sm focus:border-purple-500 focus:ring-purple-500"
|
||||
>
|
||||
{profiles.map(p => (
|
||||
<option key={p.id} value={p.id}>{p.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
||||
<div className="flex flex-col md:flex-row items-center gap-8">
|
||||
<ScoreCircle score={gci.gci_score} label="GCI Score" />
|
||||
<div className="flex-1 space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900">Gesamt-Compliance-Index</h3>
|
||||
<div className="flex items-center gap-3 mt-2">
|
||||
<MaturityBadge level={gci.maturity_level} />
|
||||
<span className="text-sm text-gray-500">
|
||||
Berechnet: {new Date(gci.calculated_at).toLocaleString('de-DE')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600">{MATURITY_INFO[gci.maturity_level]?.description || ''}</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">Regulierungsbereiche</h3>
|
||||
<div className="space-y-4">
|
||||
{gci.area_scores.map(area => (
|
||||
<AreaScoreBar key={area.regulation_id} name={area.regulation_name} score={area.score} weight={area.weight} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{history && history.snapshots.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">Verlauf</h3>
|
||||
<div className="flex items-end gap-2 h-32">
|
||||
{history.snapshots.map((snap, i) => (
|
||||
<div key={i} className="flex-1 flex flex-col items-center gap-1">
|
||||
<span className="text-xs text-gray-500">{snap.score.toFixed(0)}</span>
|
||||
<div
|
||||
className="w-full rounded-t transition-all duration-500"
|
||||
style={{ height: `${(snap.score / 100) * 100}%`, backgroundColor: getScoreRingColor(snap.score), minHeight: '4px' }}
|
||||
/>
|
||||
<span className="text-[10px] text-gray-400">
|
||||
{new Date(snap.calculated_at).toLocaleDateString('de-DE', { month: 'short' })}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-4">
|
||||
<div className="text-sm text-gray-500">Kritikalitaets-Multiplikator</div>
|
||||
<div className="text-2xl font-bold text-gray-900">{gci.criticality_multiplier.toFixed(2)}x</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-4">
|
||||
<div className="text-sm text-gray-500">Incident-Korrektur</div>
|
||||
<div className={`text-2xl font-bold ${gci.incident_adjustment < 0 ? 'text-red-600' : 'text-green-600'}`}>
|
||||
{gci.incident_adjustment > 0 ? '+' : ''}{gci.incident_adjustment.toFixed(1)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user