import { useCallback, useEffect, useRef, useState } from 'react'; export const useDetailPanel = ({ documentLookup, orderedSelectedDocuments, selectionOrder, documentsViewMode, getRowId, isDocumentRowKey, }) => { const [detailPanelOpen, setDetailPanelOpen] = useState(false); const [detailPanelDocIds, setDetailPanelDocIds] = useState([]); const [detailPanelDocs, setDetailPanelDocs] = useState([]); const lastScrolledDetailDocRef = useRef(null); const latestOrderedDocsRef = useRef([]); useEffect(() => { latestOrderedDocsRef.current = orderedSelectedDocuments; if (detailPanelOpen && orderedSelectedDocuments.length) { const snapshotIds = orderedSelectedDocuments .map((doc) => doc?.id) .filter((id) => typeof id === 'string' || typeof id === 'number'); if (snapshotIds.length) { setDetailPanelDocIds(snapshotIds); } } }, [orderedSelectedDocuments, detailPanelOpen]); const resolveDocsForIds = useCallback( (ids, fallbackDocs = []) => { if (!ids?.length) { return []; } const fallbackMap = new Map((fallbackDocs || []).map((doc) => [doc?.id, doc])); return ids .map((id) => documentLookup.get(id) || fallbackMap.get(id) || null) .filter(Boolean); }, [documentLookup], ); useEffect(() => { if (!detailPanelDocIds.length) { setDetailPanelDocs((prev) => (prev.length ? [] : prev)); return; } setDetailPanelDocs((prevDocs) => { const resolved = resolveDocsForIds(detailPanelDocIds, prevDocs); if (resolved.length === prevDocs.length && resolved.every((doc, index) => doc === prevDocs[index])) { return prevDocs; } return resolved; }); }, [detailPanelDocIds, resolveDocsForIds]); useEffect(() => { if (!detailPanelOpen) { lastScrolledDetailDocRef.current = null; return; } if (!orderedSelectedDocuments.length) { lastScrolledDetailDocRef.current = null; return; } let lastSelectedId = null; for (let index = selectionOrder.length - 1; index >= 0; index -= 1) { const key = selectionOrder[index]; if (isDocumentRowKey(key)) { lastSelectedId = getRowId(key); if (lastSelectedId) { break; } } } if (!lastSelectedId && orderedSelectedDocuments.length) { const fallbackDoc = orderedSelectedDocuments[orderedSelectedDocuments.length - 1]; lastSelectedId = fallbackDoc?.id || null; } if (!lastSelectedId || lastScrolledDetailDocRef.current === lastSelectedId) { return; } if (typeof document === 'undefined') { return; } const targetElement = document.getElementById(`document-row-${lastSelectedId}`) || document.getElementById(`document-card-${lastSelectedId}`); if (!targetElement) { return; } lastScrolledDetailDocRef.current = lastSelectedId; requestAnimationFrame(() => { targetElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); }); }, [ detailPanelOpen, orderedSelectedDocuments, selectionOrder, documentsViewMode, getRowId, isDocumentRowKey, ]); const detailPanelSelectedDocuments = detailPanelDocs; const openDetailPanel = useCallback( ({ documentIds: explicitIds, documents: explicitDocs } = {}) => { let sourceDocs = Array.isArray(explicitDocs) ? explicitDocs : null; let snapshotIds = Array.isArray(explicitIds) ? explicitIds.filter((id) => typeof id === 'string' || typeof id === 'number') : null; if (!snapshotIds?.length) { if (!sourceDocs || !sourceDocs.length) { sourceDocs = latestOrderedDocsRef.current; } snapshotIds = Array.isArray(sourceDocs) ? sourceDocs .map((doc) => doc?.id) .filter((id) => typeof id === 'string' || typeof id === 'number') : []; } const uniqueIds = []; snapshotIds.forEach((id) => { if (!uniqueIds.includes(id)) { uniqueIds.push(id); } }); const resolvedDocs = resolveDocsForIds(uniqueIds, sourceDocs || latestOrderedDocsRef.current); setDetailPanelDocIds(uniqueIds); setDetailPanelDocs(resolvedDocs); setDetailPanelOpen(true); }, [resolveDocsForIds], ); const closeDetailPanel = useCallback(() => { setDetailPanelOpen(false); }, []); return { detailPanelOpen, detailPanelSelectedDocuments, openDetailPanel, closeDetailPanel, setDetailPanelOpen, }; }; export default useDetailPanel;