/** * 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 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('Consent information could not be loaded.'); } } finally { if (isActive) { setIsLoadingConsent(false); } } }; loadConsentInfo(); return () => { isActive = false; }; }, []); 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: 'Data export downloaded.' }); } catch (error: any) { console.error('GDPR export failed:', error); setActionMessage({ type: 'error', text: 'Data export failed. Please try again.' }); } 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: 'Portable export downloaded.' }); } catch (error: any) { console.error('GDPR portability export failed:', error); setActionMessage({ type: 'error', text: 'Portable export failed. Please try again.' }); } finally { setIsPortabilityExporting(false); } }; const handleDeleteAccount = async () => { setActionMessage(null); if (deleteConfirmText !== 'LOESCHEN') { setActionMessage({ type: 'error', text: 'Please type LOESCHEN to confirm deletion.' }); 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: 'Account deleted. Redirecting to login...' }); window.location.replace('/login'); } catch (error: any) { console.error('GDPR deletion failed:', error); setActionMessage({ type: 'error', text: 'Account deletion failed. Please try again.' }); } finally { setIsDeleting(false); } }; return (

GDPR / Privacy

Manage your personal data exports and account deletion.

Back to Settings

{t('gDPR.yourDataRights')}

{t('gDPR.accessArticle15')}

{t('gDPR.downloadAFullExportOf')}

{t('gDPR.portabilityArticle20')}

{t('gDPR.downloadAMachinereadableJsonldExport')}

{t('gDPR.erasureArticle17')}

{t('gDPR.permanentlyDeleteYourAccountAnd')}

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

This action is irreversible. Type LOESCHEN to confirm.

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

{t('gDPR.processingInformation')}

{isLoadingConsent &&

{t('gDPR.loadingConsentInfo')}

} {consentError &&

{consentError}

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

{t('gDPR.dataCollected')}

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

{t('gDPR.processing')}

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

{t('gDPR.yourRights')}

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

Contact

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