'use client' /** * Klausur-Korrektur Admin Page * * Hauptseite für die KI-gestützte Abitur-Korrektur. * Zeigt alle Klausuren und ermöglicht das Erstellen neuer Klausuren. */ import { useState, useEffect, useCallback } from 'react' import AdminLayout from '@/components/admin/AdminLayout' import Link from 'next/link' import type { Klausur, GradeInfo, STATUS_COLORS, STATUS_LABELS } from './types' // API Base URL for klausur-service const API_BASE = process.env.NEXT_PUBLIC_KLAUSUR_SERVICE_URL || 'http://localhost:8086' // Tab definitions type TabId = 'willkommen' | 'klausuren' | 'erstellen' | 'direktupload' | 'statistiken' const tabs: { id: TabId; name: string; icon: JSX.Element; hidden?: boolean }[] = [ { id: 'willkommen', name: 'Start', icon: ( ), }, { id: 'klausuren', name: 'Klausuren', icon: ( ), }, { id: 'erstellen', name: 'Neue Klausur', icon: ( ), }, { id: 'direktupload', name: 'Schnellstart', hidden: true, // Hidden from tab bar, accessible via willkommen icon: ( ), }, { id: 'statistiken', name: 'Statistiken', icon: ( ), }, ] interface CreateKlausurForm { title: string subject: string year: number semester: string modus: 'abitur' | 'vorabitur' } interface VorabiturEHForm { aufgabentyp: string titel: string text_titel: string text_autor: string aufgabenstellung: string } interface EHTemplate { aufgabentyp: string name: string description: string category: string } // Direktupload form interface interface DirektuploadForm { files: File[] ehFile: File | null ehText: string aufgabentyp: string klausurTitle: string } export default function KlausurKorrekturPage() { // Check localStorage for returning users const [activeTab, setActiveTab] = useState(() => { if (typeof window !== 'undefined') { const hasVisited = localStorage.getItem('klausur_korrektur_visited') return hasVisited ? 'klausuren' : 'willkommen' } return 'willkommen' }) const [klausuren, setKlausuren] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [creating, setCreating] = useState(false) const [gradeInfo, setGradeInfo] = useState(null) // Vorabitur templates const [templates, setTemplates] = useState([]) const [loadingTemplates, setLoadingTemplates] = useState(false) // Form state for creating new Klausur const [form, setForm] = useState({ title: '', subject: 'Deutsch', year: new Date().getFullYear(), semester: 'Abitur', modus: 'abitur', }) // Vorabitur EH form const [ehForm, setEhForm] = useState({ aufgabentyp: '', titel: '', text_titel: '', text_autor: '', aufgabenstellung: '', }) // Direktupload form const [direktForm, setDirektForm] = useState({ files: [], ehFile: null, ehText: '', aufgabentyp: '', klausurTitle: `Schnellkorrektur ${new Date().toLocaleDateString('de-DE')}`, }) const [direktStep, setDirektStep] = useState<1 | 2 | 3>(1) const [uploading, setUploading] = useState(false) // Fetch klausuren const fetchKlausuren = useCallback(async () => { try { setLoading(true) const res = await fetch(`${API_BASE}/api/v1/klausuren`) if (res.ok) { const data = await res.json() setKlausuren(Array.isArray(data) ? data : data.klausuren || []) setError(null) } else { setError(`Fehler beim Laden: ${res.status}`) } } catch (err) { console.error('Failed to fetch klausuren:', err) setError('Verbindung zum Klausur-Service fehlgeschlagen') } finally { setLoading(false) } }, []) // Fetch grade info const fetchGradeInfo = useCallback(async () => { try { const res = await fetch(`${API_BASE}/api/v1/grade-info`) if (res.ok) { const data = await res.json() setGradeInfo(data) } } catch (err) { console.error('Failed to fetch grade info:', err) } }, []) // Fetch Vorabitur templates const fetchTemplates = useCallback(async () => { try { setLoadingTemplates(true) const res = await fetch(`${API_BASE}/api/v1/vorabitur/templates`) if (res.ok) { const data = await res.json() setTemplates(data.templates || []) } } catch (err) { console.error('Failed to fetch templates:', err) } finally { setLoadingTemplates(false) } }, []) useEffect(() => { fetchKlausuren() fetchGradeInfo() }, [fetchKlausuren, fetchGradeInfo]) // Fetch templates when Vorabitur mode is selected useEffect(() => { if (form.modus === 'vorabitur' && templates.length === 0) { fetchTemplates() } }, [form.modus, templates.length, fetchTemplates]) // Create new Klausur const handleCreateKlausur = async (e: React.FormEvent) => { e.preventDefault() if (!form.title.trim()) { setError('Bitte einen Titel eingeben') return } // Validate Vorabitur form if (form.modus === 'vorabitur') { if (!ehForm.aufgabentyp) { setError('Bitte einen Aufgabentyp auswählen') return } if (!ehForm.aufgabenstellung.trim()) { setError('Bitte die Aufgabenstellung eingeben') return } } try { setCreating(true) // First create the Klausur const res = await fetch(`${API_BASE}/api/v1/klausuren`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form), }) if (!res.ok) { const errorData = await res.json() setError(errorData.detail || 'Fehler beim Erstellen') return } const newKlausur = await res.json() // If Vorabitur mode, create the custom EH if (form.modus === 'vorabitur') { const ehRes = await fetch(`${API_BASE}/api/v1/klausuren/${newKlausur.id}/vorabitur-eh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ aufgabentyp: ehForm.aufgabentyp, titel: ehForm.titel || `EH: ${form.title}`, text_titel: ehForm.text_titel || null, text_autor: ehForm.text_autor || null, aufgabenstellung: ehForm.aufgabenstellung, }), }) if (!ehRes.ok) { // Klausur was created but EH failed - warn but don't fail console.error('Failed to create EH:', await ehRes.text()) setError('Klausur erstellt, aber Erwartungshorizont konnte nicht erstellt werden. Sie koennen ihn spaeter hinzufuegen.') } } setKlausuren(prev => [newKlausur, ...prev]) setForm({ title: '', subject: 'Deutsch', year: new Date().getFullYear(), semester: 'Abitur', modus: 'abitur', }) setEhForm({ aufgabentyp: '', titel: '', text_titel: '', text_autor: '', aufgabenstellung: '', }) setActiveTab('klausuren') if (!error) setError(null) } catch (err) { console.error('Failed to create klausur:', err) setError('Fehler beim Erstellen der Klausur') } finally { setCreating(false) } } // Delete Klausur const handleDeleteKlausur = async (id: string) => { if (!confirm('Klausur wirklich löschen? Alle Studentenarbeiten werden ebenfalls gelöscht.')) { return } try { const res = await fetch(`${API_BASE}/api/v1/klausuren/${id}`, { method: 'DELETE', }) if (res.ok) { setKlausuren(prev => prev.filter(k => k.id !== id)) } else { setError('Fehler beim Löschen') } } catch (err) { console.error('Failed to delete klausur:', err) setError('Fehler beim Löschen der Klausur') } } // Render Klausuren list const renderKlausurenTab = () => (
{/* Header */}

Alle Klausuren

{klausuren.length} Klausuren insgesamt

{/* Klausuren Grid */} {loading ? (
) : klausuren.length === 0 ? (

Keine Klausuren

Erstellen Sie Ihre erste Klausur zum Korrigieren.

) : (
{klausuren.map((klausur) => (
{/* Header */}

{klausur.title}

{klausur.subject} - {klausur.year}

{klausur.modus === 'abitur' ? 'Abitur' : 'Vorabitur'}
{/* Stats */}
{klausur.student_count || 0} Arbeiten
{klausur.completed_count || 0} fertig
{/* Progress bar */} {(klausur.student_count || 0) > 0 && (
Fortschritt {Math.round(((klausur.completed_count || 0) / (klausur.student_count || 1)) * 100)}%
)} {/* Actions */}
Korrigieren
))}
)}
) // Render Create form const renderErstellenTab = () => (

Neue Klausur erstellen

{/* Title */}
setForm(prev => ({ ...prev, title: e.target.value }))} placeholder="z.B. Deutsch LK Abitur 2025 - Kurs D1" className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" required />
{/* Subject + Year */}
setForm(prev => ({ ...prev, year: parseInt(e.target.value) }))} min={2020} max={2030} className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" />
{/* Semester + Modus */}
{/* Vorabitur EH Form */} {form.modus === 'vorabitur' && (

Eigenen Erwartungshorizont erstellen

Waehlen Sie einen Aufgabentyp und beschreiben Sie die Aufgabenstellung. Der EH wird automatisch mit Ihrer Klausur verknuepft.

{/* Aufgabentyp Selection */}
{loadingTemplates ? (
Lade Vorlagen...
) : ( )} {ehForm.aufgabentyp && templates.find(t => t.aufgabentyp === ehForm.aufgabentyp) && (

{templates.find(t => t.aufgabentyp === ehForm.aufgabentyp)?.description}

)}
{/* Text Details (optional) */}
setEhForm(prev => ({ ...prev, text_titel: e.target.value }))} placeholder="z.B. 'Die Verwandlung'" className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" />
setEhForm(prev => ({ ...prev, text_autor: e.target.value }))} placeholder="z.B. 'Franz Kafka'" className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" />
{/* Aufgabenstellung */}