'use client' import { useState, useEffect, useCallback } from 'react' import { useRouter } from 'next/navigation' import { useTheme } from '@/lib/ThemeContext' import { useLanguage } from '@/lib/LanguageContext' import { Sidebar } from '@/components/Sidebar' import { ThemeToggle } from '@/components/ThemeToggle' import { LanguageDropdown } from '@/components/LanguageDropdown' import { QRCodeUpload, UploadedFile } from '@/components/QRCodeUpload' import { korrekturApi, getKorrekturStats, type KorrekturStats, } from '@/lib/korrektur/api' import type { Klausur, CreateKlausurData } from './types' // LocalStorage Key for upload session const SESSION_ID_KEY = 'bp_korrektur_session' // ============================================================================= // GLASS CARD - Ultra Transparent (Apple Weather Style) // ============================================================================= interface GlassCardProps { children: React.ReactNode className?: string onClick?: () => void size?: 'sm' | 'md' | 'lg' delay?: number } function GlassCard({ children, className = '', onClick, size = 'md', delay = 0, isDark = true }: GlassCardProps & { isDark?: boolean }) { const [isVisible, setIsVisible] = useState(false) const [isHovered, setIsHovered] = useState(false) useEffect(() => { const timer = setTimeout(() => setIsVisible(true), delay) return () => clearTimeout(timer) }, [delay]) const sizeClasses = { sm: 'p-4', md: 'p-5', lg: 'p-6', } return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} onClick={onClick} > {children}
) } // ============================================================================= // STAT CARD // ============================================================================= interface StatCardProps { label: string value: string | number icon: React.ReactNode color?: string delay?: number isDark?: boolean } function StatCard({ label, value, icon, color = '#a78bfa', delay = 0, isDark = true }: StatCardProps) { return (
{icon}

{label}

{value}

) } // ============================================================================= // KLAUSUR CARD // ============================================================================= interface KlausurCardProps { klausur: Klausur onClick: () => void delay?: number isDark?: boolean } function KlausurCard({ klausur, onClick, delay = 0, isDark = true }: KlausurCardProps) { const progress = klausur.student_count ? Math.round(((klausur.completed_count || 0) / klausur.student_count) * 100) : 0 const statusColor = klausur.status === 'completed' ? '#22c55e' : klausur.status === 'in_progress' ? '#f97316' : '#6b7280' return (

{klausur.title}

{klausur.status === 'completed' ? 'Fertig' : klausur.status === 'in_progress' ? 'In Arbeit' : 'Entwurf'}

{klausur.subject} {klausur.semester} {klausur.year}

{klausur.student_count || 0} Arbeiten {progress}%
) } // ============================================================================= // CREATE KLAUSUR MODAL // ============================================================================= interface CreateKlausurModalProps { isOpen: boolean onClose: () => void onSubmit: (data: CreateKlausurData) => void isLoading: boolean isDark?: boolean } function CreateKlausurModal({ isOpen, onClose, onSubmit, isLoading, isDark = true }: CreateKlausurModalProps) { const [title, setTitle] = useState('') const [subject, setSubject] = useState('Deutsch') const [year, setYear] = useState(new Date().getFullYear()) const [semester, setSemester] = useState('Abitur') const [modus, setModus] = useState<'landes_abitur' | 'vorabitur'>('landes_abitur') if (!isOpen) return null const handleSubmit = (e: React.FormEvent) => { e.preventDefault() onSubmit({ title, subject, year, semester, modus }) } const inputClasses = isDark ? 'bg-white/10 border-white/20 text-white placeholder-white/40' : 'bg-slate-100 border-slate-300 text-slate-900 placeholder-slate-400' return (

Neue Klausur erstellen

setTitle(e.target.value)} placeholder="z.B. Deutsch LK Q4" className={`w-full p-3 rounded-xl border focus:ring-2 focus:ring-purple-500 focus:border-transparent ${inputClasses}`} required />
setYear(Number(e.target.value))} className={`w-full p-3 rounded-xl border focus:ring-2 focus:ring-purple-500 ${inputClasses}`} />
) } // ============================================================================= // MAIN PAGE // ============================================================================= export default function KorrekturPage() { const { isDark } = useTheme() const { t } = useLanguage() const router = useRouter() // State const [klausuren, setKlausuren] = useState([]) const [stats, setStats] = useState(null) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) // Modal states const [showCreateModal, setShowCreateModal] = useState(false) const [isCreating, setIsCreating] = useState(false) const [showQRModal, setShowQRModal] = useState(false) const [uploadSessionId, setUploadSessionId] = useState('') const [showDirectUpload, setShowDirectUpload] = useState(false) const [showEHUpload, setShowEHUpload] = useState(false) const [isDragging, setIsDragging] = useState(false) const [uploadedFiles, setUploadedFiles] = useState([]) const [ehFile, setEhFile] = useState(null) const [isUploading, setIsUploading] = useState(false) // Initialize session ID useEffect(() => { let storedSessionId = localStorage.getItem(SESSION_ID_KEY) if (!storedSessionId) { storedSessionId = `korrektur-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` localStorage.setItem(SESSION_ID_KEY, storedSessionId) } setUploadSessionId(storedSessionId) }, []) // Load data const loadData = useCallback(async () => { setIsLoading(true) setError(null) try { const [klausurenData, statsData] = await Promise.all([ korrekturApi.getKlausuren(), getKorrekturStats(), ]) setKlausuren(klausurenData) setStats(statsData) } catch (err) { console.error('Failed to load data:', err) setError(err instanceof Error ? err.message : 'Laden fehlgeschlagen') } finally { setIsLoading(false) } }, []) useEffect(() => { loadData() }, [loadData]) // Create klausur const handleCreateKlausur = async (data: CreateKlausurData) => { setIsCreating(true) try { const newKlausur = await korrekturApi.createKlausur(data) setKlausuren((prev) => [newKlausur, ...prev]) setShowCreateModal(false) // Navigate to the new klausur router.push(`/korrektur/${newKlausur.id}`) } catch (err) { console.error('Failed to create klausur:', err) setError(err instanceof Error ? err.message : 'Erstellung fehlgeschlagen') } finally { setIsCreating(false) } } // Handle QR uploaded files const handleMobileFileSelect = async (uploadedFile: UploadedFile) => { // For now, just close the modal - in production this would create a quick-start klausur setShowQRModal(false) // Could auto-create a klausur and navigate } // Handle direct file upload with drag & drop const handleDragOver = (e: React.DragEvent) => { e.preventDefault() setIsDragging(true) } const handleDragLeave = (e: React.DragEvent) => { e.preventDefault() setIsDragging(false) } const handleDrop = (e: React.DragEvent, isEH = false) => { e.preventDefault() setIsDragging(false) const files = Array.from(e.dataTransfer.files).filter( f => f.type === 'application/pdf' || f.type.startsWith('image/') ) if (isEH && files.length > 0) { setEhFile(files[0]) } else { setUploadedFiles(prev => [...prev, ...files]) } } const handleFileSelect = (e: React.ChangeEvent, isEH = false) => { if (!e.target.files) return const files = Array.from(e.target.files) if (isEH && files.length > 0) { setEhFile(files[0]) } else { setUploadedFiles(prev => [...prev, ...files]) } } const handleDirectUpload = async () => { if (uploadedFiles.length === 0) return setIsUploading(true) try { // Create a quick-start klausur const newKlausur = await korrekturApi.createKlausur({ title: `Schnellstart ${new Date().toLocaleDateString('de-DE')}`, subject: 'Deutsch', year: new Date().getFullYear(), semester: 'Abitur', modus: 'landes_abitur' }) // Upload each file for (let i = 0; i < uploadedFiles.length; i++) { await korrekturApi.uploadStudentWork(newKlausur.id, uploadedFiles[i], `Arbeit-${i + 1}`) } setShowDirectUpload(false) setUploadedFiles([]) router.push(`/korrektur/${newKlausur.id}`) } catch (err) { console.error('Upload failed:', err) setError(err instanceof Error ? err.message : 'Upload fehlgeschlagen') } finally { setIsUploading(false) } } const handleEHUpload = async () => { if (!ehFile) return setIsUploading(true) try { // Upload EH to backend await korrekturApi.uploadEH(ehFile) setShowEHUpload(false) setEhFile(null) loadData() // Refresh to show new EH } catch (err) { console.error('EH Upload failed:', err) setError(err instanceof Error ? err.message : 'EH Upload fehlgeschlagen') } finally { setIsUploading(false) } } return (
{/* Animated Background Blobs */}
{/* Sidebar */}
{/* Main Content */}
{/* Header */}

Korrekturplattform

KI-gestuetzte Abiturklausur-Korrektur

{/* Stats Cards */} {stats && (
} color="#f97316" delay={100} isDark={isDark} /> } color="#22c55e" delay={200} isDark={isDark} /> 0 ? `${stats.averageGrade} P` : '-'} icon={ } color="#3b82f6" delay={300} isDark={isDark} /> } color="#a78bfa" delay={400} isDark={isDark} />
)} {/* Error Display */} {error && (
{error}
)} {/* Loading */} {isLoading && (
)} {/* Klausuren Grid */} {!isLoading && ( <>

Klausuren

{klausuren.map((klausur, index) => ( router.push(`/korrektur/${klausur.id}`)} delay={500 + index * 50} isDark={isDark} /> ))} {/* New Klausur Card */} setShowCreateModal(true)} delay={500 + klausuren.length * 50} className={`min-h-[180px] border-2 border-dashed ${isDark ? 'border-white/20 hover:border-purple-400/50' : 'border-slate-300 hover:border-purple-400'}`} isDark={isDark} >

Neue Klausur

Klausur erstellen

{/* Quick Actions */}

Schnellaktionen

setShowQRModal(true)} delay={700} className="cursor-pointer" isDark={isDark} >
📱

QR Upload

Mit Handy scannen

setShowDirectUpload(true)} delay={750} className="cursor-pointer" isDark={isDark} >

Direkt hochladen

Drag & Drop

setShowCreateModal(true)} delay={800} className="cursor-pointer" isDark={isDark} >

Schnellstart

Direkt loslegen

setShowEHUpload(true)} delay={850} className="cursor-pointer" isDark={isDark} >

EH hochladen

Erwartungshorizont

router.push('/korrektur/archiv')} delay={900} className="cursor-pointer" isDark={isDark} >

Abitur-Archiv

EH durchsuchen

)}
{/* Create Klausur Modal */} setShowCreateModal(false)} onSubmit={handleCreateKlausur} isLoading={isCreating} isDark={isDark} /> {/* QR Code Modal */} {showQRModal && (
setShowQRModal(false)} />
setShowQRModal(false)} onFileUploaded={handleMobileFileSelect} />
)} {/* Direct Upload Modal */} {showDirectUpload && (
setShowDirectUpload(false)} />

Arbeiten hochladen

Ziehen Sie eingescannte Klausuren hierher oder klicken Sie zum Auswaehlen.

{/* Error Display in Modal */} {error && (
{error}
)} {/* Drag & Drop Zone */}
handleDrop(e, false)} className={`relative p-8 rounded-2xl border-2 border-dashed transition-colors ${ isDragging ? 'border-purple-400 bg-purple-500/10' : isDark ? 'border-white/20 hover:border-white/40' : 'border-slate-300 hover:border-slate-400' }`} > handleFileSelect(e, false)} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" />

{isDragging ? 'Dateien hier ablegen' : 'Dateien hierher ziehen'}

PDF oder Bilder (JPG, PNG)

{/* Uploaded Files List */} {uploadedFiles.length > 0 && (

{uploadedFiles.length} Datei(en) ausgewaehlt:

{uploadedFiles.map((file, idx) => (
{file.name}
))}
)} {/* Actions */}
)} {/* EH Upload Modal */} {showEHUpload && (
setShowEHUpload(false)} />

Erwartungshorizont hochladen

Laden Sie einen eigenen Erwartungshorizont fuer Vorabitur-Klausuren hoch.

{/* Drag & Drop Zone */}
handleDrop(e, true)} className={`relative p-8 rounded-2xl border-2 border-dashed transition-colors ${ isDragging ? 'border-orange-400 bg-orange-500/10' : isDark ? 'border-white/20 hover:border-white/40' : 'border-slate-300 hover:border-slate-400' }`} > handleFileSelect(e, true)} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" />

{ehFile ? ehFile.name : 'EH-Datei hierher ziehen'}

PDF oder Word-Dokument

{/* Selected File */} {ehFile && (
{ehFile.name}
)} {/* Actions */}
)}
) }