// ECO-PANNEAU.FR - __react/socle/_socle_archives.jsx const { useState, useEffect, useRef } = React; // 1. - COMPOSANT PRINCIPAL : GÉNÉRATEUR D'ARCHIVES SÉCURISÉES (D.O.E, RGPD, FACTURES) window.pano_ArchiveGeneratorModal = ({ type, panelId, onClose, showToast, refreshData }) => { // ZÉRO-DETTE : Utilisation de notre Hook abstrait ! const { isMounted, safeFetch } = window.pano_useSafeFetch(); // 1.1 - Composants et Icônes const { DownloadIcon, CheckCircleIcon, AlertTriangleIcon, LoaderIcon, CopyIcon, MailIcon } = window.pano_getIcons(); const { Modal, Button } = window.pano_getComponents(); // 1.2 - États const [step, setStep] = useState('generating'); const [progress, setProgress] = useState(0); const [result, setResult] = useState(null); const [errorMessage, setErrorMessage] = useState(''); const [sendingEmail, setSendingEmail] = useState(false); const [copied, setCopied] = useState(false); const hasFetched = useRef(false); // 2. - GÉNÉRATION DE L'ARCHIVE (ON MOUNT) useEffect(() => { if (hasFetched.current) return; hasFetched.current = true; let currentProgress = 0; const interval = setInterval(() => { currentProgress += (90 - currentProgress) * 0.1; if (isMounted.current) setProgress(currentProgress); }, 500); const endpoint = type === 'rgpd' ? 'archives/rgpd' : (type === 'factures' ? 'invoices/export_zip' : 'archives/doe'); const body = (type === 'rgpd' || type === 'factures') ? {} : { id: panelId }; safeFetch(endpoint, { body }) .then(d => { // SÉCURITÉ : On stoppe tout si le composant a été fermé par l'utilisateur if (!isMounted.current) return; clearInterval(interval); setProgress(100); if (d) { setResult(d.data); setStep('done'); if (refreshData) { refreshData(); } } else { setErrorMessage("Erreur lors de la génération."); setStep('error'); } }) .catch(e => { // SÉCURITÉ : On stoppe tout si le composant a été fermé if (!isMounted.current) return; clearInterval(interval); setErrorMessage("Erreur de connexion réseau."); setStep('error'); }); return () => { clearInterval(interval); }; }, [type, panelId, refreshData, safeFetch, isMounted]); // 3. - ACTIONS MÉTIER const handleCopy = () => { if (!result || !result.password) { return; } navigator.clipboard.writeText(result.password).then(() => { setCopied(true); if (showToast) { showToast("Mot de passe copié !", "success"); } // SÉCURITÉ : Vérification de isMounted avant le setTimeout setTimeout(() => { if (isMounted.current) setCopied(false); }, 2000); }); }; const handleSendEmail = async () => { if (!result) return; await safeFetch('archives/send_password', { body: { filename: result.filename }, setLoading: setSendingEmail, successMessage: "Mot de passe envoyé par e-mail avec succès." }); }; // 4. - RENDU UI return ( ( ) : step === 'done' && result ? (close) => ( <> { setTimeout(close, 2000); }} download={`eco-panneau.fr_${result.filename}`} className="flex-[2] py-3 uppercase tracking-widest justify-center shadow-lg bg-emerald-600 hover:bg-emerald-700 text-white rounded-xl font-bold flex items-center gap-2 transition text-xs" > Télécharger l'archive ) : null} >
{step === 'generating' && (

Création de l'archive sécurisée...

Chiffrement AES-256 de vos documents en cours. Veuillez patienter.

)} {step === 'error' && (

Échec de la génération

{errorMessage}

)} {step === 'done' && result && (

Archive chiffrée avec succès

Vos données ont été regroupées dans une archive ZIP protégée par un mot de passe unique.

Vous pourrez retrouver ce mot de passe plus tard depuis votre tableau de bord grâce à l'icône en forme d'œil.

Nom du fichier : eco-panneau.fr_{result.filename}

Mot de passe :

{result.password}

)}
); }; /* EOF ========== [__react/socle/_socle_archives.jsx] */