Files
breakpilot-lehrer/website/app/admin/unity-bridge/_components/AnalyticsTab.tsx
Benjamin Admin 0b37c5e692 [split-required] Split website + studio-v2 monoliths (Phase 3 continued)
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>
2026-04-24 17:52:36 +02:00

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>
)
}