Website (14 monoliths split): - compliance/page.tsx (1,519 → 9), docs/audit (1,262 → 20) - quality (1,231 → 16), alerts (1,203 → 10), docs (1,202 → 11) - i18n.ts (1,173 → 8 language files) - unity-bridge (1,094 → 12), backlog (1,087 → 6) - training (1,066 → 8), rag (1,063 → 8) - Deleted index_original.ts (4,899 LOC dead backup) Studio-v2 (5 monoliths split): - meet/page.tsx (1,481 → 9), messages (1,166 → 9) - AlertsB2BContext.tsx (1,165 → 5 modules) - alerts-b2b/page.tsx (1,019 → 6), korrektur/archiv (1,001 → 6) All existing imports preserved. Zero new TypeScript errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
93 lines
3.7 KiB
TypeScript
93 lines
3.7 KiB
TypeScript
'use client'
|
|
|
|
import type { AnalyticsOverview } from './types'
|
|
import { StatCard } from './StatCard'
|
|
|
|
export function AnalyticsTab({
|
|
analyticsOverview,
|
|
isLoadingAnalytics,
|
|
onFetchAnalytics,
|
|
}: {
|
|
analyticsOverview: AnalyticsOverview | null
|
|
isLoadingAnalytics: boolean
|
|
onFetchAnalytics: () => void
|
|
}) {
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Analytics Header */}
|
|
<div className="flex items-center justify-between">
|
|
<h2 className="text-lg font-semibold text-gray-900">Learning Analytics</h2>
|
|
<button
|
|
onClick={onFetchAnalytics}
|
|
disabled={isLoadingAnalytics}
|
|
className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 disabled:opacity-50 transition-colors"
|
|
>
|
|
{isLoadingAnalytics ? 'Laden...' : 'Aktualisieren'}
|
|
</button>
|
|
</div>
|
|
|
|
{analyticsOverview ? (
|
|
<>
|
|
{/* Stats Grid */}
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<StatCard title="Sessions" value={analyticsOverview.total_sessions} color="blue" />
|
|
<StatCard title="Schüler" value={analyticsOverview.unique_students} color="green" />
|
|
<StatCard
|
|
title="Ø Abschluss"
|
|
value={`${Math.round(analyticsOverview.avg_completion_rate * 100)}%`}
|
|
color={analyticsOverview.avg_completion_rate > 0.7 ? 'green' : 'yellow'}
|
|
/>
|
|
<StatCard
|
|
title="Ø Learning Gain"
|
|
value={analyticsOverview.avg_learning_gain !== null
|
|
? `${Math.round(analyticsOverview.avg_learning_gain * 100)}%`
|
|
: '-'
|
|
}
|
|
color={analyticsOverview.avg_learning_gain && analyticsOverview.avg_learning_gain > 0.1 ? 'green' : 'gray'}
|
|
/>
|
|
</div>
|
|
|
|
{/* Most Played Units */}
|
|
{analyticsOverview.most_played_units.length > 0 && (
|
|
<div className="bg-white rounded-lg border border-gray-200 p-4">
|
|
<h3 className="font-semibold text-gray-900 mb-3">Meistgespielte Units</h3>
|
|
<div className="space-y-2">
|
|
{analyticsOverview.most_played_units.map((item, i) => (
|
|
<div key={i} className="flex items-center justify-between p-2 bg-gray-50 rounded">
|
|
<span className="text-sm text-gray-900">{item.unit_id}</span>
|
|
<span className="text-sm font-medium text-gray-600">{item.count} Sessions</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Struggling Concepts */}
|
|
{analyticsOverview.struggling_concepts.length > 0 && (
|
|
<div className="bg-white rounded-lg border border-gray-200 p-4">
|
|
<h3 className="font-semibold text-gray-900 mb-3">Schwierige Konzepte</h3>
|
|
<div className="space-y-2">
|
|
{analyticsOverview.struggling_concepts.map((item, i) => (
|
|
<div key={i} className="flex items-center justify-between p-2 bg-red-50 rounded">
|
|
<span className="text-sm text-gray-900">{item.concept}</span>
|
|
<span className="text-sm font-medium text-red-600">{item.count} Fehler</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
) : (
|
|
<div className="text-center py-12 bg-gray-50 rounded-lg border border-gray-200">
|
|
<p className="text-gray-500">
|
|
{isLoadingAnalytics ? 'Lade Analytics...' : 'Keine Analytics-Daten verfügbar'}
|
|
</p>
|
|
<p className="text-sm text-gray-400 mt-2">
|
|
Analytics werden nach abgeschlossenen Sessions verfügbar.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|