import React, { useState, useEffect, useCallback, useMemo, } from 'react'; import { useTranslation } from 'next-i18next'; import { Modal, ModalHeader, ModalBody, ModalFooter, } from 'reactstrap'; import { debounce } from 'throttle-debounce'; import { apiv3Get, apiv3Post } from '~/client/util/apiv3-client'; import { toastError } from '~/client/util/toastr'; import { useIsSearchServiceReachable, useSiteUrl } from '~/stores/context'; import { usePageDuplicateModal } from '~/stores/modal'; import DuplicatePathsTable from './DuplicatedPathsTable'; import ApiErrorMessageList from './PageManagement/ApiErrorMessageList'; import PagePathAutoComplete from './PagePathAutoComplete'; const PageDuplicateModal = (): JSX.Element => { const { t } = useTranslation(); const { data: siteUrl } = useSiteUrl(); const { data: isReachable } = useIsSearchServiceReachable(); const { data: duplicateModalData, close: closeDuplicateModal } = usePageDuplicateModal(); const isOpened = duplicateModalData?.isOpened ?? false; const page = duplicateModalData?.page; const [pageNameInput, setPageNameInput] = useState(''); const [errs, setErrs] = useState(null); const [subordinatedPages, setSubordinatedPages] = useState([]); const [existingPaths, setExistingPaths] = useState([]); const [isDuplicateRecursively, setIsDuplicateRecursively] = useState(true); const [isDuplicateRecursivelyWithoutExistPath, setIsDuplicateRecursivelyWithoutExistPath] = useState(true); const updateSubordinatedList = useCallback(async() => { if (page == null) { return; } const { path } = page; try { const res = await apiv3Get('/pages/subordinated-list', { path }); setSubordinatedPages(res.data.subordinatedPages); } catch (err) { setErrs(err); toastError(t('modal_duplicate.label.Failed to get subordinated pages')); } }, [page, t]); const checkExistPaths = useCallback(async(fromPath, toPath) => { if (page == null) { return; } try { const res = await apiv3Get<{ existPaths: string[] }>('/page/exist-paths', { fromPath, toPath }); const { existPaths } = res.data; setExistingPaths(existPaths); } catch (err) { setErrs(err); toastError(t('modal_rename.label.Failed to get exist path')); } }, [page, t]); const checkExistPathsDebounce = useMemo(() => { return debounce(1000, checkExistPaths); }, [checkExistPaths]); useEffect(() => { if (isOpened && page != null && pageNameInput !== page.path) { checkExistPathsDebounce(page.path, pageNameInput); } }, [isOpened, pageNameInput, subordinatedPages, checkExistPathsDebounce, page]); /** * change pageNameInput for PagePathAutoComplete * @param {string} value */ function ppacInputChangeHandler(value) { setErrs(null); setPageNameInput(value); } /** * change pageNameInput * @param {string} value */ function inputChangeHandler(value) { setErrs(null); setPageNameInput(value); } function changeIsDuplicateRecursivelyHandler() { setIsDuplicateRecursively(!isDuplicateRecursively); } useEffect(() => { if (page != null && isOpened) { updateSubordinatedList(); setPageNameInput(page.path); } }, [isOpened, page, updateSubordinatedList]); const duplicate = useCallback(async() => { if (page == null) { return; } setErrs(null); const { pageId, path } = page; try { const { data } = await apiv3Post('/pages/duplicate', { pageId, pageNameInput, isRecursively: isDuplicateRecursively }); const onDuplicated = duplicateModalData?.opts?.onDuplicated; const fromPath = path; const toPath = data.page.path; if (onDuplicated != null) { onDuplicated(fromPath, toPath); } closeDuplicateModal(); } catch (err) { setErrs(err); } }, [closeDuplicateModal, duplicateModalData?.opts?.onDuplicated, isDuplicateRecursively, page, pageNameInput]); useEffect(() => { if (isOpened) { return; } // reset states after the modal closed setTimeout(() => { setPageNameInput(''); setErrs(null); setSubordinatedPages([]); setExistingPaths([]); setIsDuplicateRecursively(true); setIsDuplicateRecursivelyWithoutExistPath(false); }, 1000); }, [isOpened]); const renderBodyContent = () => { if (!isOpened || page == null) { return <>; } const { path } = page; const isTargetPageDuplicate = existingPaths.includes(pageNameInput); return ( <>

{path}

{siteUrl}
{isReachable ? ( ) : ( inputChangeHandler(e.target.value)} required /> )}
{ isTargetPageDuplicate && (

Error: Target path is duplicated.

) }
{isDuplicateRecursively && existingPaths.length !== 0 && (
setIsDuplicateRecursivelyWithoutExistPath(!isDuplicateRecursivelyWithoutExistPath)} />
)}
{isDuplicateRecursively && existingPaths.length !== 0 && ( ) }
); }; const renderFooterContent = () => { if (!isOpened || page == null) { return <>; } const submitButtonEnabled = existingPaths.length === 0 || (isDuplicateRecursively && isDuplicateRecursivelyWithoutExistPath); return ( <> ); }; return ( { t('modal_duplicate.label.Duplicate page') } {renderBodyContent()} {renderFooterContent()} ); }; export default PageDuplicateModal;