All 4 page.tsx files reduced well below 500 LOC (235/181/158/262) by extracting components and hooks into colocated _components/ and _hooks/ subdirectories. Zero behavior changes — logic relocated verbatim. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
117 lines
4.4 KiB
TypeScript
117 lines
4.4 KiB
TypeScript
'use client'
|
|
|
|
import { CanonicalControl, BACKEND_URL } from './helpers'
|
|
|
|
export interface ControlFormData {
|
|
[key: string]: unknown
|
|
}
|
|
|
|
interface CRUDDeps {
|
|
selectedControl: CanonicalControl | null
|
|
fullReload: () => Promise<void>
|
|
reviewMode: boolean
|
|
reviewIndex: number
|
|
reviewItems: CanonicalControl[]
|
|
setMode: (m: 'list' | 'detail' | 'create' | 'edit') => void
|
|
setSelectedControl: (c: CanonicalControl | null) => void
|
|
setReviewMode: (v: boolean) => void
|
|
setReviewItems: (items: CanonicalControl[]) => void
|
|
setReviewIndex: (i: number) => void
|
|
setSaving: (v: boolean) => void
|
|
setBulkProcessing: (v: boolean) => void
|
|
reviewCount: number
|
|
totalCount: number
|
|
stateFilter: string
|
|
}
|
|
|
|
export function createCRUDHandlers(deps: CRUDDeps) {
|
|
const {
|
|
selectedControl, fullReload, reviewMode, reviewIndex, reviewItems,
|
|
setMode, setSelectedControl, setReviewMode, setReviewItems, setReviewIndex,
|
|
setSaving, setBulkProcessing, reviewCount, totalCount, stateFilter,
|
|
} = deps
|
|
|
|
const handleCreate = async (data: ControlFormData) => {
|
|
setSaving(true)
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}?endpoint=create-control`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data),
|
|
})
|
|
if (!res.ok) { const err = await res.json(); alert(`Fehler: ${err.error || err.details || 'Unbekannt'}`); return }
|
|
await fullReload()
|
|
setMode('list')
|
|
} catch { alert('Netzwerkfehler') } finally { setSaving(false) }
|
|
}
|
|
|
|
const handleUpdate = async (data: ControlFormData) => {
|
|
if (!selectedControl) return
|
|
setSaving(true)
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}?endpoint=update-control&id=${selectedControl.control_id}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data),
|
|
})
|
|
if (!res.ok) { const err = await res.json(); alert(`Fehler: ${err.error || err.details || 'Unbekannt'}`); return }
|
|
await fullReload()
|
|
setSelectedControl(null)
|
|
setMode('list')
|
|
} catch { alert('Netzwerkfehler') } finally { setSaving(false) }
|
|
}
|
|
|
|
const handleDelete = async (controlId: string) => {
|
|
if (!confirm(`Control ${controlId} wirklich loeschen?`)) return
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}?id=${controlId}`, { method: 'DELETE' })
|
|
if (!res.ok && res.status !== 204) { alert('Fehler beim Loeschen'); return }
|
|
await fullReload()
|
|
setSelectedControl(null)
|
|
setMode('list')
|
|
} catch { alert('Netzwerkfehler') }
|
|
}
|
|
|
|
const handleReview = async (controlId: string, action: string) => {
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}?endpoint=review&id=${controlId}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ action }),
|
|
})
|
|
if (res.ok) {
|
|
await fullReload()
|
|
if (reviewMode) {
|
|
const remaining = reviewItems.filter(c => c.control_id !== controlId)
|
|
setReviewItems(remaining)
|
|
if (remaining.length > 0) {
|
|
const nextIdx = Math.min(reviewIndex, remaining.length - 1)
|
|
setReviewIndex(nextIdx)
|
|
setSelectedControl(remaining[nextIdx])
|
|
} else { setReviewMode(false); setSelectedControl(null); setMode('list') }
|
|
} else { setSelectedControl(null); setMode('list') }
|
|
}
|
|
} catch { /* ignore */ }
|
|
}
|
|
|
|
const handleBulkReject = async (sourceState: string) => {
|
|
const count = stateFilter === sourceState ? totalCount : reviewCount
|
|
if (!confirm(`Alle ${count} Controls mit Status "${sourceState}" auf "deprecated" setzen? Diese Aktion kann nicht rueckgaengig gemacht werden.`)) return
|
|
setBulkProcessing(true)
|
|
try {
|
|
const res = await fetch(`${BACKEND_URL}?endpoint=bulk-review`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ release_state: sourceState, action: 'reject' }),
|
|
})
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
alert(`${data.affected_count} Controls auf "deprecated" gesetzt.`)
|
|
await fullReload()
|
|
} else { const err = await res.json(); alert(`Fehler: ${err.error || err.details || 'Unbekannt'}`) }
|
|
} catch { alert('Netzwerkfehler') } finally { setBulkProcessing(false) }
|
|
}
|
|
|
|
return { handleCreate, handleUpdate, handleDelete, handleReview, handleBulkReject }
|
|
}
|