refactor(admin): split consent-management, control-library, incidents, training pages
Agent-completed splits committed after agents hit rate limits before committing their work. All 4 pages now under 500 LOC: - consent-management: 1303 -> 193 LOC (+ 7 _components, _hooks, _data, _types) - control-library: 1210 -> 298 LOC (+ _components, _types) - incidents: 1150 -> 373 LOC (+ _components) - training: 1127 -> 366 LOC (+ _components) Verification: next build clean (142 pages generated). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
'use client'
|
||||
|
||||
import type { TrainingStats, DeadlineInfo } from '@/lib/sdk/training/types'
|
||||
import { KPICard } from './KPICard'
|
||||
|
||||
interface OverviewTabProps {
|
||||
stats: TrainingStats
|
||||
deadlines: DeadlineInfo[]
|
||||
escalationResult: { total_checked: number; escalated: number } | null
|
||||
onDismissEscalation: () => void
|
||||
}
|
||||
|
||||
export function OverviewTab({ stats, deadlines, escalationResult, onDismissEscalation }: OverviewTabProps) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{escalationResult && (
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 flex items-center justify-between">
|
||||
<div>
|
||||
<span className="font-medium text-blue-900">Eskalation abgeschlossen: </span>
|
||||
<span className="text-blue-700">
|
||||
{escalationResult.total_checked} Zuweisungen geprueft, {escalationResult.escalated} eskaliert
|
||||
</span>
|
||||
</div>
|
||||
<button onClick={onDismissEscalation} className="text-blue-400 hover:text-blue-600 text-lg font-bold">×</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<KPICard label="Module" value={stats.total_modules} />
|
||||
<KPICard label="Zuweisungen" value={stats.total_assignments} />
|
||||
<KPICard label="Abschlussrate" value={`${stats.completion_rate.toFixed(1)}%`} color={stats.completion_rate >= 80 ? 'green' : stats.completion_rate >= 50 ? 'yellow' : 'red'} />
|
||||
<KPICard label="Ueberfaellig" value={stats.overdue_count} color={stats.overdue_count > 0 ? 'red' : 'green'} />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<KPICard label="Ausstehend" value={stats.pending_count} />
|
||||
<KPICard label="In Bearbeitung" value={stats.in_progress_count} />
|
||||
<KPICard label="Avg. Quiz-Score" value={`${stats.avg_quiz_score.toFixed(1)}%`} />
|
||||
<KPICard label="Deadlines (7d)" value={stats.upcoming_deadlines} color={stats.upcoming_deadlines > 5 ? 'yellow' : 'green'} />
|
||||
</div>
|
||||
|
||||
{/* Status Bar */}
|
||||
<div className="bg-white border rounded-lg p-4">
|
||||
<h3 className="text-sm font-medium text-gray-700 mb-3">Status-Verteilung</h3>
|
||||
{stats.total_assignments > 0 && (
|
||||
<div className="flex gap-1 h-6 rounded-full overflow-hidden bg-gray-100">
|
||||
{stats.completed_count > 0 && <div className="bg-green-500" style={{ width: `${(stats.completed_count / stats.total_assignments) * 100}%` }} title={`Abgeschlossen: ${stats.completed_count}`} />}
|
||||
{stats.in_progress_count > 0 && <div className="bg-blue-500" style={{ width: `${(stats.in_progress_count / stats.total_assignments) * 100}%` }} title={`In Bearbeitung: ${stats.in_progress_count}`} />}
|
||||
{stats.pending_count > 0 && <div className="bg-gray-400" style={{ width: `${(stats.pending_count / stats.total_assignments) * 100}%` }} title={`Ausstehend: ${stats.pending_count}`} />}
|
||||
{stats.overdue_count > 0 && <div className="bg-red-500" style={{ width: `${(stats.overdue_count / stats.total_assignments) * 100}%` }} title={`Ueberfaellig: ${stats.overdue_count}`} />}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex gap-4 mt-2 text-xs text-gray-500">
|
||||
<span className="flex items-center gap-1"><span className="w-3 h-3 rounded-full bg-green-500 inline-block" /> Abgeschlossen</span>
|
||||
<span className="flex items-center gap-1"><span className="w-3 h-3 rounded-full bg-blue-500 inline-block" /> In Bearbeitung</span>
|
||||
<span className="flex items-center gap-1"><span className="w-3 h-3 rounded-full bg-gray-400 inline-block" /> Ausstehend</span>
|
||||
<span className="flex items-center gap-1"><span className="w-3 h-3 rounded-full bg-red-500 inline-block" /> Ueberfaellig</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Deadlines */}
|
||||
{deadlines.length > 0 && (
|
||||
<div className="bg-white border rounded-lg p-4">
|
||||
<h3 className="text-sm font-medium text-gray-700 mb-3">Naechste Deadlines</h3>
|
||||
<div className="space-y-2">
|
||||
{deadlines.slice(0, 5).map(d => (
|
||||
<div key={d.assignment_id} className="flex items-center justify-between text-sm">
|
||||
<div>
|
||||
<span className="font-medium">{d.module_title}</span>
|
||||
<span className="text-gray-500 ml-2">({d.user_name})</span>
|
||||
</div>
|
||||
<span className={`px-2 py-0.5 rounded text-xs ${
|
||||
d.days_left <= 0 ? 'bg-red-100 text-red-700' :
|
||||
d.days_left <= 7 ? 'bg-yellow-100 text-yellow-700' :
|
||||
'bg-gray-100 text-gray-600'
|
||||
}`}>
|
||||
{d.days_left <= 0 ? `${Math.abs(d.days_left)} Tage ueberfaellig` : `${d.days_left} Tage`}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user