import { useCallback, useEffect, useMemo, useRef } from 'react'; import type { ComponentProps, ReactNode } from 'react'; import { SidebarExpandIcon } from '../components/icons'; import DocumentsPanel from '../documents/panel/DocumentsPanel'; import DocumentViewerPanel from '../viewer/DocumentViewerPanel'; import { usePanelManager } from './PanelManagerContext'; import { FolderManagerProvider } from '../folders/FolderManagerContext'; import type { Identifier } from '../types/identifiers'; type EnsureAssetUrl = ( docId: Identifier, asset: unknown, options?: Record, ) => Promise | void; type EnsureViewerData = (docId: Identifier, options?: Record) => Promise; type GetDocumentAsset = (document: unknown, assetType: string) => unknown; type NotifyApiError = (error: unknown, fallbackMessage?: string) => void; type DocumentsTableProps = ComponentProps | null; type DetailPanelProps = (ComponentProps & { onClose?: () => void; onOpenViewer?: (args: { documentIds: Array }) => void; folderNodes?: Map; ensureFolderData?: ( folderId: Identifier | 'root', options?: { force?: boolean; includeDocuments?: boolean }, ) => Promise; }) | null; type WorkspaceSurface = { content: ReactNode; detail?: ReactNode | null; detailMode?: 'overlay' | 'inline' | null } | null; export interface UseWorkspaceSurfaceArgs { sidebarHidden?: boolean; onExpandSidebar?: () => void; documentsTableProps?: DocumentsTableProps; detailPanelProps?: DetailPanelProps; detailPanelOpen?: boolean; viewerWorkspaceDocument?: unknown; viewerDocumentId?: Identifier | null; ensureAssetUrl?: EnsureAssetUrl; ensureViewerData?: EnsureViewerData; getDocumentAsset?: GetDocumentAsset; notifyApiError?: NotifyApiError; closeDocumentViewer?: () => void; } interface UseWorkspaceSurfaceResult { surface: WorkspaceSurface; } export const useWorkspaceSurface = ({ sidebarHidden = false, onExpandSidebar, documentsTableProps, detailPanelProps, detailPanelOpen = false, viewerWorkspaceDocument, viewerDocumentId, ensureAssetUrl, ensureViewerData, getDocumentAsset, notifyApiError, closeDocumentViewer, }: UseWorkspaceSurfaceArgs): UseWorkspaceSurfaceResult => { const { registerDetailCloseHandler, setDetailActive } = usePanelManager(); useEffect(() => { const handler = detailPanelProps?.onClose || null; registerDetailCloseHandler(handler); return () => registerDetailCloseHandler(null); }, [registerDetailCloseHandler, detailPanelProps?.onClose]); const setDetailActiveRef = useRef(setDetailActive); useEffect(() => { setDetailActiveRef.current = setDetailActive; }, [setDetailActive]); useEffect(() => { setDetailActive(Boolean(detailPanelOpen)); }, [detailPanelOpen, setDetailActive]); useEffect(() => { return () => { if (setDetailActiveRef.current) { setDetailActiveRef.current(false); } }; }, []); const renderSidebarToggle = useCallback<() => ReactNode>(() => { if (!sidebarHidden) { return null; } return ( ); }, [sidebarHidden, onExpandSidebar]); const documentsSurface = useMemo(() => { if (!documentsTableProps) { return null; } const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null; const viewMode = documentsTableProps.viewMode; const sidebarMode = viewMode === 'desk' ? 'overlay' : 'inline'; const detailMode: 'overlay' | 'inline' | null = detailPanelOpen && detailPanelProps ? sidebarMode : null; const detail = detailPanelOpen && detailPanelProps ? (() => { const { onClose, onOpenViewer, tags: tagOptions, folderNodes, ensureFolderData, ...restDetailProps } = detailPanelProps; const viewer = ( ); if (folderNodes && ensureFolderData) { return ( {viewer} ); } return ( <>{viewer} ); })() : null; return { content: ( ), detail, detailMode, }; }, [ documentsTableProps, renderSidebarToggle, detailPanelOpen, detailPanelProps, ]); const showViewerWorkspace = Boolean(viewerDocumentId); const viewerSurface = useMemo(() => { if (!showViewerWorkspace) { return null; } const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null; const detailExtras = detailPanelProps || {}; const { tagLookupById, tags: tagOptions, onTagAdd, onTagRemove, correspondents, correspondentLookupById, onCorrespondentAdd, onCorrespondentRemove, onUpdateTitle, onUpdateIssued, resolveFolderPath, folderNodes, ensureFolderData, } = detailExtras; const viewer = ( ); const content = folderNodes && ensureFolderData ? ( {viewer} ) : viewer; return { content, detail: null, detailMode: null }; }, [ showViewerWorkspace, viewerWorkspaceDocument, ensureViewerData, ensureAssetUrl, getDocumentAsset, notifyApiError, renderSidebarToggle, closeDocumentViewer, detailPanelProps, ]); const surface = useMemo(() => { if (showViewerWorkspace) { return viewerSurface; } return documentsSurface; }, [showViewerWorkspace, viewerSurface, documentsSurface]); return { surface }; };