Files
breakpilot-compliance/admin-compliance/lib/sdk/vendor-compliance/context-actions.tsx
Sharang Parnerkar 7d8e5667c9 refactor(admin-compliance): split 7 oversized files under 500 LOC hard cap (batch 3)
- tom-generator/export/zip.ts: extract private helpers to zip-helpers.ts (544→342 LOC)
- tom-generator/export/docx.ts: extract private helpers to docx-helpers.ts (525→378 LOC)
- tom-generator/export/pdf.ts: extract private helpers to pdf-helpers.ts (517→446 LOC)
- tom-generator/demo-data/index.ts: extract DEMO_RISK_PROFILES + DEMO_EVIDENCE_DOCUMENTS to demo-data-part2.ts (518→360 LOC)
- einwilligungen/generator/privacy-policy-sections.ts: extract sections 5-7 to part2 (559→313 LOC)
- einwilligungen/export/pdf.ts: extract HTML/CSS helpers to pdf-helpers.ts (505→296 LOC)
- vendor-compliance/context.tsx: extract API action hooks to context-actions.tsx (509→286 LOC)

All originals re-export from sibling files — zero consumer import changes needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 00:43:41 +02:00

249 lines
7.1 KiB
TypeScript

'use client'
/**
* Vendor Compliance Context - API Actions
*
* Extracted from context.tsx to stay under 500 LOC hard cap.
* Contains loadData, refresh, and all CRUD API action hooks.
*/
import { useCallback } from 'react'
import type { Dispatch } from 'react'
import type { ProcessingActivity, VendorComplianceAction } from './types'
const API_BASE = '/api/sdk/v1/vendor-compliance'
export function useContextApiActions(
state: { processingActivities: ProcessingActivity[]; contracts: Array<{ id: string; vendorId: string; expirationDate?: Date | null; status: string }>; vendors: Array<{ id: string; contracts: string[] }> },
dispatch: Dispatch<VendorComplianceAction>
) {
const loadData = useCallback(async () => {
dispatch({ type: 'SET_LOADING', payload: true })
dispatch({ type: 'SET_ERROR', payload: null })
try {
const [
activitiesRes,
vendorsRes,
contractsRes,
findingsRes,
controlsRes,
controlInstancesRes,
] = await Promise.all([
fetch(`${API_BASE}/processing-activities`),
fetch(`${API_BASE}/vendors`),
fetch(`${API_BASE}/contracts`),
fetch(`${API_BASE}/findings`),
fetch(`${API_BASE}/controls`),
fetch(`${API_BASE}/control-instances`),
])
if (activitiesRes.ok) {
const data = await activitiesRes.json()
dispatch({ type: 'SET_PROCESSING_ACTIVITIES', payload: data.data || [] })
}
if (vendorsRes.ok) {
const data = await vendorsRes.json()
dispatch({ type: 'SET_VENDORS', payload: data.data || [] })
}
if (contractsRes.ok) {
const data = await contractsRes.json()
dispatch({ type: 'SET_CONTRACTS', payload: data.data || [] })
}
if (findingsRes.ok) {
const data = await findingsRes.json()
dispatch({ type: 'SET_FINDINGS', payload: data.data || [] })
}
if (controlsRes.ok) {
const data = await controlsRes.json()
dispatch({ type: 'SET_CONTROLS', payload: data.data || [] })
}
if (controlInstancesRes.ok) {
const data = await controlInstancesRes.json()
dispatch({ type: 'SET_CONTROL_INSTANCES', payload: data.data || [] })
}
} catch (error) {
console.error('Failed to load vendor compliance data:', error)
dispatch({
type: 'SET_ERROR',
payload: 'Fehler beim Laden der Daten',
})
} finally {
dispatch({ type: 'SET_LOADING', payload: false })
}
}, [dispatch])
const refresh = useCallback(async () => {
await loadData()
}, [loadData])
const createProcessingActivity = useCallback(
async (
data: Omit<ProcessingActivity, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>
): Promise<ProcessingActivity> => {
const response = await fetch(`${API_BASE}/processing-activities`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Erstellen der Verarbeitungstätigkeit')
}
const result = await response.json()
const activity = result.data
dispatch({ type: 'ADD_PROCESSING_ACTIVITY', payload: activity })
return activity
},
[dispatch]
)
const deleteProcessingActivity = useCallback(
async (id: string): Promise<void> => {
const response = await fetch(`${API_BASE}/processing-activities/${id}`, {
method: 'DELETE',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Löschen der Verarbeitungstätigkeit')
}
dispatch({ type: 'DELETE_PROCESSING_ACTIVITY', payload: id })
},
[dispatch]
)
const duplicateProcessingActivity = useCallback(
async (id: string): Promise<ProcessingActivity> => {
const original = state.processingActivities.find((a) => a.id === id)
if (!original) {
throw new Error('Verarbeitungstätigkeit nicht gefunden')
}
const { id: _id, vvtId: _vvtId, createdAt: _createdAt, updatedAt: _updatedAt, tenantId: _tenantId, ...rest } = original
const newActivity = await createProcessingActivity({
...rest,
vvtId: '',
name: {
de: `${original.name.de} (Kopie)`,
en: `${original.name.en} (Copy)`,
},
status: 'DRAFT',
})
return newActivity
},
[state.processingActivities, createProcessingActivity]
)
const deleteVendor = useCallback(
async (id: string): Promise<void> => {
const response = await fetch(`${API_BASE}/vendors/${id}`, {
method: 'DELETE',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Löschen des Vendors')
}
dispatch({ type: 'DELETE_VENDOR', payload: id })
},
[dispatch]
)
const deleteContract = useCallback(
async (id: string): Promise<void> => {
const contract = state.contracts.find((c) => c.id === id)
const response = await fetch(`${API_BASE}/contracts/${id}`, {
method: 'DELETE',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Löschen des Vertrags')
}
dispatch({ type: 'DELETE_CONTRACT', payload: id })
if (contract) {
const vendor = state.vendors.find((v) => v.id === contract.vendorId)
if (vendor) {
dispatch({
type: 'UPDATE_VENDOR',
payload: {
id: vendor.id,
data: { contracts: vendor.contracts.filter((cId) => cId !== id) },
},
})
}
}
},
[dispatch, state.contracts, state.vendors]
)
const startContractReview = useCallback(
async (contractId: string): Promise<void> => {
dispatch({
type: 'UPDATE_CONTRACT',
payload: { id: contractId, data: { reviewStatus: 'IN_PROGRESS' } },
})
const response = await fetch(`${API_BASE}/contracts/${contractId}/review`, {
method: 'POST',
})
if (!response.ok) {
dispatch({
type: 'UPDATE_CONTRACT',
payload: { id: contractId, data: { reviewStatus: 'FAILED' } },
})
const error = await response.json()
throw new Error(error.error || 'Fehler beim Starten der Vertragsprüfung')
}
const result = await response.json()
dispatch({
type: 'UPDATE_CONTRACT',
payload: {
id: contractId,
data: {
reviewStatus: 'COMPLETED',
reviewCompletedAt: new Date(),
complianceScore: result.data.complianceScore,
},
},
})
if (result.data.findings && result.data.findings.length > 0) {
dispatch({ type: 'ADD_FINDINGS', payload: result.data.findings })
}
},
[dispatch]
)
return {
loadData,
refresh,
createProcessingActivity,
deleteProcessingActivity,
duplicateProcessingActivity,
deleteVendor,
deleteContract,
startContractReview,
}
}