// ECO-PANNEAU.FR - _react/clients/_clients.jsx window.pano_ClientView = ({ data, refreshData }) => { const { useState, useEffect, useMemo, useRef } = React; // 1. - SÉCURITÉ ANTI-FUITE DE MÉMOIRE (Zéro-Dette) const { isMounted, safeFetch } = window.pano_useSafeFetch(); // 1.1 - Routage Zéro-Dette et Navigation Globale const urlModal = window.pano_useUrlModal ? window.pano_useUrlModal() : {}; const { activeModal, activeDialog, activeChat, targetId, dialogId, currentTab, changeTab, openModal, openDialog, closeCurrentLayer, replaceCurrentLayer, openChat } = urlModal; const activeTab = currentTab || 'dashboard'; const setActiveTab = changeTab; const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const [pendingGlobalTab, setPendingGlobalTab] = useState(null); // 2. - États Locaux (Modales et Édition) const [confirmConfig, setConfirmConfig] = useState(null); const [archiveConfig, setArchiveConfig] = useState(null); const [revealedPwd, setRevealedPwd] = useState(null); const [panelTeamModal, setPanelTeamModal] = useState(null); const [managingPanneau, setManagingPanneau] = useState(null); const [editingEntity, setEditingEntity] = useState(null); const [draggedItem, setDraggedItem] = useState(null); const [isSaving, setIsSaving] = useState(false); const [validationErrors, setValidationErrors] = useState([]); const [previewPanneau, setPreviewPanneau] = useState(null); const [moderationAlert, setModerationAlert] = useState(null); // 3. - STABILISATION DES COMPOSANTS (Zéro clignotement) const icons = useMemo(() => window.pano_getIcons(), []); const { HomeIcon, BuildingIcon, MessageSquareIcon, FileTextIcon, UserCircleIcon, PackageIcon, CheckCircleIcon, AlertTriangleIcon, LoaderIcon, ArrowLeftIcon, ShieldAlertIcon, LockIcon, EyeIcon, Trash2Icon, RefreshCwIcon, EditIcon, QrCodeIcon } = icons; const comps = useMemo(() => window.pano_getComponents(), []); const { Button, Modal, ConfirmModal, GlobalChatModal, FormInput, PasswordPromptModal, ClientDashboardTab, ClientPanelsTab, ClientLivraisonsTab, ClientMessagesTab, ClientInvoicesTab, ClientAccountTab, DashboardLayout, PanneauEditorForm, EntityEditorModal, ClientCheckoutModal, ClientDelegateShareModal, ClientLegalVaultModal, PreviewModal, ArchiveGeneratorModal, ClientRiverainsListModal, ClientNewsletterModal, ClientPanelTeamModal } = comps; // 4. - Données utilisateur const [meRes, setMeRes] = useState(null); useEffect(() => { fetch(window.pano_CONFIG.apiBaseUrl + 'auth/me') .then(r => r.json()) .then(d => { if (!isMounted.current) return; if (d && d.status === 'success') setMeRes(d.data); }) .catch(e => { if (!isMounted.current) return; if (window.pano_logFallback) window.pano_logFallback(`Erreur fetch auth/me dans ClientView: ${e.message}`); }); }, [isMounted]); const myClientData = data.me || data.clients?.[0] || {}; const isImpersonating = meRes?.is_impersonating; const isSupportLocked = myClientData.admin_access_until && new Date(String(myClientData.admin_access_until || '').replace(' ', 'T')) > new Date(); const isLockedForClient = isSupportLocked && !isImpersonating; let clientOpts = {}; try { if (myClientData.uiMode) clientOpts = JSON.parse(myClientData.uiMode); } catch(err) {} const toggleDashboardPin = async (listKey, id, e) => { if (e) { e.preventDefault(); e.stopPropagation(); } let arr = [...(clientOpts[listKey] || [])]; if (arr.includes(id)) arr = arr.filter(x => x !== id); else arr.push(id); const newOpts = { ...clientOpts, [listKey]: arr }; const d = await safeFetch('clients/profile/update', { body: { ...myClientData, uiMode: JSON.stringify(newOpts) } }); if (!isMounted.current) return; if (d && refreshData) refreshData(); }; const safeSetActiveTab = (newTab) => { if (newTab === activeTab) return; if (hasUnsavedChanges && activeTab === 'account') { setPendingGlobalTab(newTab); openDialog('confirm_discard_global', null, false); } else { setActiveTab(newTab); } }; // Intercepteur Stripe 3D Secure avec restauration du contexte ET Garbage Collection useEffect(() => { const url = new URL(window.location); const paymentIntent = url.searchParams.get('payment_intent'); if (paymentIntent) { let payload = { payment_intent_id: paymentIntent }; let pId = null; try { const savedCtx = sessionStorage.getItem('pano_checkout_context'); if (savedCtx) { const parsed = JSON.parse(savedCtx); payload = { ...payload, ...parsed }; pId = parsed.id; sessionStorage.removeItem('pano_checkout_context'); } } catch(e) {} safeFetch('panneaux/activate_paid', { body: payload }).then((d) => { if (!isMounted.current) return; if (d) { if (refreshData) refreshData(); sessionStorage.setItem('pano_payment_success', paymentIntent); if (pId) openDialog('select_offer', pId, false); } }); } if (url.searchParams.get('payment_success') && !paymentIntent) { if (window.pano_showToast && isMounted.current) window.pano_showToast("Paiement validé !", "success"); } if (url.searchParams.get('payment_canceled')) { sessionStorage.removeItem('pano_checkout_context'); if (window.pano_showToast && isMounted.current) window.pano_showToast("Paiement annulé.", "warning"); } if (paymentIntent || url.searchParams.get('payment_success') || url.searchParams.get('payment_canceled')) { const cleanUrl = new URL(window.location); cleanUrl.searchParams.delete('payment_intent'); cleanUrl.searchParams.delete('payment_intent_client_secret'); cleanUrl.searchParams.delete('redirect_status'); cleanUrl.searchParams.delete('payment_success'); cleanUrl.searchParams.delete('payment_canceled'); window.history.replaceState(window.history.state || {}, '', cleanUrl); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [openDialog, refreshData, isMounted, safeFetch]); const allPanels = data.panneaux || []; const interactions = data.interactions || []; const { pendingInvites, visiblePanels } = window.pano_getPanelAccessRights ? window.pano_getPanelAccessRights(allPanels, myClientData.id, myClientData.email_hash) : { pendingInvites:[], visiblePanels:[] }; const expectedFullName = myClientData.full_name || 'Utilisateur'; const expectedCompany = myClientData.name || 'Société'; const expectedAuthorName = `${expectedFullName} (${expectedCompany})`; let unreadPanelsCount = 0; visiblePanels.forEach(p => { const hasUnread = interactions.some(m => { if (m.resolved) return false; if (m.panneauId !== p.id && m.panneauId !== 'GROUP_' + p.id) return false; const isMe = (m.authorType === 'Client' && ( m.author === 'Client' || m.author === myClientData.email || m.author === myClientData.full_name || m.author === myClientData.name || m.author === expectedAuthorName )); return !isMe && m.authorType !== 'Systeme' && m.authorType !== 'System'; }); if (hasUnread) unreadPanelsCount++; }); const pendingDeliveriesCount = visiblePanels.filter(c => c.physicalPanels > 0 && (c.shipping_status === 'Expédié' || c.shipping_status === 'Attente validation client')).length; const unreadSupportCount = interactions.filter(m => !m.resolved && m.panneauId === `SUPPORT_${myClientData.id}` && m.authorType !== 'Client').length; const unreadInvoicesCount = (data.invoices || []).filter(inv => !inv.client_downloaded).length; const totalUnread = window.pano_computeClientUnread ? window.pano_computeClientUnread(interactions, myClientData, visiblePanels, pendingInvites) : 0; const handleLogout = async () => { await safeFetch('auth/logout', { method: 'GET', silent: true }); window.location.href = '?'; }; const handleUnimpersonate = async () => { const d = await safeFetch('auth/unimpersonate', {}); if (d) window.location.href = '?'; }; const handleRevokeAccess = async () => { const d = await safeFetch('clients/revoke_access', { setLoading: setIsSaving, successMessage: "Accès révoqué avec succès !" }); if (!isMounted.current) return; if (d) { if (isImpersonating) window.location.href = '?'; else { refreshData(); setActiveTab('dashboard'); } } }; let finalCustomLogout = null; if (isImpersonating) { finalCustomLogout = { label: "Clôturer l'intervention", icon: , action: handleRevokeAccess, className: "bg-emerald-600 hover:bg-emerald-700 text-white" }; } let finalNavItems = [ { id: 'dashboard', icon: , label: 'Tableau de bord', badge: pendingInvites.length }, { id: 'panels', icon: , label: 'Mes panneaux', badge: unreadPanelsCount }, { id: 'livraisons', icon: , label: 'Livraisons', badge: pendingDeliveriesCount }, { id: 'billing', icon: , label: 'Factures et avoirs', badge: unreadInvoicesCount }, { id: 'messages', icon: , label: 'Messagerie', badge: totalUnread }, { id: 'account', icon: , label: 'Mon compte', badge: unreadSupportCount }, ]; if (isLockedForClient) { finalNavItems = [ { id: 'messages', icon: , label: 'Messagerie', badge: totalUnread } ]; if (activeTab !== 'messages') setActiveTab('messages'); } const handleCreateNewPanel = async () => { setIsSaving(true); let idReservé = null; let maxTries = 5; let serverData = {}; // Capture des métadonnées initiales while (!idReservé && maxTries > 0) { if (!isMounted.current) break; const tempId = 'pan_' + window.pano_generateID().replace(/-/g, '').substring(0, 12); try { const d = await safeFetch('panneaux/reserve_id', { body: { id: tempId }, silent: true }); if (d && d.status === 'success') { idReservé = tempId; serverData = d.data || {}; } } catch(e) { if (window.pano_logFallback) window.pano_logFallback(`Erreur lors de la réservation ID: ${e.message}`); } maxTries--; } if (!isMounted.current) return; setIsSaving(false); if (idReservé) { setManagingPanneau({ ...serverData, // Injection des données fraîchement créées côté serveur (dont updated_at) id: idReservé, name: '', location: '', permitNumber: '', status: 'Réservé', offerType: 'rental', currentRate: data.prices?.rentalMo ?? 180, physicalPanels: 0, hasNoAds: false, privateDocs: [], shippingAddress: '', client_uid: myClientData.id }); setValidationErrors([]); openModal('editor', idReservé, false); } else { if (window.pano_showToast) window.pano_showToast("Erreur lors de la réservation de l'identifiant. Veuillez réessayer.", "error"); } }; const demoPanneau = allPanels.find(p => p.id === 'demo-panneau') || { id: 'demo-panneau', status: 'Actif', offerType: 'demo', name: 'Panneau de démonstration', location: 'Paris', themeColor: '#059669', hasNoAds: false }; const panneauCible = managingPanneau || (targetId ? visiblePanels.find(p => p.id === targetId) : null) || (dialogId ? visiblePanels.find(p => p.id === dialogId) : null); const previewCible = previewPanneau || (targetId ? (visiblePanels.find(p => p.id === targetId) || (targetId === 'demo-panneau' ? demoPanneau : null)) : null); const teamPanneauCibleId = panelTeamModal?.id || dialogId; const foundTeamPanneau = teamPanneauCibleId ? allPanels.find(p => p.id === teamPanneauCibleId) : null; const teamPanneauCible = foundTeamPanneau || panelTeamModal; let currentLockedFields = []; if (panneauCible && String(panneauCible.client_uid) !== String(myClientData.id)) { const hashTarget = myClientData.email_hash || myClientData.id; const myCollab = panneauCible.collaborators?.find(c => c.uid === hashTarget); if (myCollab?.rights?.locked_fields) { currentLockedFields = myCollab.rights.locked_fields; } } const saveEditedEntity = () => { const p = panneauCible || {}; const currentData = p.draft_data && Object.keys(p.draft_data).length > 0 ? { ...p, ...p.draft_data } : p; let newInter = [...(currentData.intervenants || [])]; let newLots = JSON.parse(JSON.stringify(currentData.lots || [])); const loc = editingEntity.location; if (loc.type === 'intervenant') { if (loc.index !== undefined) newInter[loc.index] = editingEntity.data; else newInter.push({...editingEntity.data, id: window.pano_generateID()}); } else if (loc.type === 'lot') { if (loc.index !== undefined) newLots[loc.index] = {...newLots[loc.index], ...editingEntity.data}; else newLots.push({...editingEntity.data, id: window.pano_generateID(), entreprises: []}); } else if (loc.type === 'entreprise') { if (loc.index !== undefined) newLots[loc.lotIndex].entreprises[loc.index] = editingEntity.data; else newLots[loc.lotIndex].entreprises.push({...editingEntity.data, id: window.pano_generateID()}); } const isDraftPanel = p.status === 'Brouillon' || p.status === 'Réservé'; if (!isDraftPanel) { setManagingPanneau({ ...p, draft_data: { ...(p.draft_data || {}), intervenants: newInter, lots: newLots } }); } else { setManagingPanneau({ ...p, intervenants: newInter, lots: newLots }); } closeCurrentLayer(); }; const deleteEntity = (loc) => { setConfirmConfig({ title: "Supprimer l'élément", message: "Êtes-vous sûr de vouloir supprimer cet élément ?", confirmText: "Supprimer", type: 'error', isDestructive: true, onConfirm: () => { const p = panneauCible || {}; const currentData = p.draft_data && Object.keys(p.draft_data).length > 0 ? { ...p, ...p.draft_data } : p; let newInter = [...(currentData.intervenants || [])]; let newLots = JSON.parse(JSON.stringify(currentData.lots || [])); if (loc.type === 'intervenant') newInter.splice(loc.index, 1); else if (loc.type === 'lot') newLots.splice(loc.index, 1); else newLots[loc.lotIndex].entreprises.splice(loc.index, 1); const isDraftPanel = p.status === 'Brouillon' || p.status === 'Réservé'; if (!isDraftPanel) { setManagingPanneau({ ...p, draft_data: { ...(p.draft_data || {}), intervenants: newInter, lots: newLots } }); } else { setManagingPanneau({ ...p, intervenants: newInter, lots: newLots }); } closeCurrentLayer(); } }); openDialog('confirm', null, false); }; const handleDragStart = (e, location) => { setDraggedItem(location); e.dataTransfer.effectAllowed = 'move'; }; const handleDragOver = (e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; const handleDrop = (e, dropLocation) => { e.preventDefault(); if (!draggedItem || draggedItem.type !== dropLocation.type) return; if (draggedItem.type === 'entreprise' && draggedItem.lotIndex !== dropLocation.lotIndex) return; const p = panneauCible || {}; const currentData = p.draft_data && Object.keys(p.draft_data).length > 0 ? { ...p, ...p.draft_data } : p; let newInter = [...(currentData.intervenants || [])]; let newLots = JSON.parse(JSON.stringify(currentData.lots || [])); if (draggedItem.type === 'intervenant') { const item = newInter.splice(draggedItem.index, 1)[0]; newInter.splice(dropLocation.index, 0, item); } else if (draggedItem.type === 'lot') { const item = newLots.splice(draggedItem.index, 1)[0]; newLots.splice(dropLocation.index, 0, item); } else if (draggedItem.type === 'entreprise') { const arr = newLots[dropLocation.lotIndex].entreprises; const item = arr.splice(draggedItem.index, 1)[0]; arr.splice(dropLocation.index, 0, item); } const isDraftPanel = p.status === 'Brouillon' || p.status === 'Réservé'; if (!isDraftPanel) { setManagingPanneau({ ...p, draft_data: { ...(p.draft_data || {}), intervenants: newInter, lots: newLots } }); } else { setManagingPanneau({ ...p, intervenants: newInter, lots: newLots }); } setDraggedItem(null); }; const validatePanel = (uiPrefs = {}) => { const p = { ...(panneauCible || {}), ...(panneauCible?.draft_data || {}) }; if (p.id === 'demo-panneau' || p.offerType === 'demo') return []; const errors = []; if (!p.name?.trim()) errors.push("Le nom du chantier est manquant."); if (!p.location?.trim()) errors.push("L'adresse du panneau est manquante."); if (!uiPrefs.simp_opt_hide_legal && !p.pdfId) errors.push("L'arrêté légal (PDF) n'a pas été uploadé."); if (p.client_uid === myClientData.id || !p.id) { if (!myClientData.name?.trim()) errors.push("Facturation : Le nom de la société est manquant (onglet Mon compte)."); if (!myClientData.full_name?.trim()) errors.push("Profil : Nom complet manquant (onglet Mon compte)."); if (!myClientData.address?.trim()) errors.push("Facturation : Adresse postale manquante (onglet Mon compte)."); if (!myClientData.siret?.trim()) errors.push("Facturation : SIRET de l'entreprise manquant (onglet Mon compte)."); let parsedOpts = {}; try { if (myClientData.uiMode) parsedOpts = JSON.parse(myClientData.uiMode); } catch(e) {} if (parsedOpts.has_tva !== false && !myClientData.tva?.trim()) { errors.push("Facturation : Numéro de TVA intracommunautaire manquant (onglet Mon compte)."); } } return errors; }; const handleSavePanneau = async (forceDraft = false, forceReactivate = false, isCheckout = false, uiPrefs = {}) => { const pCible = panneauCible || {}; if (!pCible.id) return; if (!forceDraft && (pCible.status === 'Actif' || forceReactivate)) { const errs = validatePanel(uiPrefs); if (errs.length > 0) { setValidationErrors(errs); setTimeout(() => { const scrollEls = document.querySelectorAll('.custom-scrollbar'); scrollEls.forEach(el => el.scrollTo({ top: 0, behavior: 'smooth' })); }, 50); return; } } let finalStatus = pCible.status; if (finalStatus === 'Réservé') finalStatus = 'Brouillon'; let detailsToSave; const original = data.panneaux.find(x => x.id === pCible.id) || (pCible.id === 'demo-panneau' ? demoPanneau : pCible); if (forceReactivate || (!forceDraft && !isCheckout)) { finalStatus = 'Actif'; detailsToSave = { ...pCible, ...(pCible.draft_data || {}), draft_data: {} }; detailsToSave.name = detailsToSave.name?.trim() || 'Projet sans nom'; detailsToSave.location = detailsToSave.location?.trim() || ''; } else { if (finalStatus === 'Brouillon') { detailsToSave = { ...pCible, draft_data: {} }; detailsToSave.name = detailsToSave.name?.trim() || 'Brouillon sans nom'; detailsToSave.location = detailsToSave.location?.trim() || ''; } else { const newDraftData = pCible.draft_data ? { ...pCible.draft_data } : {}; if (Object.keys(newDraftData).length > 0) { newDraftData.name = newDraftData.name?.trim() || 'Projet sans nom'; newDraftData.location = newDraftData.location?.trim() || ''; } detailsToSave = { ...original, draft_data: newDraftData }; } } setIsSaving(true); // --- JUST-IN-TIME FETCH (JIT) POUR ÉRADIQUER LE CONFLIT D'ÉDITION --- let freshOriginal = null; if (pCible.id !== 'demo-panneau') { try { const dSync = await safeFetch('sync', { method: 'GET', silent: true }); if (dSync && dSync.data && dSync.data.panneaux) { freshOriginal = dSync.data.panneaux.find(x => x.id === pCible.id); } } catch(e) {} } const originalToUse = freshOriginal || original; // --- ANTI-CONFLIT D'ÉDITION : Fusion des métadonnées serveurs ultra-fraîches --- if (originalToUse) { Object.assign(detailsToSave, { updated_at: originalToUse.updated_at, shipping_status: originalToUse.shipping_status, tracking_number: originalToUse.tracking_number, tracking_link: originalToUse.tracking_link, admin_seen: originalToUse.admin_seen }); } const payload = { id: pCible.id, status: finalStatus, offerType: pCible.offerType, currentRate: pCible.currentRate, physicalPanels: pCible.physicalPanels, details: detailsToSave }; const d = await safeFetch('panneaux', { body: payload, setLoading: setIsSaving }); if (!isMounted.current) return; if (d) { if (refreshData) refreshData(); if (d.data && d.data.status === 'Attente validation') { closeCurrentLayer(); setModerationAlert("Votre panneau contient des termes nécessitant une vérification. Il sera publié après validation par le support technique."); } else if (d.data && d.data.message_override) { closeCurrentLayer(); if (window.pano_showToast) window.pano_showToast(d.data.message_override, "success"); } else if (isCheckout) { setManagingPanneau({ ...pCible, status: pCible.status === 'Réservé' ? 'Brouillon' : pCible.status }); replaceCurrentLayer('dialog', 'select_offer', null, false); } else if (forceDraft) { closeCurrentLayer(); if (window.pano_showToast) window.pano_showToast("Modifications sauvegardées !", "success"); } else { closeCurrentLayer(); if (window.pano_showToast) window.pano_showToast("Panneau publié avec succès !", "success"); } } }; const handleDiscardDraft = async () => { const p = panneauCible || {}; if (!p.id) return; const original = data.panneaux.find(x => x.id === p.id) || (p.id === 'demo-panneau' ? demoPanneau : undefined); if (!original || !original.draft_data || Object.keys(original.draft_data).length === 0) { setManagingPanneau({ ...original, draft_data: {} }); return; } const payload = { id: original.id, status: original.status, offerType: original.offerType, currentRate: original.currentRate, physicalPanels: original.physicalPanels, details: { ...original, draft_data: {} } }; const d = await safeFetch('panneaux', { body: payload, setLoading: setIsSaving, successMessage: "Modifications annulées. Version en ligne restaurée." }); if (!isMounted.current) return; if (d) { setManagingPanneau({ ...original, draft_data: {} }); if (refreshData) refreshData(); } }; const renderContent = () => { const baseProps = { data, myClientData, clientOpts, toggleDashboardPin, refreshData, setArchiveConfig, openLocalModal: (name, id, e) => openModal(name, id, false), openLocalDialog: (name, id, e) => openDialog(name, id, false), closeCurrentLayer: (e) => closeCurrentLayer(), activeModal, activeDialog, targetId, dialogId, handleCreateNewPanel }; if (isLockedForClient) return ; switch(activeTab) { case 'dashboard': return ; case 'panels': return ; case 'livraisons': return ; case 'billing': return ; case 'messages': return ; case 'account': return ; default: return ; } }; if (!DashboardLayout) return null; const hasAdminAccess = !!myClientData.admin_access_until; const sidebarFooter = hasAdminAccess ? (
Accès technique actif

Le support technique a accès à votre compte jusqu'au {window.pano_formatDate(myClientData.admin_access_until)}.

) : null; return ( {isLockedForClient && (

Télémaintenance en cours

Le support technique intervient sur votre compte. Vos actions sont temporairement restreintes à la messagerie du support technique.

)} {isImpersonating && (

Mode administrateur actif

Vous contrôlez actuellement le compte de {myClientData.name}. N'oubliez pas de clôturer l'intervention une fois terminé.

)} {renderContent()} {GlobalChatModal && ( openDialog(name, id, false)} openLocalModal={(name, id, e) => openModal(name, id, false)} setPanelTeamModal={setPanelTeamModal} setManagingPanneau={setManagingPanneau} isLockedForClient={isLockedForClient} /> )} {/* MODALES SENSIBLES PROTÉGÉES CONTRE LE BYPASS (ZÉRO-TRUST) */} {!isLockedForClient && ( <> {activeModal === 'editor' && panneauCible && PanneauEditorForm && ( p.id === panneauCible.id) || (panneauCible.id === 'demo-panneau' ? demoPanneau : undefined)} onCancel={() => { closeCurrentLayer(); }} onSaveDraft={() => handleSavePanneau(true)} onPublish={(uiPrefs) => { const errs = validatePanel(uiPrefs); if (errs.length > 0) { setValidationErrors(errs); setTimeout(() => { const scrollEls = document.querySelectorAll('.custom-scrollbar'); scrollEls.forEach(el => el.scrollTo({ top: 0, behavior: 'smooth' })); }, 50); } else { setValidationErrors([]); const isNewOrDraft = panneauCible.status === 'Brouillon' || panneauCible.status === 'Réservé'; handleSavePanneau(false, false, isNewOrDraft, uiPrefs); } }} onDiscardDraft={handleDiscardDraft} onPreview={(draftPanel) => { setPreviewPanneau(draftPanel); openDialog('preview_draft', null, false); }} onEditEntity={(loc, eData) => { setEditingEntity({location: loc, data: eData}); openDialog('entity_editor', null, false); }} draggedItem={draggedItem} handleDragStart={handleDragStart} handleDragOver={handleDragOver} handleDrop={handleDrop} deleteEntity={deleteEntity} isSaving={isSaving} lockedFields={currentLockedFields} validationErrors={validationErrors} myClientData={myClientData} currentUserRole="client" /> )} {activeModal === 'newsletter' && panneauCible && ClientNewsletterModal && ( )} {(activeDialog === 'team' || activeModal === 'team') && teamPanneauCible && ClientPanelTeamModal && ( )} {activeModal === 'delegate' && panneauCible && ClientDelegateShareModal && ( )} {activeModal === 'vault' && panneauCible && ClientLegalVaultModal && ( )} {activeModal === 'riverains_list' && panneauCible && ClientRiverainsListModal && ( )} {activeDialog === 'entity_editor' && editingEntity && EntityEditorModal && ( )} {activeDialog === 'select_offer' && panneauCible && ClientCheckoutModal && ( { replaceCurrentLayer('modal', 'editor', panneauCible.id, false); }} refreshData={refreshData} showToast={window.pano_showToast} onGoToBilling={(e) => { closeCurrentLayer(); setActiveTab('billing'); }} /> )} {activeDialog === 'archive_config' && archiveConfig && ArchiveGeneratorModal && ( { if (archiveConfig.type === 'rgpd') { replaceCurrentLayer('dialog', 'privacy_modal', null, false); } else { closeCurrentLayer(); } }} refreshData={refreshData} /> )} )} {(activeModal === 'preview' || activeDialog === 'preview_draft') && previewCible && PreviewModal && ( { setPreviewPanneau(null); closeCurrentLayer(); }} refreshData={refreshData} isAdmin={false} /> )} {activeDialog === 'confirm' && confirmConfig && ConfirmModal && } {activeDialog === 'confirm_discard_global' && pendingGlobalTab && ConfirmModal && ( { setHasUnsavedChanges(false); setActiveTab(pendingGlobalTab); closeCurrentLayer(); }} onCancel={(e) => { setPendingGlobalTab(null); closeCurrentLayer(); }} /> )} {/* MODALE D'ALERTE MODÉRATION (PERSISTANTE) */} {moderationAlert && Modal && ( setModerationAlert(null)} actions={(close) => ( )} >

{moderationAlert}

)} {/* MODALES GLOBALES DE MOT DE PASSE (ARCHIVES) */} {activeDialog === 'pwd_arc' && dialogId && PasswordPromptModal && ( { const d = await safeFetch('archives/reveal_password', { body: { filename: dialogId, password: pwd }, setLoading: setIsSaving }); if (!isMounted.current) return; if (d) { replaceCurrentLayer('dialog', 'show_pwd_arc', null, false); setTimeout(() => { if (isMounted.current) setRevealedPwd(d.data.password); }, 50); } }} onCancel={closeCurrentLayer} isSaving={isSaving} /> )} {activeDialog === 'show_pwd_arc' && revealedPwd && Modal && ( { setRevealedPwd(null); closeCurrentLayer(); }}>

Voici le mot de passe unique de cette archive :

{revealedPwd}
)}
); }; /* EOF ========== [_react/clients/_clients.jsx] */