Files
breakpilot-lehrer/klausur-service/frontend/src/hooks/useKlausur.tsx
Benjamin Boenisch 5a31f52310 Initial commit: breakpilot-lehrer - Lehrer KI Platform
Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website,
Klausur-Service, School-Service, Voice-Service, Geo-Service,
BreakPilot Drive, Agent-Core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:26 +01:00

176 lines
5.4 KiB
TypeScript

import { createContext, useContext, useState, useCallback, ReactNode } from 'react'
import { klausurApi, Klausur, StudentKlausur } from '../services/api'
interface KlausurContextType {
klausuren: Klausur[]
currentKlausur: Klausur | null
currentStudent: StudentKlausur | null
loading: boolean
error: string | null
loadKlausuren: () => Promise<void>
selectKlausur: (id: string, keepStudent?: boolean) => Promise<void>
selectStudent: (id: string) => void
setStudentById: (id: string) => void
refreshAndSelectStudent: (klausurId: string, studentId: string) => Promise<void>
createKlausur: (data: Partial<Klausur>) => Promise<Klausur>
deleteKlausur: (id: string) => Promise<void>
updateCriteria: (studentId: string, criterion: string, score: number) => Promise<void>
}
const KlausurContext = createContext<KlausurContextType | null>(null)
export function KlausurProvider({ children }: { children: ReactNode }) {
const [klausuren, setKlausuren] = useState<Klausur[]>([])
const [currentKlausur, setCurrentKlausur] = useState<Klausur | null>(null)
const [currentStudent, setCurrentStudent] = useState<StudentKlausur | null>(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const loadKlausuren = useCallback(async () => {
setLoading(true)
setError(null)
try {
const data = await klausurApi.listKlausuren()
setKlausuren(data)
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to load Klausuren')
} finally {
setLoading(false)
}
}, [])
const selectKlausur = useCallback(async (id: string, keepStudent = false) => {
setLoading(true)
setError(null)
try {
const klausur = await klausurApi.getKlausur(id)
setCurrentKlausur(klausur)
// Optionally keep the current student selection (for refresh after save)
if (keepStudent && currentStudent) {
const updatedStudent = klausur.students.find(s => s.id === currentStudent.id)
setCurrentStudent(updatedStudent || null)
} else if (!keepStudent) {
setCurrentStudent(null)
}
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to load Klausur')
} finally {
setLoading(false)
}
}, [currentStudent])
const selectStudent = useCallback((id: string) => {
if (!currentKlausur) return
const student = currentKlausur.students.find(s => s.id === id)
setCurrentStudent(student || null)
}, [currentKlausur])
// Set student directly by ID (for cases where we need to set before state updates)
const setStudentById = useCallback((id: string) => {
if (!currentKlausur) return
const student = currentKlausur.students.find(s => s.id === id)
if (student) {
setCurrentStudent(student)
}
}, [currentKlausur])
// Combined refresh and select - useful after upload
const refreshAndSelectStudent = useCallback(async (klausurId: string, studentId: string) => {
setLoading(true)
setError(null)
try {
const klausur = await klausurApi.getKlausur(klausurId)
setCurrentKlausur(klausur)
const student = klausur.students.find(s => s.id === studentId)
if (student) {
setCurrentStudent(student)
}
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to load Klausur')
} finally {
setLoading(false)
}
}, [])
const createKlausur = useCallback(async (data: Partial<Klausur>) => {
setLoading(true)
setError(null)
try {
const klausur = await klausurApi.createKlausur(data)
setKlausuren(prev => [...prev, klausur])
return klausur
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to create Klausur')
throw e
} finally {
setLoading(false)
}
}, [])
const deleteKlausur = useCallback(async (id: string) => {
setLoading(true)
setError(null)
try {
await klausurApi.deleteKlausur(id)
setKlausuren(prev => prev.filter(k => k.id !== id))
if (currentKlausur?.id === id) {
setCurrentKlausur(null)
setCurrentStudent(null)
}
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to delete Klausur')
throw e
} finally {
setLoading(false)
}
}, [currentKlausur])
const updateCriteria = useCallback(async (studentId: string, criterion: string, score: number) => {
try {
const updated = await klausurApi.updateCriteria(studentId, criterion, score)
if (currentKlausur) {
setCurrentKlausur({
...currentKlausur,
students: currentKlausur.students.map(s =>
s.id === studentId ? updated : s
)
})
}
if (currentStudent?.id === studentId) {
setCurrentStudent(updated)
}
} catch (e) {
setError(e instanceof Error ? e.message : 'Failed to update criteria')
throw e
}
}, [currentKlausur, currentStudent])
return (
<KlausurContext.Provider value={{
klausuren,
currentKlausur,
currentStudent,
loading,
error,
loadKlausuren,
selectKlausur,
selectStudent,
setStudentById,
refreshAndSelectStudent,
createKlausur,
deleteKlausur,
updateCriteria
}}>
{children}
</KlausurContext.Provider>
)
}
export function useKlausur() {
const context = useContext(KlausurContext)
if (!context) {
throw new Error('useKlausur must be used within a KlausurProvider')
}
return context
}