'use client' import { useState, useEffect } from 'react' import dynamic from 'next/dynamic' import { ExecutiveDashboardData } from '../types' const ComplianceTrendChart = dynamic( () => import('@/components/compliance/charts/ComplianceTrendChart'), { ssr: false, loading: () =>
} ) interface ExecutiveTabProps { loading: boolean onRefresh: () => void } export default function ExecutiveTab({ loading, onRefresh }: ExecutiveTabProps) { const [executiveData, setExecutiveData] = useState(null) const [execLoading, setExecLoading] = useState(true) const [error, setError] = useState(null) const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000' useEffect(() => { loadExecutiveData() }, []) const loadExecutiveData = async () => { setExecLoading(true) setError(null) try { const res = await fetch(`${BACKEND_URL}/api/v1/compliance/dashboard/executive`) if (res.ok) { setExecutiveData(await res.json()) } else { setError('Executive Dashboard konnte nicht geladen werden') } } catch (err) { console.error('Failed to load executive dashboard:', err) setError('Verbindung zum Backend fehlgeschlagen') } finally { setExecLoading(false) } } if (execLoading) { return (
) } if (error || !executiveData) { return (

{error || 'Keine Daten verfuegbar'}

) } const { traffic_light_status, overall_score, score_trend, score_change, top_risks, upcoming_deadlines, team_workload } = executiveData const trafficLightColors = { green: { bg: 'bg-green-500', ring: 'ring-green-200', text: 'text-green-700', label: 'Gut' }, yellow: { bg: 'bg-yellow-500', ring: 'ring-yellow-200', text: 'text-yellow-700', label: 'Achtung' }, red: { bg: 'bg-red-500', ring: 'ring-red-200', text: 'text-red-700', label: 'Kritisch' }, } const tlConfig = trafficLightColors[traffic_light_status] return (
{/* Header Row: Traffic Light + Key Metrics */}
{/* Charts Row */}
{/* Bottom Row: Deadlines + Workload */}
{/* Last Updated */}
Zuletzt aktualisiert: {new Date(executiveData.last_updated).toLocaleString('de-DE')}
) } // ============================================================================ // Sub-components // ============================================================================ function TrafficLightCard({ tlConfig, overall_score, score_change }: { tlConfig: { bg: string; ring: string; text: string; label: string } overall_score: number score_change: number | null }) { return (
{overall_score.toFixed(0)}%

{tlConfig.label}

Erfuellungsgrad

{score_change !== null && (

= 0 ? 'text-green-600' : 'text-red-600'}`}> {score_change >= 0 ? '\u2191' : '\u2193'} {Math.abs(score_change).toFixed(1)}% zum Vormonat

)}
) } function MetricCard({ label, value, detail, iconBg, iconColor, iconPath }: { label: string value: number detail: string iconBg: string iconColor: string iconPath: string }) { return (

{label}

{value}

{detail}

) } function TrendChartCard({ score_trend, onRefresh }: { score_trend: { date: string; score: number; label: string }[] onRefresh: () => void }) { return (

Compliance-Trend (12 Monate)

) } function TopRisksCard({ top_risks }: { top_risks: ExecutiveDashboardData['top_risks'] }) { const riskColors: Record = { critical: 'bg-red-100 text-red-700 border-red-200', high: 'bg-orange-100 text-orange-700 border-orange-200', medium: 'bg-yellow-100 text-yellow-700 border-yellow-200', low: 'bg-green-100 text-green-700 border-green-200', } return (

Top 5 Risiken

{top_risks.length === 0 ? (

Keine offenen Risiken

) : (
{top_risks.map((risk) => (
{risk.risk_level.toUpperCase()}

{risk.title}

{risk.owner || 'Kein Owner'}

{risk.risk_id}
))}
)}
) } function DeadlinesCard({ upcoming_deadlines }: { upcoming_deadlines: ExecutiveDashboardData['upcoming_deadlines'] }) { const statusColors: Record = { overdue: 'bg-red-100 text-red-700', at_risk: 'bg-yellow-100 text-yellow-700', on_track: 'bg-green-100 text-green-700', } return (

Naechste Fristen

{upcoming_deadlines.length === 0 ? (

Keine anstehenden Fristen

) : (
{upcoming_deadlines.slice(0, 5).map((deadline) => (
{deadline.days_remaining < 0 ? `${Math.abs(deadline.days_remaining)}d ueberfaellig` : deadline.days_remaining === 0 ? 'Heute' : `${deadline.days_remaining}d`}

{deadline.title}

{new Date(deadline.deadline).toLocaleDateString('de-DE')}

))}
)}
) } function WorkloadCard({ team_workload }: { team_workload: ExecutiveDashboardData['team_workload'] }) { return (

Team-Auslastung

{team_workload.length === 0 ? (

Keine Daten verfuegbar

) : (
{team_workload.slice(0, 5).map((member) => (
{member.name} {member.completed_tasks}/{member.total_tasks} ({member.completion_rate.toFixed(0)}%)
))}
)}
) }