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>
176 lines
5.4 KiB
TypeScript
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
|
|
}
|