import React, { useState } from 'react'; import { Box, Alert, Typography } from '@mui/material'; import ConsentCheckboxes from './MultiUpload/ConsentCheckboxes'; import { apiFetch } from '../../Utils/apiFetch'; /** * Manages consents with save functionality * Wraps ConsentCheckboxes and provides save for workshop + social media consents * * @param mode - 'edit' (default) shows save/discard, 'upload' hides them */ function ConsentManager({ initialConsents, consents: externalConsents, onConsentsChange, token, groupId, onRefresh, mode = 'edit' }) { // Initialize with proper defaults const defaultConsents = { workshopConsent: false, socialMediaConsents: [] }; const [consents, setConsents] = useState(defaultConsents); const [originalConsents, setOriginalConsents] = useState(defaultConsents); const [saving, setSaving] = useState(false); const [initialized, setInitialized] = useState(false); const [successMessage, setSuccessMessage] = useState(''); const [errorMessage, setErrorMessage] = useState(''); const [showEmailHint, setShowEmailHint] = useState(false); // In upload mode: use external state const isUploadMode = mode === 'upload'; const currentConsents = isUploadMode ? externalConsents : consents; const setCurrentConsents = isUploadMode ? onConsentsChange : setConsents; // Update ONLY ONCE when initialConsents first arrives (edit mode only) React.useEffect(() => { if (initialConsents && !initialized && !isUploadMode) { // Deep copy to avoid shared references const consentsCopy = { workshopConsent: initialConsents.workshopConsent, socialMediaConsents: [...(initialConsents.socialMediaConsents || [])] }; setConsents(consentsCopy); // Separate deep copy for original const originalCopy = { workshopConsent: initialConsents.workshopConsent, socialMediaConsents: [...(initialConsents.socialMediaConsents || [])] }; setOriginalConsents(originalCopy); setInitialized(true); } }, [initialConsents, initialized, isUploadMode]); const hasChanges = () => { if (isUploadMode) return false; // No changes tracking in upload mode // Check workshop consent if (consents.workshopConsent !== originalConsents.workshopConsent) { return true; } // Check social media consents - sort before comparing (order doesn't matter) const currentIds = (consents.socialMediaConsents || []).map(c => c.platformId).sort((a, b) => a - b); const originalIds = (originalConsents.socialMediaConsents || []).map(c => c.platformId).sort((a, b) => a - b); // Different lengths = definitely changed if (currentIds.length !== originalIds.length) { return true; } // Compare sorted arrays element by element for (let i = 0; i < currentIds.length; i++) { if (currentIds[i] !== originalIds[i]) { return true; } } return false; }; // Check if social media consent was revoked (for email hint) const hasSocialMediaRevocations = () => { const currentIds = new Set((consents.socialMediaConsents || []).map(c => c.platformId)); const originalIds = new Set((originalConsents.socialMediaConsents || []).map(c => c.platformId)); // Check if any original platform is missing in current for (let platformId of originalIds) { if (!currentIds.has(platformId)) { return true; } } return false; }; const handleSave = async () => { if (!hasChanges()) { return; } try { setSaving(true); setSuccessMessage(''); setErrorMessage(''); // Detect changes const changes = []; // Workshop consent change if (consents.workshopConsent !== originalConsents.workshopConsent) { changes.push({ consentType: 'workshop', action: consents.workshopConsent ? 'restore' : 'revoke' }); } // Social media consent changes const originalSocialIds = new Set(originalConsents.socialMediaConsents.map(c => c.platformId)); const currentSocialIds = new Set(consents.socialMediaConsents.map(c => c.platformId)); // Revoked social media consents const revoked = []; originalSocialIds.forEach(platformId => { if (!currentSocialIds.has(platformId)) { revoked.push(platformId); changes.push({ consentType: 'social_media', action: 'revoke', platformId }); } }); // Restored social media consents currentSocialIds.forEach(platformId => { if (!originalSocialIds.has(platformId)) { changes.push({ consentType: 'social_media', action: 'restore', platformId }); } }); // Save each change for (const change of changes) { const res = await apiFetch(`/api/manage/${token}/consents`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(change) }); if (!res.ok) { const body = await res.json().catch(() => ({})); throw new Error(body.error || 'Fehler beim Speichern der Einwilligung'); } } // Show success message setSuccessMessage('Einwilligungen wurden erfolgreich gespeichert.'); // Show email hint after saving if social media was revoked setShowEmailHint(revoked.length > 0); // Update original consents with deep copy setOriginalConsents({ workshopConsent: consents.workshopConsent, socialMediaConsents: [...(consents.socialMediaConsents || [])] }); // Don't refresh - just show success message } catch (error) { console.error('Error saving consents:', error); setErrorMessage(error.message || 'Einwilligungen konnten nicht gespeichert werden'); } finally { setSaving(false); } }; const handleDiscard = () => { setConsents({ ...originalConsents, socialMediaConsents: [...(originalConsents.socialMediaConsents || [])] }); setSuccessMessage(''); setErrorMessage(''); setShowEmailHint(false); }; const handleConsentChange = (newConsents) => { // Force new object reference so React detects the change setConsents({ workshopConsent: newConsents.workshopConsent, socialMediaConsents: [...(newConsents.socialMediaConsents || [])] }); }; return ( {/* Alerts and Buttons only in edit mode */} {!isUploadMode && ( <> {/* Success Message */} {successMessage && ( {successMessage} )} {/* Email Hint - show IMMEDIATELY when social media revoked (before save) */} {hasChanges() && hasSocialMediaRevocations() && !successMessage && ( Hinweis: Bei Widerruf einer Social Media Einwilligung müssen Sie nach dem Speichern eine E-Mail an{' '} info@hobbyhimmel.de {' '} senden, um die Löschung Ihrer Bilder anzufordern. )} {/* Email Hint after successful save */} {showEmailHint && successMessage && ( Wichtig: Bitte sende eine E-Mail an{' '} info@hobbyhimmel.de {' '} mit Deiner Gruppen-ID, um die Löschung Deiner Bilder auf den Social Media Plattformen anzufordern. )} {/* Error Message */} {errorMessage && ( {errorMessage} )} {/* Action Buttons */} {hasChanges() && ( )} )} ); } export default ConsentManager;