163 lines
4.5 KiB
JavaScript
163 lines
4.5 KiB
JavaScript
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;
|