// ECO-PANNEAU.FR - _react/clients/_clients_panneaux.jsx
window.pano_ClientPanelsTab = ({ data, myClientData, refreshData, setManagingPanneau, setValidationErrors, setPreviewPanneau, clientOpts, toggleDashboardPin, handleCreateNewPanel, setPanelTeamModal, setArchiveConfig }) => {
// 1. - HOOKS ET ROUTAGE Zéro-Dette
const { useState } = React;
// SÉCURITÉ ANTI-FUITE DE MÉMOIRE (Memory Leak)
const { isMounted, safeFetch } = window.pano_useSafeFetch();
// CORRECTION ZÉRO-DETTE : Distribution centralisée des props du routeur pour éviter les Render Loops
const urlModal = window.pano_useUrlModal ? window.pano_useUrlModal() : {};
const { openModal, openDialog, closeCurrentLayer, openChat, activeModal, activeDialog, targetId, dialogId } = urlModal;
// 2. - COMPOSANTS ET ICÔNES
const {
BuildingIcon, PlusIcon, AlertTriangleIcon, PinIcon, QrCodeIcon, EditIcon
} = window.pano_getIcons();
const {
Modal, Button, AlertBox,
CardGrid, SearchBar, EmptySearch, PaginationFooter, ClientPanelCard, ClientInviteCard
} = window.pano_getComponents();
// 3. - RECHERCHE ET PAGINATION
const { pendingInvites, visiblePanels } = window.pano_getPanelAccessRights ? window.pano_getPanelAccessRights(data.panneaux || [], myClientData.id, myClientData.email_hash) : { pendingInvites:[], visiblePanels:[] };
const isSuspended = myClientData.paymentStatus === 'suspended';
const purchasesAllowed = data.settings?.allow_new_purchases !== '0';
const hasAnyPanelOrInvite = visiblePanels.length > 0 || pendingInvites.length > 0;
const {
searchQuery, setSearchQuery,
visibleCount, setVisibleCount,
filteredData: filteredPanels
} = window.pano_useSearchAndPagination(visiblePanels, (p, q) => {
const n = window.pano_normalizeString;
return n(p.name).includes(q) ||
n(p.location).includes(q) ||
n(p.id).includes(q) ||
n(p.status).includes(q);
});
const activePendingInvites = pendingInvites.filter(p => {
if (!searchQuery) return true;
const q = window.pano_normalizeString(searchQuery);
const n = window.pano_normalizeString;
const inviter = p.owner_company || p.owner_name || '';
return n(p.name).includes(q) || n(inviter).includes(q);
});
const isFeatureEnabled = (adminOpt, clientVal) => {
if (adminOpt === 'disabled') return false;
if (adminOpt === 'active') return true;
if (adminOpt === 'optional_on') return clientVal !== false;
if (adminOpt === 'optional_off' || adminOpt === 'optional') return clientVal === true;
return true;
};
const hasNewsletterFeature = isFeatureEnabled(data.settings?.opt_newsletter, clientOpts?.newsletter);
const hasCollabFeature = isFeatureEnabled(data.settings?.opt_collab, clientOpts?.collab);
const hasMessagingFeature = isFeatureEnabled(data.settings?.opt_messaging, clientOpts?.messaging);
const threads = window.pano_buildClientChatThreads ? window.pano_buildClientChatThreads(data.interactions || [], myClientData, visiblePanels, pendingInvites) : [];
const unreadMap = {};
threads.forEach(t => {
if (t.unread > 0 && t.panneauId) {
if (!unreadMap[t.panneauId]) {
unreadMap[t.panneauId] = { total: 0, riverain: 0, group: 0 };
}
unreadMap[t.panneauId].total += t.unread;
if (t.type === 'riverain') unreadMap[t.panneauId].riverain += t.unread;
if (t.type === 'group') unreadMap[t.panneauId].group += t.unread;
}
});
const pinnedIds = clientOpts?.pinned_panels || [];
const attentionPanels = [];
const pinnedPanels = [];
const draftChangesPanels = [];
const draftPanelsList = [];
const otherPanels = [];
// 4.1 - Classification Urgence > Favoris > Reste
filteredPanels.forEach(c => {
if (c.status === 'Réservé') return;
const isPinned = pinnedIds.includes(c.id);
const unreadCount = unreadMap[c.id]?.total || 0;
const hasDraft = c.draft_data && Object.keys(c.draft_data).length > 0;
const isUnreadDOE = c.status === 'DOE' && !c.doe_downloaded;
const needsAttention = c.status === 'Suspendu' || c.status === 'Attente validation' || c.inactivity_alert_level > 0 || unreadCount > 0 || isUnreadDOE || (c.physicalPanels > 0 && (c.shipping_status === 'Expédié' || c.shipping_status === 'Attente validation client'));
if (needsAttention) {
attentionPanels.push(c);
} else if (isPinned) {
pinnedPanels.push(c);
} else if (c.status === 'Actif' && hasDraft) {
draftChangesPanels.push(c);
} else if (c.status === 'Brouillon') {
draftPanelsList.push(c);
} else {
otherPanels.push(c);
}
});
const displayedOtherPanels = otherPanels.slice(0, visibleCount);
const demoPanneau = (data.panneaux || []).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 demoHasDraft = demoPanneau.draft_data && Object.keys(demoPanneau.draft_data).length > 0;
// 5. - RENDU UI
return (
Mes panneaux
Gestion de vos affichages et de vos collaborations.
{hasAnyPanelOrInvite && SearchBar && (
{!isSuspended && (
Nouveau panneau
)}
)}
{!hasAnyPanelOrInvite && !isSuspended && (
Nouveau panneau
)}
{(!purchasesAllowed) &&
Les commandes sont temporairement suspendues, mais la création de brouillons reste autorisée. }
{/* SECTION DÉMO (SI PRÉSENT DANS VISIBLE PANELS) */}
{visiblePanels.some(p => p.id === 'demo-panneau') && (
Panneau de démonstration
{demoHasDraft && Modifié }
Modifiez ce panneau pour mettre à jour la page d'accueil.
{ const livePanel = { ...demoPanneau }; delete livePanel.draft_data; if (setPreviewPanneau) setPreviewPanneau(livePanel); openModal('preview', livePanel.id, false); }} className="bg-white shadow-sm flex-1 sm:flex-none" title="Voir le panneau en ligne" />
{
const panelToEdit = JSON.parse(JSON.stringify(demoPanneau));
if (panelToEdit.draft_data && Object.keys(panelToEdit.draft_data).length > 0) {
const draft = panelToEdit.draft_data;
delete panelToEdit.draft_data;
Object.assign(panelToEdit, draft);
}
setManagingPanneau(panelToEdit);
setValidationErrors([]);
openModal('editor', 'demo-panneau', false);
}} className="w-full sm:w-auto px-8 py-3.5 uppercase tracking-widest font-black shadow-md justify-center">
Édition
)}
{/* 5.2 - Affichage des grilles conditionnelles */}
{!hasAnyPanelOrInvite ? (
Aucun panneau
Vous n'avez pas encore de projet en cours.
) : filteredPanels.length === 0 && activePendingInvites.length === 0 ? (
EmptySearch &&
) : (
<>
{/* 5.2.1 - Priorité */}
{(attentionPanels.length > 0 || activePendingInvites.length > 0) && (
Action requise
{activePendingInvites.map(p => (
))}
{attentionPanels.map(c => {
return (
toggleDashboardPin('pinned_panels', id, e)}
unreadMap={unreadMap} setPreviewPanneau={setPreviewPanneau}
setManagingPanneau={setManagingPanneau} setValidationErrors={setValidationErrors}
isSuspended={isSuspended} hasNewsletterFeature={hasNewsletterFeature}
hasCollabFeature={hasCollabFeature} hasMessagingFeature={hasMessagingFeature} refreshData={refreshData}
setPanelTeamModal={setPanelTeamModal} setArchiveConfig={setArchiveConfig}
openModal={openModal} openDialog={openDialog} closeCurrentLayer={closeCurrentLayer} openChat={openChat}
activeDialog={activeDialog} dialogId={dialogId}
/>
);
})}
)}
{/* 5.2.2 - Favoris */}
{pinnedPanels.length > 0 && (
Favoris (Épinglés)
{pinnedPanels.map(c => {
return (
toggleDashboardPin('pinned_panels', id, e)}
unreadMap={unreadMap} setPreviewPanneau={setPreviewPanneau}
setManagingPanneau={setManagingPanneau} setValidationErrors={setValidationErrors}
isSuspended={isSuspended} hasNewsletterFeature={hasNewsletterFeature}
hasCollabFeature={hasCollabFeature} hasMessagingFeature={hasMessagingFeature} refreshData={refreshData}
setPanelTeamModal={setPanelTeamModal} setArchiveConfig={setArchiveConfig}
openModal={openModal} openDialog={openDialog} closeCurrentLayer={closeCurrentLayer} openChat={openChat}
activeDialog={activeDialog} dialogId={dialogId}
/>
);
})}
)}
{/* 5.2.3 - Modifications à publier */}
{draftChangesPanels.length > 0 && (
Modifications à publier
{draftChangesPanels.map(c => {
return (
toggleDashboardPin('pinned_panels', id, e)}
unreadMap={unreadMap} setPreviewPanneau={setPreviewPanneau}
setManagingPanneau={setManagingPanneau} setValidationErrors={setValidationErrors}
isSuspended={isSuspended} hasNewsletterFeature={hasNewsletterFeature}
hasCollabFeature={hasCollabFeature} hasMessagingFeature={hasMessagingFeature} refreshData={refreshData}
setPanelTeamModal={setPanelTeamModal} setArchiveConfig={setArchiveConfig}
openModal={openModal} openDialog={openDialog} closeCurrentLayer={closeCurrentLayer} openChat={openChat}
activeDialog={activeDialog} dialogId={dialogId}
/>
);
})}
)}
{/* 5.2.4 - Brouillons */}
{draftPanelsList.length > 0 && (
Mes brouillons
{draftPanelsList.map(c => {
return (
toggleDashboardPin('pinned_panels', id, e)}
unreadMap={unreadMap} setPreviewPanneau={setPreviewPanneau}
setManagingPanneau={setManagingPanneau} setValidationErrors={setValidationErrors}
isSuspended={isSuspended} hasNewsletterFeature={hasNewsletterFeature}
hasCollabFeature={hasCollabFeature} hasMessagingFeature={hasMessagingFeature} refreshData={refreshData}
setPanelTeamModal={setPanelTeamModal} setArchiveConfig={setArchiveConfig}
openModal={openModal} openDialog={openDialog} closeCurrentLayer={closeCurrentLayer} openChat={openChat}
activeDialog={activeDialog} dialogId={dialogId}
/>
);
})}
)}
{/* 5.2.5 - Autres panneaux */}
{otherPanels.length > 0 && (
Autres panneaux
{otherPanels.length}
{displayedOtherPanels.map(c => {
return (
toggleDashboardPin('pinned_panels', id, e)}
unreadMap={unreadMap} setPreviewPanneau={setPreviewPanneau}
setManagingPanneau={setManagingPanneau} setValidationErrors={setValidationErrors}
isSuspended={isSuspended} hasNewsletterFeature={hasNewsletterFeature}
hasCollabFeature={hasCollabFeature} hasMessagingFeature={hasMessagingFeature} refreshData={refreshData}
setPanelTeamModal={setPanelTeamModal} setArchiveConfig={setArchiveConfig}
openModal={openModal} openDialog={openDialog} closeCurrentLayer={closeCurrentLayer} openChat={openChat}
activeDialog={activeDialog} dialogId={dialogId}
/>
);
})}
{PaginationFooter && (
)}
)}
>
)}
);
};
/* EOF ========== [_react/clients/_clients_panneaux.jsx] */