'use client' import React, { useState, useEffect, useMemo } from 'react' import { useSDK } from '@/lib/sdk' import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader' import { Course, CourseCategory, Enrollment, EnrollmentStatus, AcademyStatistics, isEnrollmentOverdue, getDaysUntilDeadline } from '@/lib/sdk/academy/types' import { fetchSDKAcademyList, generateAllCourses, fetchCertificates, deleteEnrollment, completeEnrollment } from '@/lib/sdk/academy/api' import type { Certificate } from '@/lib/sdk/academy/types' import { Tab, TabId } from './_types' import { TabNavigation, StatCard, FilterBar } from './_components/shared' import { CourseCard } from './_components/CourseCard' import { EnrollmentCard } from './_components/EnrollmentCard' import { CertificatesTab } from './_components/CertificatesTab' import { EnrollmentEditModal } from './_components/EnrollmentEditModal' import { CourseEditModal } from './_components/CourseEditModal' import { SettingsTab } from './_components/SettingsTab' import { HeaderActions, GenerationResultBar, LoadingSpinner, OverdueAlert, InfoBox, EmptyCourses, EmptyEnrollments } from './_components/PageSections' // ============================================================================= // MAIN PAGE // ============================================================================= export default function AcademyPage() { const { state } = useSDK() const [activeTab, setActiveTab] = useState('overview') const [courses, setCourses] = useState([]) const [enrollments, setEnrollments] = useState([]) const [certificates, setCertificates] = useState([]) const [statistics, setStatistics] = useState(null) const [isLoading, setIsLoading] = useState(true) const [isGenerating, setIsGenerating] = useState(false) const [generateResult, setGenerateResult] = useState<{ generated: number; skipped: number; errors: string[] } | null>(null) // Modal states const [editingEnrollment, setEditingEnrollment] = useState(null) const [editingCourse, setEditingCourse] = useState(null) const [settingsSaved, setSettingsSaved] = useState(false) // Filters const [selectedCategory, setSelectedCategory] = useState('all') const [selectedStatus, setSelectedStatus] = useState('all') const [certSearch, setCertSearch] = useState('') // Load data from SDK backend useEffect(() => { loadData() }, []) // Calculate tab counts const tabCounts = useMemo(() => { return { courses: courses.length, enrollments: enrollments.filter(e => e.status !== 'completed').length, certificates: certificates.length || enrollments.filter(e => e.certificateId).length, overdue: enrollments.filter(e => isEnrollmentOverdue(e)).length } }, [courses, enrollments, certificates]) // Filtered courses const filteredCourses = useMemo(() => { let filtered = [...courses] if (selectedCategory !== 'all') { filtered = filtered.filter(c => c.category === selectedCategory) } return filtered.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) }, [courses, selectedCategory]) // Filtered enrollments const filteredEnrollments = useMemo(() => { let filtered = [...enrollments] if (selectedStatus !== 'all') { filtered = filtered.filter(e => e.status === selectedStatus) } // Sort: overdue first, then by deadline return filtered.sort((a, b) => { const aOverdue = isEnrollmentOverdue(a) ? -1 : 0 const bOverdue = isEnrollmentOverdue(b) ? -1 : 0 if (aOverdue !== bOverdue) return aOverdue - bOverdue return getDaysUntilDeadline(a.deadline) - getDaysUntilDeadline(b.deadline) }) }, [enrollments, selectedStatus]) // Enrollment counts per course const enrollmentCountByCourseId = useMemo(() => { const counts: Record = {} enrollments.forEach(e => { counts[e.courseId] = (counts[e.courseId] || 0) + 1 }) return counts }, [enrollments]) // Course name lookup const courseNameById = useMemo(() => { const map: Record = {} courses.forEach(c => { map[c.id] = c.title }) return map }, [courses]) const tabs: Tab[] = [ { id: 'overview', label: 'Uebersicht' }, { id: 'courses', label: 'Kurse', count: tabCounts.courses, countColor: 'bg-blue-100 text-blue-600' }, { id: 'enrollments', label: 'Einschreibungen', count: tabCounts.enrollments, countColor: 'bg-yellow-100 text-yellow-600' }, { id: 'certificates', label: 'Zertifikate', count: tabCounts.certificates, countColor: 'bg-green-100 text-green-600' }, { id: 'settings', label: 'Einstellungen' } ] const stepInfo = STEP_EXPLANATIONS['academy'] const loadData = async () => { setIsLoading(true) try { const [data, certs] = await Promise.allSettled([ fetchSDKAcademyList(), fetchCertificates(), ]) if (data.status === 'fulfilled') { setCourses(data.value.courses) setEnrollments(data.value.enrollments) setStatistics(data.value.statistics) } else { console.error('Failed to load Academy data:', data.reason) } if (certs.status === 'fulfilled') { setCertificates(certs.value) } } finally { setIsLoading(false) } } const handleCompleteEnrollment = async (id: string) => { try { await completeEnrollment(id) await loadData() } catch (e) { console.error('Failed to complete enrollment:', e) } } const handleDeleteEnrollment = async (id: string) => { if (!window.confirm('Einschreibung wirklich loeschen?')) return try { await deleteEnrollment(id) await loadData() } catch (e) { console.error('Failed to delete enrollment:', e) } } const handleGenerateAll = async () => { setIsGenerating(true) setGenerateResult(null) try { const result = await generateAllCourses() setGenerateResult({ generated: result.generated, skipped: result.skipped, errors: result.errors || [] }) // Reload data to show new courses await loadData() } catch (error) { console.error('Failed to generate courses:', error) setGenerateResult({ generated: 0, skipped: 0, errors: [error instanceof Error ? error.message : 'Fehler bei der Generierung'] }) } finally { setIsGenerating(false) } } const clearFilters = () => { setSelectedCategory('all') setSelectedStatus('all') } return (
{/* Step Header */} {/* Generation Result */} {generateResult && } {/* Tab Navigation */} {/* Loading State */} {isLoading ? ( ) : activeTab === 'settings' ? ( { setSettingsSaved(true); setTimeout(() => setSettingsSaved(false), 2000) }} saved={settingsSaved} /> ) : activeTab === 'certificates' ? ( ) : ( <> {/* Statistics (Overview Tab) */} {activeTab === 'overview' && statistics && (
0 ? 'red' : 'green'} />
)} {/* Overdue Alert */} {tabCounts.overdue > 0 && ( { setActiveTab('enrollments') setSelectedStatus('all') }} /> )} {/* Info Box (Overview Tab) */} {activeTab === 'overview' && } {/* Filters */} {/* Courses Tab */} {(activeTab === 'overview' || activeTab === 'courses') && (
{activeTab === 'courses' && (

Kurse ({filteredCourses.length})

)} {filteredCourses.map(course => ( ))}
)} {/* Enrollments Tab */} {activeTab === 'enrollments' && (

Einschreibungen ({filteredEnrollments.length})

{filteredEnrollments.map(enrollment => ( ))}
)} {/* Empty States */} {activeTab === 'courses' && filteredCourses.length === 0 && ( )} {activeTab === 'enrollments' && filteredEnrollments.length === 0 && ( )} )} {/* Enrollment Edit Modal */} {editingEnrollment && ( setEditingEnrollment(null)} onSaved={() => { setEditingEnrollment(null); loadData() }} /> )} {/* Course Edit Modal */} {editingCourse && ( setEditingCourse(null)} onSaved={() => { setEditingCourse(null); loadData() }} /> )}
) }