Phase 1 — Python (klausur-service): 5 monoliths → 36 files - dsfa_corpus_ingestion.py (1,828 LOC → 5 files) - cv_ocr_engines.py (2,102 LOC → 7 files) - cv_layout.py (3,653 LOC → 10 files) - vocab_worksheet_api.py (2,783 LOC → 8 files) - grid_build_core.py (1,958 LOC → 6 files) Phase 2 — Go (edu-search-service, school-service): 8 monoliths → 19 files - staff_crawler.go (1,402 → 4), policy/store.go (1,168 → 3) - policy_handlers.go (700 → 2), repository.go (684 → 2) - search.go (592 → 2), ai_extraction_handlers.go (554 → 2) - seed_data.go (591 → 2), grade_service.go (646 → 2) Phase 3 — TypeScript (admin-lehrer): 45 monoliths → 220+ files - sdk/types.ts (2,108 → 16 domain files) - ai/rag/page.tsx (2,686 → 14 files) - 22 page.tsx files split into _components/ + _hooks/ - 11 component files split into sub-components - 10 SDK data catalogs added to loc-exceptions - Deleted dead backup index_original.ts (4,899 LOC) All original public APIs preserved via re-export facades. Zero new errors: Python imports verified, Go builds clean, TypeScript tsc --noEmit shows only pre-existing errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
148 lines
4.4 KiB
TypeScript
148 lines
4.4 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react'
|
|
import type { AbiturDokument } from '@/lib/education/abitur-docs-types'
|
|
import type { ViewMode, ThemaSuggestion } from '@/lib/education/abitur-archiv-types'
|
|
|
|
export function useAbiturArchiv() {
|
|
// Documents state
|
|
const [documents, setDocuments] = useState<AbiturDokument[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
// Pagination
|
|
const [page, setPage] = useState(1)
|
|
const [totalPages, setTotalPages] = useState(1)
|
|
const [total, setTotal] = useState(0)
|
|
const limit = 20
|
|
|
|
// View mode
|
|
const [viewMode, setViewMode] = useState<ViewMode>('grid')
|
|
|
|
// Filters
|
|
const [filterOpen, setFilterOpen] = useState(false)
|
|
const [filterFach, setFilterFach] = useState<string>('')
|
|
const [filterJahr, setFilterJahr] = useState<string>('')
|
|
const [filterBundesland, setFilterBundesland] = useState<string>('')
|
|
const [filterNiveau, setFilterNiveau] = useState<string>('')
|
|
const [filterTyp, setFilterTyp] = useState<string>('')
|
|
|
|
// Theme search
|
|
const [searchQuery, setSearchQuery] = useState<string>('')
|
|
const [themes, setThemes] = useState<ThemaSuggestion[]>([])
|
|
|
|
// Modal
|
|
const [selectedDocument, setSelectedDocument] = useState<AbiturDokument | null>(null)
|
|
|
|
// Stats
|
|
const [stats, setStats] = useState({ total: 0, indexed: 0, faecher: 0 })
|
|
|
|
const fetchDocuments = useCallback(async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
|
|
const params = new URLSearchParams()
|
|
params.set('page', page.toString())
|
|
params.set('limit', limit.toString())
|
|
if (filterFach) params.set('fach', filterFach)
|
|
if (filterJahr) params.set('jahr', filterJahr)
|
|
if (filterBundesland) params.set('bundesland', filterBundesland)
|
|
if (filterNiveau) params.set('niveau', filterNiveau)
|
|
if (filterTyp) params.set('typ', filterTyp)
|
|
if (searchQuery) params.set('thema', searchQuery)
|
|
|
|
try {
|
|
const response = await fetch(`/api/education/abitur-archiv?${params.toString()}`)
|
|
if (!response.ok) throw new Error('Fehler beim Laden der Dokumente')
|
|
|
|
const data = await response.json()
|
|
setDocuments(data.documents || [])
|
|
setTotalPages(data.total_pages || 1)
|
|
setTotal(data.total || 0)
|
|
setThemes(data.themes || [])
|
|
|
|
const indexed = (data.documents || []).filter((d: AbiturDokument) => d.status === 'indexed').length
|
|
const uniqueFaecher = new Set((data.documents || []).map((d: AbiturDokument) => d.fach)).size
|
|
setStats({ total: data.total || 0, indexed, faecher: uniqueFaecher })
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Unbekannter Fehler')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [page, filterFach, filterJahr, filterBundesland, filterNiveau, filterTyp, searchQuery])
|
|
|
|
useEffect(() => {
|
|
fetchDocuments()
|
|
}, [fetchDocuments])
|
|
|
|
const clearFilters = () => {
|
|
setFilterFach('')
|
|
setFilterJahr('')
|
|
setFilterBundesland('')
|
|
setFilterNiveau('')
|
|
setFilterTyp('')
|
|
setSearchQuery('')
|
|
setPage(1)
|
|
}
|
|
|
|
const handleSearch = (query: string) => {
|
|
setSearchQuery(query)
|
|
setPage(1)
|
|
}
|
|
|
|
const handleClearSearch = () => {
|
|
setSearchQuery('')
|
|
setPage(1)
|
|
}
|
|
|
|
const handleDownload = (doc: AbiturDokument) => {
|
|
const link = window.document.createElement('a')
|
|
link.href = doc.file_path
|
|
link.download = doc.dateiname
|
|
link.click()
|
|
}
|
|
|
|
const handleAddToKlausur = (doc: AbiturDokument) => {
|
|
const params = new URLSearchParams()
|
|
params.set('archiv_doc_id', doc.id)
|
|
params.set('aufgabentyp', doc.typ === 'erwartungshorizont' ? 'vorlage' : 'aufgabe')
|
|
window.location.href = `/education/klausur-korrektur?${params.toString()}`
|
|
}
|
|
|
|
const hasActiveFilters = !!(filterFach || filterJahr || filterBundesland || filterNiveau || filterTyp || searchQuery)
|
|
|
|
return {
|
|
documents,
|
|
loading,
|
|
error,
|
|
page,
|
|
setPage,
|
|
totalPages,
|
|
total,
|
|
limit,
|
|
viewMode,
|
|
setViewMode,
|
|
filterOpen,
|
|
setFilterOpen,
|
|
filterFach,
|
|
setFilterFach,
|
|
filterJahr,
|
|
setFilterJahr,
|
|
filterBundesland,
|
|
setFilterBundesland,
|
|
filterNiveau,
|
|
setFilterNiveau,
|
|
filterTyp,
|
|
setFilterTyp,
|
|
searchQuery,
|
|
selectedDocument,
|
|
setSelectedDocument,
|
|
stats,
|
|
clearFilters,
|
|
handleSearch,
|
|
handleClearSearch,
|
|
handleDownload,
|
|
handleAddToKlausur,
|
|
hasActiveFilters,
|
|
fetchDocuments,
|
|
}
|
|
}
|