feat: BreakPilot PWA - Full codebase (clean push without large binaries)
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed

All services: admin-v2, studio-v2, website, ai-compliance-sdk,
consent-service, klausur-service, voice-service, and infrastructure.
Large PDFs and compiled binaries excluded via .gitignore.
This commit is contained in:
BreakPilot Dev
2026-02-11 13:25:58 +01:00
commit 19855efacc
2512 changed files with 933814 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
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
}