'use client' import { useEffect, useState, useCallback } from 'react' import { getAssignments, getContent, getModuleMedia, getQuiz, submitQuiz, startAssignment, generateCertificate, listCertificates, downloadCertificatePDF, getInteractiveManifest, completeAssignment, } from '@/lib/sdk/training/api' import type { TrainingAssignment, ModuleContent, TrainingMedia, QuizSubmitResponse, InteractiveVideoManifest, } from '@/lib/sdk/training/types' import { AssignmentsList } from './_components/AssignmentsList' import { ContentView } from './_components/ContentView' import { QuizView } from './_components/QuizView' import { CertificatesView } from './_components/CertificatesView' type Tab = 'assignments' | 'content' | 'quiz' | 'certificates' interface QuizQuestionItem { id: string question: string options: string[] difficulty: string } const TABS: { key: Tab; label: string }[] = [ { key: 'assignments', label: 'Meine Schulungen' }, { key: 'content', label: 'Schulungsinhalt' }, { key: 'quiz', label: 'Quiz' }, { key: 'certificates', label: 'Zertifikate' }, ] export default function LearnerPage() { const [activeTab, setActiveTab] = useState('assignments') const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [assignments, setAssignments] = useState([]) const [selectedAssignment, setSelectedAssignment] = useState(null) const [content, setContent] = useState(null) const [media, setMedia] = useState([]) const [questions, setQuestions] = useState([]) const [answers, setAnswers] = useState>({}) const [quizResult, setQuizResult] = useState(null) const [quizSubmitting, setQuizSubmitting] = useState(false) const [quizTimer, setQuizTimer] = useState(0) const [quizActive, setQuizActive] = useState(false) const [certificates, setCertificates] = useState([]) const [certGenerating, setCertGenerating] = useState(false) const [interactiveManifest, setInteractiveManifest] = useState(null) const [userId] = useState('00000000-0000-0000-0000-000000000001') const loadAssignments = useCallback(async () => { setLoading(true) try { const d = await getAssignments({ user_id: userId, limit: 100 }); setAssignments(d.assignments || []) } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { setLoading(false) } }, [userId]) const loadCertificates = useCallback(async () => { try { const d = await listCertificates(); setCertificates(d.certificates || []) } catch { /* may not exist */ } }, []) useEffect(() => { loadAssignments(); loadCertificates() }, [loadAssignments, loadCertificates]) useEffect(() => { if (!quizActive) return const interval = setInterval(() => setQuizTimer(t => t + 1), 1000) return () => clearInterval(interval) }, [quizActive]) async function loadInteractiveManifest(moduleId: string, assignmentId: string) { try { const manifest = await getInteractiveManifest(moduleId, assignmentId) setInteractiveManifest(manifest?.checkpoints?.length > 0 ? manifest : null) } catch { setInteractiveManifest(null) } } async function handleStartAssignment(assignment: TrainingAssignment) { try { await startAssignment(assignment.id) setSelectedAssignment({ ...assignment, status: 'in_progress' }) const [contentData, mediaData] = await Promise.all([ getContent(assignment.module_id).catch(() => null), getModuleMedia(assignment.module_id).catch(() => ({ media: [] })), ]) setContent(contentData); setMedia(mediaData.media || []) await loadInteractiveManifest(assignment.module_id, assignment.id) setActiveTab('content'); loadAssignments() } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Starten') } } async function handleResumeContent(assignment: TrainingAssignment) { setSelectedAssignment(assignment) try { const [contentData, mediaData] = await Promise.all([ getContent(assignment.module_id).catch(() => null), getModuleMedia(assignment.module_id).catch(() => ({ media: [] })), ]) setContent(contentData); setMedia(mediaData.media || []) await loadInteractiveManifest(assignment.module_id, assignment.id) setActiveTab('content') } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } } async function handleAllCheckpointsPassed() { if (!selectedAssignment) return try { await completeAssignment(selectedAssignment.id) setSelectedAssignment({ ...selectedAssignment, status: 'completed' }) loadAssignments() } catch { /* already completed */ } } async function handleStartQuiz() { if (!selectedAssignment) return try { const data = await getQuiz(selectedAssignment.module_id) setQuestions(data.questions || []); setAnswers({}); setQuizResult(null) setQuizTimer(0); setQuizActive(true); setActiveTab('quiz') } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Quiz-Laden') } } async function handleSubmitQuiz() { if (!selectedAssignment || questions.length === 0) return setQuizSubmitting(true); setQuizActive(false) try { const result = await submitQuiz(selectedAssignment.module_id, { assignment_id: selectedAssignment.id, answers: questions.map(q => ({ question_id: q.id, selected_index: answers[q.id] ?? -1 })), duration_seconds: quizTimer, }) setQuizResult(result); loadAssignments() } catch (e) { setError(e instanceof Error ? e.message : 'Quiz-Abgabe fehlgeschlagen') } finally { setQuizSubmitting(false) } } async function handleGenerateCertificate(assignmentId: string) { setCertGenerating(true) try { const data = await generateCertificate(assignmentId) if (data.certificate_id) { const blob = await downloadCertificatePDF(data.certificate_id) const url = URL.createObjectURL(blob) const a = document.createElement('a'); a.href = url a.download = `zertifikat-${data.certificate_id.substring(0, 8)}.pdf` a.click(); URL.revokeObjectURL(url) } loadAssignments(); loadCertificates() } catch (e) { setError(e instanceof Error ? e.message : 'Zertifikat-Erstellung fehlgeschlagen') } finally { setCertGenerating(false) } } async function handleDownloadPDF(certId: string) { try { const blob = await downloadCertificatePDF(certId) const url = URL.createObjectURL(blob) const a = document.createElement('a'); a.href = url a.download = `zertifikat-${certId.substring(0, 8)}.pdf` a.click(); URL.revokeObjectURL(url) } catch (e) { setError(e instanceof Error ? e.message : 'PDF-Download fehlgeschlagen') } } return (

Learner Portal

Absolvieren Sie Ihre Compliance-Schulungen

{error && (
{error}
)}
{TABS.map(tab => ( ))}
{activeTab === 'assignments' && ( )} {activeTab === 'content' && ( )} {activeTab === 'quiz' && ( setAnswers(prev => ({ ...prev, [qId]: oi }))} onSubmitQuiz={handleSubmitQuiz} onRetryQuiz={handleStartQuiz} onGenerateCertificate={handleGenerateCertificate} /> )} {activeTab === 'certificates' && ( )}
) }