backend-lehrer (10 files): - game/database.py (785 → 5), correction_api.py (683 → 4) - classroom_engine/antizipation.py (676 → 5) - llm_gateway schools/edu_search already done in prior batch klausur-service (12 files): - orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4) - zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5) - eh_templates.py (658 → 5), mail/api.py (651 → 5) - qdrant_service.py (638 → 5), training_api.py (625 → 4) website (6 pages): - middleware (696 → 8), mail (733 → 6), consent (628 → 8) - compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7) studio-v2 (3 components): - B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2) - dashboard-experimental (739 → 2) admin-lehrer (4 files): - uebersetzungen (769 → 4), manager (670 → 2) - ChunkBrowserQA (675 → 6), dsfa/page (674 → 5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
164 lines
4.5 KiB
TypeScript
164 lines
4.5 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import type { Risk, RiskFormData } from './types'
|
|
|
|
const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'
|
|
|
|
export function useRisks() {
|
|
const [risks, setRisks] = useState<Risk[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [viewMode, setViewMode] = useState<'matrix' | 'list'>('matrix')
|
|
const [selectedRisk, setSelectedRisk] = useState<Risk | null>(null)
|
|
const [editModalOpen, setEditModalOpen] = useState(false)
|
|
const [createModalOpen, setCreateModalOpen] = useState(false)
|
|
|
|
const [formData, setFormData] = useState<RiskFormData>({
|
|
risk_id: '',
|
|
title: '',
|
|
description: '',
|
|
category: 'compliance_gap',
|
|
likelihood: 3,
|
|
impact: 3,
|
|
owner: '',
|
|
treatment_plan: '',
|
|
status: 'open',
|
|
mitigating_controls: [],
|
|
residual_likelihood: null,
|
|
residual_impact: null,
|
|
})
|
|
|
|
useEffect(() => {
|
|
loadRisks()
|
|
}, [])
|
|
|
|
const loadRisks = async () => {
|
|
setLoading(true)
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}/api/v1/compliance/risks`)
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setRisks(data.risks || [])
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load risks:', error)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const openCreateModal = () => {
|
|
setFormData({
|
|
risk_id: `RISK-${String(risks.length + 1).padStart(3, '0')}`,
|
|
title: '',
|
|
description: '',
|
|
category: 'compliance_gap',
|
|
likelihood: 3,
|
|
impact: 3,
|
|
owner: '',
|
|
treatment_plan: '',
|
|
status: 'open',
|
|
mitigating_controls: [],
|
|
residual_likelihood: null,
|
|
residual_impact: null,
|
|
})
|
|
setCreateModalOpen(true)
|
|
}
|
|
|
|
const openEditModal = (risk: Risk) => {
|
|
setSelectedRisk(risk)
|
|
setFormData({
|
|
risk_id: risk.risk_id,
|
|
title: risk.title,
|
|
description: risk.description || '',
|
|
category: risk.category,
|
|
likelihood: risk.likelihood,
|
|
impact: risk.impact,
|
|
owner: risk.owner || '',
|
|
treatment_plan: risk.treatment_plan || '',
|
|
status: risk.status,
|
|
mitigating_controls: risk.mitigating_controls || [],
|
|
residual_likelihood: risk.residual_likelihood,
|
|
residual_impact: risk.residual_impact,
|
|
})
|
|
setEditModalOpen(true)
|
|
}
|
|
|
|
const handleCreate = async () => {
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}/api/v1/compliance/risks`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
risk_id: formData.risk_id,
|
|
title: formData.title,
|
|
description: formData.description,
|
|
category: formData.category,
|
|
likelihood: formData.likelihood,
|
|
impact: formData.impact,
|
|
owner: formData.owner,
|
|
treatment_plan: formData.treatment_plan,
|
|
mitigating_controls: formData.mitigating_controls,
|
|
}),
|
|
})
|
|
|
|
if (res.ok) {
|
|
setCreateModalOpen(false)
|
|
loadRisks()
|
|
} else {
|
|
const error = await res.text()
|
|
alert(`Fehler: ${error}`)
|
|
}
|
|
} catch (error) {
|
|
console.error('Create failed:', error)
|
|
alert('Fehler beim Erstellen')
|
|
}
|
|
}
|
|
|
|
const handleUpdate = async () => {
|
|
if (!selectedRisk) return
|
|
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}/api/v1/compliance/risks/${selectedRisk.risk_id}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
title: formData.title,
|
|
description: formData.description,
|
|
category: formData.category,
|
|
likelihood: formData.likelihood,
|
|
impact: formData.impact,
|
|
owner: formData.owner,
|
|
treatment_plan: formData.treatment_plan,
|
|
status: formData.status,
|
|
mitigating_controls: formData.mitigating_controls,
|
|
residual_likelihood: formData.residual_likelihood,
|
|
residual_impact: formData.residual_impact,
|
|
}),
|
|
})
|
|
|
|
if (res.ok) {
|
|
setEditModalOpen(false)
|
|
loadRisks()
|
|
} else {
|
|
const error = await res.text()
|
|
alert(`Fehler: ${error}`)
|
|
}
|
|
} catch (error) {
|
|
console.error('Update failed:', error)
|
|
alert('Fehler beim Aktualisieren')
|
|
}
|
|
}
|
|
|
|
return {
|
|
risks, loading,
|
|
viewMode, setViewMode,
|
|
selectedRisk,
|
|
editModalOpen, setEditModalOpen,
|
|
createModalOpen, setCreateModalOpen,
|
|
formData, setFormData,
|
|
openCreateModal, openEditModal,
|
|
handleCreate, handleUpdate,
|
|
}
|
|
}
|