'use client' import { ART9_CATEGORIES, STATUS_COLORS, STATUS_LABELS, BUSINESS_FUNCTION_LABELS, PROTECTION_LEVEL_LABELS, DEPLOYMENT_LABELS, REVIEW_INTERVAL_LABELS, } from '@/lib/sdk/vvt-types' import type { VVTActivity, VVTOrganizationHeader } from '@/lib/sdk/vvt-types' import { DATA_SUBJECT_CATEGORY_META, PERSONAL_DATA_CATEGORY_META, LEGAL_BASIS_META, TRANSFER_MECHANISM_META, } from '@/lib/sdk/vvt-types' // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function resolveDataSubjects(cats: string[]) { return cats.map(c => DATA_SUBJECT_CATEGORY_META[c as keyof typeof DATA_SUBJECT_CATEGORY_META]?.de || c).join(', ') } function resolveDataCategories(cats: string[]) { return cats.map(c => PERSONAL_DATA_CATEGORY_META[c as keyof typeof PERSONAL_DATA_CATEGORY_META]?.label?.de || c).join(', ') } function resolveLegalBasis(lb: { type: string; description?: string; reference?: string }) { const meta = LEGAL_BASIS_META[lb.type as keyof typeof LEGAL_BASIS_META] const label = meta ? `${meta.label.de} (${meta.article})` : lb.type return lb.reference ? `${label} — ${lb.reference}` : label } function resolveTransferMechanism(m: string) { const meta = TRANSFER_MECHANISM_META[m as keyof typeof TRANSFER_MECHANISM_META] return meta?.de || m } function buildDocumentHtml(activities: VVTActivity[], orgHeader: VVTOrganizationHeader, today: string): string { const approvedActivities = activities.filter(a => a.status !== 'ARCHIVED') let html = ` Verzeichnis von Verarbeitungstaetigkeiten — ${orgHeader.organizationName || 'Organisation'}

Verzeichnis von Verarbeitungstaetigkeiten

gemaess Art. 30 Abs. 1 DSGVO
${orgHeader.organizationName || '(Organisation eintragen)'}
${orgHeader.industry ? `Branche: ${orgHeader.industry}
` : ''} ${orgHeader.employeeCount ? `Mitarbeiter: ${orgHeader.employeeCount}
` : ''} ${orgHeader.locations && orgHeader.locations.length > 0 ? `Standorte: ${orgHeader.locations.join(', ')}
` : ''} ${orgHeader.dpoName ? `
Datenschutzbeauftragter: ${orgHeader.dpoName}
` : ''} ${orgHeader.dpoContact ? `Kontakt DSB: ${orgHeader.dpoContact}
` : ''}

Inhaltsverzeichnis

${approvedActivities.length} Verarbeitungstaetigkeiten in ${[...new Set(approvedActivities.map(a => a.businessFunction))].length} Geschaeftsbereichen

${approvedActivities.map((a) => `
${a.vvtId} ${a.name || '(Ohne Namen)'} ${BUSINESS_FUNCTION_LABELS[a.businessFunction]} — ${STATUS_LABELS[a.status]}
`).join('')}
` for (const a of approvedActivities) { const hasArt9 = a.personalDataCategories.some(c => ART9_CATEGORIES.includes(c)) const hasThirdCountry = a.thirdCountryTransfers.length > 0 html += `
${a.vvtId}

${a.name || '(Ohne Namen)'}

${STATUS_LABELS[a.status]} ${hasArt9 ? 'Art. 9' : ''} ${a.dpiaRequired ? 'DSFA' : ''} ${hasThirdCountry ? 'Drittland' : ''}
${a.description ? `
Beschreibung
${a.description}
` : ''}
Pflichtfeld (Art. 30)Inhalt
Verantwortlicher${a.responsible || `nicht angegeben`}
Geschaeftsbereich${BUSINESS_FUNCTION_LABELS[a.businessFunction]}
Zwecke der Verarbeitung${a.purposes.length > 0 ? a.purposes.join('; ') : `nicht angegeben`}
Rechtsgrundlage(n)${a.legalBases.length > 0 ? a.legalBases.map(resolveLegalBasis).join('
') : `nicht angegeben`}
Kategorien betroffener Personen${a.dataSubjectCategories.length > 0 ? resolveDataSubjects(a.dataSubjectCategories) : `nicht angegeben`}
Kategorien personenbezogener Daten${a.personalDataCategories.length > 0 ? resolveDataCategories(a.personalDataCategories) : `nicht angegeben`}${hasArt9 ? '
Enthalt besondere Kategorien nach Art. 9 DSGVO' : ''}
Empfaengerkategorien${a.recipientCategories.length > 0 ? a.recipientCategories.map(r => `${r.name} (${r.type})`).join('; ') : `keine`}
Uebermittlung an Drittlaender${hasThirdCountry ? a.thirdCountryTransfers.map(t => `${t.country}: ${t.recipient} — ${resolveTransferMechanism(t.transferMechanism)}`).join('
') : 'Keine Drittlanduebermittlung'}
Loeschfristen${a.retentionPeriod.description || `nicht angegeben`}${a.retentionPeriod.legalBasis ? `
Rechtsgrundlage: ${a.retentionPeriod.legalBasis}` : ''}${a.retentionPeriod.deletionProcedure ? `
Verfahren: ${a.retentionPeriod.deletionProcedure}` : ''}
TOM (Art. 32 DSGVO)${a.tomDescription || `nicht beschrieben`}
${a.structuredToms && (a.structuredToms.accessControl.length > 0 || a.structuredToms.confidentiality.length > 0 || a.structuredToms.integrity.length > 0 || a.structuredToms.availability.length > 0 || a.structuredToms.separation.length > 0) ? `
Strukturierte TOMs
${a.structuredToms.accessControl.length > 0 ? `` : ''} ${a.structuredToms.confidentiality.length > 0 ? `` : ''} ${a.structuredToms.integrity.length > 0 ? `` : ''} ${a.structuredToms.availability.length > 0 ? `` : ''} ${a.structuredToms.separation.length > 0 ? `` : ''}
KategorieMassnahmen
Zugriffskontrolle${a.structuredToms.accessControl.join(', ')}
Vertraulichkeit${a.structuredToms.confidentiality.join(', ')}
Integritaet${a.structuredToms.integrity.join(', ')}
Verfuegbarkeit${a.structuredToms.availability.join(', ')}
Trennbarkeit${a.structuredToms.separation.join(', ')}
` : ''}
Erstellt: ${new Date(a.createdAt).toLocaleDateString('de-DE')} | Aktualisiert: ${new Date(a.updatedAt).toLocaleDateString('de-DE')} ${a.dpiaRequired ? ' | DSFA erforderlich' : ''} | Schutzniveau: ${PROTECTION_LEVEL_LABELS[a.protectionLevel]} | Deployment: ${DEPLOYMENT_LABELS[a.deploymentModel]}
` } html += ` ` return html } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- export function TabDokument({ activities, orgHeader }: { activities: VVTActivity[]; orgHeader: VVTOrganizationHeader }) { const today = new Date().toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }) const nonArchivedActivities = activities.filter(a => a.status !== 'ARCHIVED') const handlePrintDocument = () => { const htmlContent = buildDocumentHtml(activities, orgHeader, today) const printWindow = window.open('', '_blank') if (printWindow) { printWindow.document.write(htmlContent) printWindow.document.close() printWindow.focus() setTimeout(() => printWindow.print(), 300) } } const handleDownloadHtml = () => { const htmlContent = buildDocumentHtml(activities, orgHeader, today) const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `vvt-dokument-${new Date().toISOString().split('T')[0]}.html` a.click() URL.revokeObjectURL(url) } return (

VVT-Dokument (Art. 30 DSGVO)

Druckfertiges Verarbeitungsverzeichnis mit Deckblatt, Inhaltsverzeichnis und allen {nonArchivedActivities.length} Verarbeitungstaetigkeiten.

{nonArchivedActivities.length === 0 && (
Keine Verarbeitungstaetigkeiten vorhanden. Erstellen Sie zuerst Eintraege im Tab "Verzeichnis".
)}
{nonArchivedActivities.length > 0 && (

Vorschau — Inhalt des Dokuments

Deckblatt
Verzeichnis von Verarbeitungstaetigkeiten
gemaess Art. 30 Abs. 1 DSGVO
{orgHeader.organizationName || '(Organisation eintragen)'} {orgHeader.dpoName && <>
DSB: {orgHeader.dpoName}} {orgHeader.dpoContact && <> ({orgHeader.dpoContact})}
Version {orgHeader.vvtVersion} | Stand: {today}
{nonArchivedActivities.map((a) => { const hasArt9 = a.personalDataCategories.some(c => ART9_CATEGORIES.includes(c)) return (
{a.vvtId} {a.name || '(Ohne Namen)'} {STATUS_LABELS[a.status]} {hasArt9 && Art. 9}
Zweck: {a.purposes.join(', ') || '—'}
Rechtsgrundlage: {a.legalBases.map(lb => lb.type).join(', ') || '—'}
Betroffene: {a.dataSubjectCategories.length || 0} Kategorien
Datenkategorien: {a.personalDataCategories.length || 0}
Empfaenger: {a.recipientCategories.length || 0}
Loeschfrist: {a.retentionPeriod.description || '—'}
) })}
Tipp: Klicken Sie auf "Als PDF drucken" fuer das vollstaendige, formatierte Dokument mit allen Pflichtfeldern nach Art. 30 DSGVO — inklusive Deckblatt und Inhaltsverzeichnis.
)}
) }