'use client' import { useState, useEffect } from 'react' import { useSDK, Control as SDKControl, ControlType, ImplementationStatus } from '@/lib/sdk' export function useControlsData() { const { state, dispatch } = useSDK() const [loading, setLoading] = useState(true) const [error, setError] = useState(null) // Track effectiveness locally as it's not in the SDK state type const [effectivenessMap, setEffectivenessMap] = useState>({}) // Track linked evidence per control const [evidenceMap, setEvidenceMap] = useState>({}) const fetchEvidenceForControls = async (_controlIds: string[]) => { try { const res = await fetch('/api/sdk/v1/compliance/evidence') if (res.ok) { const data = await res.json() const allEvidence = data.evidence || data if (Array.isArray(allEvidence)) { const map: Record = {} for (const ev of allEvidence) { const ctrlId = ev.control_id || '' if (!map[ctrlId]) map[ctrlId] = [] map[ctrlId].push({ id: ev.id, title: ev.title || ev.name || 'Nachweis', status: ev.status || 'pending', }) } setEvidenceMap(map) } } } catch { // Silently fail } } // Fetch controls from backend on mount useEffect(() => { const fetchControls = async () => { try { setLoading(true) const res = await fetch('/api/sdk/v1/compliance/controls') if (res.ok) { const data = await res.json() const backendControls = data.controls || data if (Array.isArray(backendControls) && backendControls.length > 0) { const mapped: SDKControl[] = backendControls.map((c: Record) => ({ id: (c.control_id || c.id) as string, name: (c.name || c.title || '') as string, description: (c.description || '') as string, type: ((c.type || c.control_type || 'TECHNICAL') as string).toUpperCase() as ControlType, category: (c.category || '') as string, implementationStatus: ((c.implementation_status || c.status || 'NOT_IMPLEMENTED') as string).toUpperCase() as ImplementationStatus, effectiveness: (c.effectiveness || 'LOW') as 'LOW' | 'MEDIUM' | 'HIGH', evidence: (c.evidence || []) as string[], owner: (c.owner || null) as string | null, dueDate: c.due_date ? new Date(c.due_date as string) : null, })) dispatch({ type: 'SET_STATE', payload: { controls: mapped } }) setError(null) fetchEvidenceForControls(mapped.map(c => c.id)) return } } } catch { // API not available — show empty state } finally { setLoading(false) } } fetchControls() }, []) // eslint-disable-line react-hooks/exhaustive-deps const handleStatusChange = async (controlId: string, status: ImplementationStatus) => { dispatch({ type: 'UPDATE_CONTROL', payload: { id: controlId, data: { implementationStatus: status } }, }) try { await fetch(`/api/sdk/v1/compliance/controls/${controlId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ implementation_status: status }), }) } catch { // Silently fail — SDK state is already updated } } const handleEffectivenessChange = async (controlId: string, effectiveness: number) => { setEffectivenessMap(prev => ({ ...prev, [controlId]: effectiveness })) try { await fetch(`/api/sdk/v1/compliance/controls/${controlId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ effectiveness_score: effectiveness }), }) } catch { // Silently fail — local state is already updated } } const handleAddControl = (data: { name: string; description: string; type: ControlType; category: string; owner: string }) => { const newControl: SDKControl = { id: `ctrl-${Date.now()}`, name: data.name, description: data.description, type: data.type, category: data.category, implementationStatus: 'NOT_IMPLEMENTED', effectiveness: 'LOW', evidence: [], owner: data.owner || null, dueDate: null, } dispatch({ type: 'ADD_CONTROL', payload: newControl }) } return { state, dispatch, loading, error, setError, effectivenessMap, evidenceMap, handleStatusChange, handleEffectivenessChange, handleAddControl, } }