Split the 1371-line VVT page into _components/ extractions (FormPrimitives, api, TabVerzeichnis, TabEditor, TabExport) to bring page.tsx under the 300 LOC soft target. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
141 lines
5.2 KiB
TypeScript
141 lines
5.2 KiB
TypeScript
import type { VVTActivity, VVTOrganizationHeader } from '@/lib/sdk/vvt-types'
|
|
|
|
export const VVT_API_BASE = '/api/sdk/v1/compliance/vvt'
|
|
|
|
export function activityFromApi(raw: any): VVTActivity {
|
|
return {
|
|
id: raw.id,
|
|
vvtId: raw.vvt_id,
|
|
name: raw.name || '',
|
|
description: raw.description || '',
|
|
purposes: raw.purposes || [],
|
|
legalBases: raw.legal_bases || [],
|
|
dataSubjectCategories: raw.data_subject_categories || [],
|
|
personalDataCategories: raw.personal_data_categories || [],
|
|
recipientCategories: raw.recipient_categories || [],
|
|
thirdCountryTransfers: raw.third_country_transfers || [],
|
|
retentionPeriod: raw.retention_period || { description: '' },
|
|
tomDescription: raw.tom_description || '',
|
|
businessFunction: raw.business_function || 'other',
|
|
systems: raw.systems || [],
|
|
deploymentModel: raw.deployment_model || 'cloud',
|
|
dataSources: raw.data_sources || [],
|
|
dataFlows: raw.data_flows || [],
|
|
protectionLevel: raw.protection_level || 'MEDIUM',
|
|
dpiaRequired: raw.dpia_required || false,
|
|
structuredToms: raw.structured_toms || { accessControl: [], confidentiality: [], integrity: [], availability: [], separation: [] },
|
|
status: raw.status || 'DRAFT',
|
|
responsible: raw.responsible || '',
|
|
owner: raw.owner || '',
|
|
createdAt: raw.created_at || new Date().toISOString(),
|
|
updatedAt: raw.updated_at || raw.created_at || new Date().toISOString(),
|
|
}
|
|
}
|
|
|
|
export function activityToApi(act: VVTActivity): Record<string, unknown> {
|
|
return {
|
|
vvt_id: act.vvtId,
|
|
name: act.name,
|
|
description: act.description,
|
|
purposes: act.purposes,
|
|
legal_bases: act.legalBases,
|
|
data_subject_categories: act.dataSubjectCategories,
|
|
personal_data_categories: act.personalDataCategories,
|
|
recipient_categories: act.recipientCategories,
|
|
third_country_transfers: act.thirdCountryTransfers,
|
|
retention_period: act.retentionPeriod,
|
|
tom_description: act.tomDescription,
|
|
business_function: act.businessFunction,
|
|
systems: act.systems,
|
|
deployment_model: act.deploymentModel,
|
|
data_sources: act.dataSources,
|
|
data_flows: act.dataFlows,
|
|
protection_level: act.protectionLevel,
|
|
dpia_required: act.dpiaRequired,
|
|
structured_toms: act.structuredToms,
|
|
status: act.status,
|
|
responsible: act.responsible,
|
|
owner: act.owner,
|
|
}
|
|
}
|
|
|
|
export function orgHeaderFromApi(raw: any): VVTOrganizationHeader {
|
|
return {
|
|
organizationName: raw.organization_name || '',
|
|
industry: raw.industry || '',
|
|
locations: raw.locations || [],
|
|
employeeCount: raw.employee_count || 0,
|
|
dpoName: raw.dpo_name || '',
|
|
dpoContact: raw.dpo_contact || '',
|
|
vvtVersion: raw.vvt_version || '1.0',
|
|
lastReviewDate: raw.last_review_date || '',
|
|
nextReviewDate: raw.next_review_date || '',
|
|
reviewInterval: raw.review_interval || 'annual',
|
|
}
|
|
}
|
|
|
|
export function orgHeaderToApi(org: VVTOrganizationHeader): Record<string, unknown> {
|
|
return {
|
|
organization_name: org.organizationName,
|
|
industry: org.industry,
|
|
locations: org.locations,
|
|
employee_count: org.employeeCount,
|
|
dpo_name: org.dpoName,
|
|
dpo_contact: org.dpoContact,
|
|
vvt_version: org.vvtVersion,
|
|
last_review_date: org.lastReviewDate || null,
|
|
next_review_date: org.nextReviewDate || null,
|
|
review_interval: org.reviewInterval,
|
|
}
|
|
}
|
|
|
|
export async function apiListActivities(): Promise<VVTActivity[]> {
|
|
const res = await fetch(`${VVT_API_BASE}/activities`)
|
|
if (!res.ok) throw new Error(`GET activities failed: ${res.status}`)
|
|
const data = await res.json()
|
|
return data.map(activityFromApi)
|
|
}
|
|
|
|
export async function apiGetOrganization(): Promise<VVTOrganizationHeader | null> {
|
|
const res = await fetch(`${VVT_API_BASE}/organization`)
|
|
if (!res.ok) return null
|
|
const data = await res.json()
|
|
if (!data) return null
|
|
return orgHeaderFromApi(data)
|
|
}
|
|
|
|
export async function apiCreateActivity(act: VVTActivity): Promise<VVTActivity> {
|
|
const res = await fetch(`${VVT_API_BASE}/activities`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(activityToApi(act)),
|
|
})
|
|
if (!res.ok) throw new Error(`POST activity failed: ${res.status}`)
|
|
return activityFromApi(await res.json())
|
|
}
|
|
|
|
export async function apiUpdateActivity(id: string, act: VVTActivity): Promise<VVTActivity> {
|
|
const res = await fetch(`${VVT_API_BASE}/activities/${id}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(activityToApi(act)),
|
|
})
|
|
if (!res.ok) throw new Error(`PUT activity failed: ${res.status}`)
|
|
return activityFromApi(await res.json())
|
|
}
|
|
|
|
export async function apiDeleteActivity(id: string): Promise<void> {
|
|
const res = await fetch(`${VVT_API_BASE}/activities/${id}`, { method: 'DELETE' })
|
|
if (!res.ok) throw new Error(`DELETE activity failed: ${res.status}`)
|
|
}
|
|
|
|
export async function apiUpsertOrganization(org: VVTOrganizationHeader): Promise<VVTOrganizationHeader> {
|
|
const res = await fetch(`${VVT_API_BASE}/organization`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(orgHeaderToApi(org)),
|
|
})
|
|
if (!res.ok) throw new Error(`PUT organization failed: ${res.status}`)
|
|
return orgHeaderFromApi(await res.json())
|
|
}
|