// Copyright (c) 2026 PowerOn AG // All rights reserved. /** * GDPR Page * * Provides access to user data rights (export, portability, deletion). */ import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { FaDownload, FaFileExport, FaShieldAlt, FaSpinner, FaTrash } from 'react-icons/fa'; import api from '../api'; import { clearUserDataCache } from '../utils/userCache'; import { StackLayout } from '../components/Layout/StackLayout'; import { Panel } from '../components/Layout/Panel'; import styles from './GDPR.module.css'; import { useLanguage } from '../providers/language/LanguageContext'; type ConsentInfo = { dataCollected?: Record; dataProcessing?: Record; userRights?: Record; contact?: Record; }; type ActionMessage = { type: 'success' | 'error'; text: string; }; const _downloadJson = (data: unknown, fileName: string, mimeType = 'application/json') => { const fileBlob = new Blob([JSON.stringify(data, null, 2)], { type: mimeType }); const fileUrl = URL.createObjectURL(fileBlob); const link = document.createElement('a'); link.href = fileUrl; link.download = fileName; document.body.appendChild(link); link.click(); link.remove(); URL.revokeObjectURL(fileUrl); }; export const GDPRPage: React.FC = () => { const { t } = useLanguage(); const contactEmail = 'p.motsch@poweron.swiss'; const [consentInfo, setConsentInfo] = useState(null); const [isLoadingConsent, setIsLoadingConsent] = useState(true); const [consentError, setConsentError] = useState(null); const [isExporting, setIsExporting] = useState(false); const [isPortabilityExporting, setIsPortabilityExporting] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [actionMessage, setActionMessage] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [deleteConfirmText, setDeleteConfirmText] = useState(''); const [isDeleted, setIsDeleted] = useState(false); const isActionLocked = isDeleting || isDeleted; useEffect(() => { let isActive = true; const loadConsentInfo = async () => { setIsLoadingConsent(true); setConsentError(null); try { const response = await api.get('/api/user/me/consent-info'); if (isActive) { setConsentInfo(response.data as ConsentInfo); } } catch (error: any) { console.error('Failed to load GDPR consent info:', error); if (isActive) { setConsentError(t('Einwilligungsinformationen konnten nicht geladen werden.')); } } finally { if (isActive) { setIsLoadingConsent(false); } } }; loadConsentInfo(); return () => { isActive = false; }; }, [t]); const handleDataExport = async () => { if (isActionLocked) return; setIsExporting(true); setActionMessage(null); try { const response = await api.get('/api/user/me/data-export'); _downloadJson(response.data, 'gdpr-data-export.json'); setActionMessage({ type: 'success', text: t('Datenexport heruntergeladen.') }); } catch (error: any) { console.error('GDPR export failed:', error); setActionMessage({ type: 'error', text: t('Datenexport fehlgeschlagen. Bitte erneut versuchen.') }); } finally { setIsExporting(false); } }; const handlePortabilityExport = async () => { if (isActionLocked) return; setIsPortabilityExporting(true); setActionMessage(null); try { const response = await api.get('/api/user/me/data-portability', { headers: { Accept: 'application/ld+json' }, }); _downloadJson(response.data, 'gdpr-data-portability.json', 'application/ld+json'); setActionMessage({ type: 'success', text: t('Portabler Export heruntergeladen.') }); } catch (error: any) { console.error('GDPR portability export failed:', error); setActionMessage({ type: 'error', text: t('Portabler Export fehlgeschlagen. Bitte erneut versuchen.') }); } finally { setIsPortabilityExporting(false); } }; const handleDeleteAccount = async () => { setActionMessage(null); if (deleteConfirmText !== 'LOESCHEN') { setActionMessage({ type: 'error', text: t('Bitte geben Sie LOESCHEN ein, um die Löschung zu bestätigen.') }); return; } setIsDeleting(true); try { await api.delete('/api/user/me/', { params: { confirmDeletion: true } }); localStorage.removeItem('authToken'); sessionStorage.removeItem('auth_authority'); clearUserDataCache(); setIsDeleted(true); setActionMessage({ type: 'success', text: t('Konto gelöscht. Weiterleitung zur Anmeldung…') }); window.location.replace('/login'); } catch (error: any) { console.error('GDPR deletion failed:', error); setActionMessage({ type: 'error', text: t('Kontolöschung fehlgeschlagen. Bitte erneut versuchen.') }); } finally { setIsDeleting(false); } }; return (

{t('DSGVO / Datenschutz')}

{t('Verwalten Sie Ihre personenbezogenen Datenexporte und Kontolöschung.')}

{t('Zurück zu Einstellungen')}

{t('Zugriff (Artikel 15)')}

{t('Einen vollständigen Export herunterladen von')}

{t('Datenübertragbarkeit (Artikel 20)')}

{t('Einen maschinenlesbaren JSON-LD-Export herunterladen')}

{t('Löschung (Artikel 17)')}

{t('Ihr Konto dauerhaft löschen und')}

{!showDeleteConfirm && ( )} {showDeleteConfirm && (

{t('Diese Aktion ist unwiderruflich. Geben Sie {word} ein, um zu bestätigen.', { word: 'LOESCHEN', })}

setDeleteConfirmText(event.target.value)} placeholder="LOESCHEN" disabled={isDeleting} />
)}
{actionMessage && (
{actionMessage.text}
)}
{isLoadingConsent &&

{t('Lade Einwilligungsinformationen')}

} {consentError &&

{consentError}

} {!isLoadingConsent && !consentError && consentInfo && (

{t('Gesammelte Daten')}

    {Object.entries(consentInfo.dataCollected || {}).map(([key, value]) => (
  • {key}: {value}
  • ))}

{t('Verarbeitung')}

    {Object.entries(consentInfo.dataProcessing || {}).map(([key, value]) => (
  • {key}: {value}
  • ))}

{t('Ihre Rechte')}

    {Object.entries(consentInfo.userRights || {}).map(([key, value]) => (
  • {key}: {value}
  • ))}

{t('Kontakt')}

    {Object.entries({ ...(consentInfo.contact || {}), email: contactEmail, }).map(([key, value]) => (
  • {key}: {value}
  • ))}
)}
); }; export default GDPRPage;