import type React from 'react' import type { VendorComplianceAction, VendorComplianceState, ProcessingActivity, Vendor, ContractDocument, Finding, ControlInstance, ExportFormat, } from './types' type Dispatch = React.Dispatch const API_BASE = '/api/sdk/v1/vendor-compliance' // ========================================== // DATA LOADING // ========================================== export async function loadAllData(dispatch: Dispatch): Promise { 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 }) } } // ========================================== // PROCESSING ACTIVITIES ACTIONS // ========================================== export async function apiCreateProcessingActivity( dispatch: Dispatch, data: Omit ): Promise { 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 Verarbeitungstaetigkeit') } const result = await response.json() const activity = result.data dispatch({ type: 'ADD_PROCESSING_ACTIVITY', payload: activity }) return activity } export async function apiUpdateProcessingActivity( dispatch: Dispatch, id: string, data: Partial ): Promise { const response = await fetch(`${API_BASE}/processing-activities/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Aktualisieren der Verarbeitungstaetigkeit') } dispatch({ type: 'UPDATE_PROCESSING_ACTIVITY', payload: { id, data } }) } export async function apiDeleteProcessingActivity( dispatch: Dispatch, id: string ): Promise { 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 Loeschen der Verarbeitungstaetigkeit') } dispatch({ type: 'DELETE_PROCESSING_ACTIVITY', payload: id }) } export async function apiDuplicateProcessingActivity( dispatch: Dispatch, state: VendorComplianceState, id: string ): Promise { const original = state.processingActivities.find((a) => a.id === id) if (!original) { throw new Error('Verarbeitungstaetigkeit nicht gefunden') } const { id: _id, vvtId: _vvtId, createdAt: _createdAt, updatedAt: _updatedAt, tenantId: _tenantId, ...rest } = original const newActivity = await apiCreateProcessingActivity(dispatch, { ...rest, vvtId: '', // Will be generated by backend name: { de: `${original.name.de} (Kopie)`, en: `${original.name.en} (Copy)`, }, status: 'DRAFT', }) return newActivity } // ========================================== // VENDOR ACTIONS // ========================================== export async function apiCreateVendor( dispatch: Dispatch, data: Omit ): Promise { const response = await fetch(`${API_BASE}/vendors`, { 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 des Vendors') } const result = await response.json() const vendor = result.data dispatch({ type: 'ADD_VENDOR', payload: vendor }) return vendor } export async function apiUpdateVendor( dispatch: Dispatch, id: string, data: Partial ): Promise { const response = await fetch(`${API_BASE}/vendors/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Aktualisieren des Vendors') } dispatch({ type: 'UPDATE_VENDOR', payload: { id, data } }) } export async function apiDeleteVendor( dispatch: Dispatch, id: string ): Promise { 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 Loeschen des Vendors') } dispatch({ type: 'DELETE_VENDOR', payload: id }) } // ========================================== // CONTRACT ACTIONS // ========================================== export async function apiUploadContract( dispatch: Dispatch, state: VendorComplianceState, vendorId: string, file: File, metadata: Partial ): Promise { const formData = new FormData() formData.append('file', file) formData.append('vendorId', vendorId) formData.append('metadata', JSON.stringify(metadata)) const response = await fetch(`${API_BASE}/contracts`, { method: 'POST', body: formData, }) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Hochladen des Vertrags') } const result = await response.json() const contract = result.data dispatch({ type: 'ADD_CONTRACT', payload: contract }) // Update vendor's contracts list const vendor = state.vendors.find((v) => v.id === vendorId) if (vendor) { dispatch({ type: 'UPDATE_VENDOR', payload: { id: vendorId, data: { contracts: [...vendor.contracts, contract.id] }, }, }) } return contract } export async function apiUpdateContract( dispatch: Dispatch, id: string, data: Partial ): Promise { const response = await fetch(`${API_BASE}/contracts/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Aktualisieren des Vertrags') } dispatch({ type: 'UPDATE_CONTRACT', payload: { id, data } }) } export async function apiDeleteContract( dispatch: Dispatch, state: VendorComplianceState, id: string ): Promise { 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 Loeschen des Vertrags') } dispatch({ type: 'DELETE_CONTRACT', payload: id }) // Update vendor's contracts list 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) }, }, }) } } } export async function apiStartContractReview( dispatch: Dispatch, contractId: string ): Promise { 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 Vertragspruefung') } const result = await response.json() // Update contract with review results dispatch({ type: 'UPDATE_CONTRACT', payload: { id: contractId, data: { reviewStatus: 'COMPLETED', reviewCompletedAt: new Date(), complianceScore: result.data.complianceScore, }, }, }) // Add findings if (result.data.findings && result.data.findings.length > 0) { dispatch({ type: 'ADD_FINDINGS', payload: result.data.findings }) } } // ========================================== // FINDINGS ACTIONS // ========================================== export async function apiUpdateFinding( dispatch: Dispatch, id: string, data: Partial ): Promise { const response = await fetch(`${API_BASE}/findings/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Aktualisieren des Findings') } dispatch({ type: 'UPDATE_FINDING', payload: { id, data } }) } export async function apiResolveFinding( dispatch: Dispatch, id: string, resolution: string ): Promise { await apiUpdateFinding(dispatch, id, { status: 'RESOLVED', resolution, resolvedAt: new Date(), }) } // ========================================== // CONTROL ACTIONS // ========================================== export async function apiUpdateControlInstance( dispatch: Dispatch, id: string, data: Partial ): Promise { const response = await fetch(`${API_BASE}/control-instances/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Aktualisieren des Control-Status') } dispatch({ type: 'UPDATE_CONTROL_INSTANCE', payload: { id, data } }) } // ========================================== // EXPORT ACTIONS // ========================================== export async function apiExportVVT( format: ExportFormat, activityIds?: string[] ): Promise { const params = new URLSearchParams({ format }) if (activityIds && activityIds.length > 0) { params.append('activityIds', activityIds.join(',')) } const response = await fetch(`${API_BASE}/export/vvt?${params}`) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Exportieren des VVT') } const blob = await response.blob() const url = URL.createObjectURL(blob) return url } export async function apiExportVendorAuditPack( vendorId: string, format: ExportFormat ): Promise { const params = new URLSearchParams({ format, vendorId }) const response = await fetch(`${API_BASE}/export/vendor-audit?${params}`) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Exportieren des Vendor Audit Packs') } const blob = await response.blob() const url = URL.createObjectURL(blob) return url } export async function apiExportRoPA( format: ExportFormat ): Promise { const params = new URLSearchParams({ format }) const response = await fetch(`${API_BASE}/export/ropa?${params}`) if (!response.ok) { const error = await response.json() throw new Error(error.error || 'Fehler beim Exportieren des RoPA') } const blob = await response.blob() const url = URL.createObjectURL(blob) return url }