import type { FC, JSX } from 'react'; import { Suspense, useState, useCallback, useMemo, } from 'react'; import { useTranslation } from 'next-i18next'; import { dirname } from 'pathe'; import { Modal, ModalHeader, ModalBody, ModalFooter, Button, } from 'reactstrap'; import { ItemsTree } from '~/features/page-tree/components'; import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context'; import { useCurrentPageData } from '~/states/page'; import { usePageSelectModalStatus, usePageSelectModalActions, useSelectedPageInModal, } from '~/states/ui/modal/page-select'; import ItemsTreeContentSkeleton from '../ItemsTree/ItemsTreeContentSkeleton'; import { TreeItemForModal, treeItemForModalSize } from './TreeItemForModal'; const PageSelectModalSubstance: FC = () => { const { close: closeModal } = usePageSelectModalActions(); const [isIncludeSubPage, setIsIncludeSubPage] = useState(true); const [scrollerElem, setScrollerElem] = useState(null); // Callback ref to capture the scroller element and trigger re-render const scrollerRefCallback = useCallback((node: HTMLDivElement | null) => { setScrollerElem(node); }, []); const { t } = useTranslation(); const isGuestUser = useIsGuestUser(); const isReadOnlyUser = useIsReadOnlyUser(); const currentPage = useCurrentPageData(); const { opts } = usePageSelectModalStatus(); // Get selected page from atom const selectedPage = useSelectedPageInModal(); const isHierarchicalSelectionMode = opts?.isHierarchicalSelectionMode ?? false; const onClickCancel = useCallback(() => { closeModal(); }, [closeModal]); const { onSelected } = opts ?? {}; const onClickDone = useCallback(() => { if (selectedPage != null) { onSelected?.(selectedPage, isIncludeSubPage); } closeModal(); }, [selectedPage, closeModal, isIncludeSubPage, onSelected]); // Memoize heavy calculation - parent page path without trailing slash for matching const parentPagePath = useMemo(() => { const dn = dirname(currentPage?.path ?? ''); // Ensure root path is '/' not '' return dn === '' ? '/' : dn; }, [currentPage?.path]); // Memoize target path calculation const targetPath = useMemo(() => ( selectedPage?.path || parentPagePath ), [selectedPage?.path, parentPagePath]); // Memoize checkbox handler const handleIncludeSubPageChange = useCallback(() => { setIsIncludeSubPage(!isIncludeSubPage); }, [isIncludeSubPage]); if (isGuestUser == null) { return <>; } return ( <> {t('page_select_modal.select_page_location')} }> {/* 133px = 63px(ModalHeader) + 70px(ModalFooter) */}
{scrollerElem && ( treeItemForModalSize} scrollerElem={scrollerElem} /> )}
{ isHierarchicalSelectionMode && (
)}
); }; export const PageSelectModal = (): JSX.Element => { const pageSelectModalData = usePageSelectModalStatus(); const { close: closePageSelectModal } = usePageSelectModalActions(); const isOpen = pageSelectModalData?.isOpened ?? false; if (!isOpen) { return <>; } return ( ); };