Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
241 lines
7.5 KiB
TypeScript
241 lines
7.5 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState, useCallback } from 'react'
|
|
import { useCompliance } from '../provider'
|
|
import type { DSRRequestType } from '@breakpilot/compliance-sdk-types'
|
|
|
|
export interface DSRPortalProps {
|
|
onSubmit?: (type: DSRRequestType, email: string, name: string) => void
|
|
className?: string
|
|
style?: React.CSSProperties
|
|
}
|
|
|
|
const DSR_TYPES: Record<DSRRequestType, { name: string; description: string }> = {
|
|
ACCESS: {
|
|
name: 'Auskunft (Art. 15)',
|
|
description: 'Welche Daten haben Sie über mich gespeichert?',
|
|
},
|
|
RECTIFICATION: {
|
|
name: 'Berichtigung (Art. 16)',
|
|
description: 'Korrigieren Sie falsche Daten über mich.',
|
|
},
|
|
ERASURE: {
|
|
name: 'Löschung (Art. 17)',
|
|
description: 'Löschen Sie alle meine personenbezogenen Daten.',
|
|
},
|
|
PORTABILITY: {
|
|
name: 'Datenübertragbarkeit (Art. 20)',
|
|
description: 'Exportieren Sie meine Daten in einem maschinenlesbaren Format.',
|
|
},
|
|
RESTRICTION: {
|
|
name: 'Einschränkung (Art. 18)',
|
|
description: 'Schränken Sie die Verarbeitung meiner Daten ein.',
|
|
},
|
|
OBJECTION: {
|
|
name: 'Widerspruch (Art. 21)',
|
|
description: 'Ich widerspreche der Verarbeitung meiner Daten.',
|
|
},
|
|
}
|
|
|
|
export function DSRPortal({ onSubmit, className, style }: DSRPortalProps) {
|
|
const { dsgvo } = useCompliance()
|
|
const [selectedType, setSelectedType] = useState<DSRRequestType | null>(null)
|
|
const [email, setEmail] = useState('')
|
|
const [name, setName] = useState('')
|
|
const [additionalInfo, setAdditionalInfo] = useState('')
|
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
const [submitted, setSubmitted] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const handleSubmit = useCallback(
|
|
async (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
if (!selectedType || !email || !name) return
|
|
|
|
setIsSubmitting(true)
|
|
setError(null)
|
|
|
|
try {
|
|
await dsgvo.submitDSR(selectedType, email, name)
|
|
onSubmit?.(selectedType, email, name)
|
|
setSubmitted(true)
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Ein Fehler ist aufgetreten')
|
|
} finally {
|
|
setIsSubmitting(false)
|
|
}
|
|
},
|
|
[selectedType, email, name, dsgvo, onSubmit]
|
|
)
|
|
|
|
const containerStyle: React.CSSProperties = {
|
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
maxWidth: '600px',
|
|
margin: '0 auto',
|
|
padding: '20px',
|
|
...style,
|
|
}
|
|
|
|
const inputStyle: React.CSSProperties = {
|
|
width: '100%',
|
|
padding: '12px',
|
|
fontSize: '14px',
|
|
border: '1px solid #ddd',
|
|
borderRadius: '4px',
|
|
marginBottom: '15px',
|
|
boxSizing: 'border-box',
|
|
}
|
|
|
|
const buttonStyle: React.CSSProperties = {
|
|
padding: '12px 24px',
|
|
fontSize: '16px',
|
|
fontWeight: 500,
|
|
color: '#fff',
|
|
backgroundColor: '#1a1a1a',
|
|
border: 'none',
|
|
borderRadius: '4px',
|
|
cursor: 'pointer',
|
|
width: '100%',
|
|
}
|
|
|
|
if (submitted) {
|
|
return (
|
|
<div style={containerStyle} className={className}>
|
|
<div
|
|
style={{
|
|
textAlign: 'center',
|
|
padding: '40px 20px',
|
|
backgroundColor: '#f0fdf4',
|
|
borderRadius: '8px',
|
|
}}
|
|
>
|
|
<div style={{ fontSize: '48px', marginBottom: '20px' }}>✓</div>
|
|
<h2 style={{ margin: '0 0 10px', color: '#166534' }}>Anfrage eingereicht</h2>
|
|
<p style={{ margin: 0, color: '#166534' }}>
|
|
Wir werden Ihre Anfrage innerhalb von 30 Tagen bearbeiten. Sie erhalten eine
|
|
Bestätigung per E-Mail an {email}.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div style={containerStyle} className={className}>
|
|
<h2 style={{ margin: '0 0 10px' }}>Betroffenenrechte-Portal</h2>
|
|
<p style={{ margin: '0 0 20px', color: '#666' }}>
|
|
Hier können Sie Ihre Rechte gemäß DSGVO wahrnehmen. Wählen Sie die gewünschte Anfrage und
|
|
füllen Sie das Formular aus.
|
|
</p>
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
<div style={{ marginBottom: '20px' }}>
|
|
<label style={{ display: 'block', fontWeight: 500, marginBottom: '10px' }}>
|
|
Art der Anfrage *
|
|
</label>
|
|
<div style={{ display: 'grid', gap: '10px' }}>
|
|
{Object.entries(DSR_TYPES).map(([type, { name, description }]) => (
|
|
<label
|
|
key={type}
|
|
style={{
|
|
display: 'flex',
|
|
padding: '15px',
|
|
border: `2px solid ${selectedType === type ? '#1a1a1a' : '#ddd'}`,
|
|
borderRadius: '8px',
|
|
cursor: 'pointer',
|
|
backgroundColor: selectedType === type ? '#f5f5f5' : '#fff',
|
|
}}
|
|
>
|
|
<input
|
|
type="radio"
|
|
name="dsrType"
|
|
value={type}
|
|
checked={selectedType === type}
|
|
onChange={() => setSelectedType(type as DSRRequestType)}
|
|
style={{ marginRight: '15px' }}
|
|
/>
|
|
<div>
|
|
<div style={{ fontWeight: 500 }}>{name}</div>
|
|
<div style={{ fontSize: '13px', color: '#666' }}>{description}</div>
|
|
</div>
|
|
</label>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ marginBottom: '15px' }}>
|
|
<label style={{ display: 'block', fontWeight: 500, marginBottom: '5px' }}>
|
|
Ihr Name *
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={name}
|
|
onChange={e => setName(e.target.value)}
|
|
required
|
|
placeholder="Max Mustermann"
|
|
style={inputStyle}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{ marginBottom: '15px' }}>
|
|
<label style={{ display: 'block', fontWeight: 500, marginBottom: '5px' }}>
|
|
E-Mail-Adresse *
|
|
</label>
|
|
<input
|
|
type="email"
|
|
value={email}
|
|
onChange={e => setEmail(e.target.value)}
|
|
required
|
|
placeholder="max@example.com"
|
|
style={inputStyle}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{ marginBottom: '20px' }}>
|
|
<label style={{ display: 'block', fontWeight: 500, marginBottom: '5px' }}>
|
|
Zusätzliche Informationen (optional)
|
|
</label>
|
|
<textarea
|
|
value={additionalInfo}
|
|
onChange={e => setAdditionalInfo(e.target.value)}
|
|
placeholder="Weitere Details zu Ihrer Anfrage..."
|
|
rows={4}
|
|
style={{ ...inputStyle, resize: 'vertical' }}
|
|
/>
|
|
</div>
|
|
|
|
{error && (
|
|
<div
|
|
style={{
|
|
padding: '12px',
|
|
backgroundColor: '#fef2f2',
|
|
color: '#dc2626',
|
|
borderRadius: '4px',
|
|
marginBottom: '15px',
|
|
}}
|
|
>
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={!selectedType || !email || !name || isSubmitting}
|
|
style={{
|
|
...buttonStyle,
|
|
opacity: !selectedType || !email || !name || isSubmitting ? 0.5 : 1,
|
|
cursor: !selectedType || !email || !name || isSubmitting ? 'not-allowed' : 'pointer',
|
|
}}
|
|
>
|
|
{isSubmitting ? 'Wird gesendet...' : 'Anfrage einreichen'}
|
|
</button>
|
|
</form>
|
|
|
|
<p style={{ marginTop: '20px', fontSize: '12px', color: '#666' }}>
|
|
Ihre Anfrage wird gemäß Art. 12 DSGVO innerhalb von einem Monat bearbeitet. In komplexen
|
|
Fällen kann diese Frist um weitere zwei Monate verlängert werden.
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|