import React, { useState, useEffect, useCallback, } from 'react'; import PropTypes from 'prop-types'; import { Modal, ModalHeader, ModalBody, ModalFooter, } from 'reactstrap'; import { withTranslation } from 'react-i18next'; import { debounce } from 'throttle-debounce'; import { usePageRenameModalStatus, usePageRenameModalOpened } from '~/stores/ui'; import { withUnstatedContainers } from './UnstatedUtils'; import { toastError } from '~/client/util/apiNotification'; import AppContainer from '~/client/services/AppContainer'; import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client'; import ApiErrorMessageList from './PageManagement/ApiErrorMessageList'; import ComparePathsTable from './ComparePathsTable'; import DuplicatedPathsTable from './DuplicatedPathsTable'; const PageRenameModal = (props) => { const { t, appContainer, } = props; const { crowi } = appContainer.config; const { data: isOpened } = usePageRenameModalOpened(); const { data: pagesDataToRename, close: closeRenameModal } = usePageRenameModalStatus(); const { path, revisionId, pageId } = pagesDataToRename; const [pageNameInput, setPageNameInput] = useState(''); const [errs, setErrs] = useState(null); const [subordinatedPages, setSubordinatedPages] = useState([]); const [existingPaths, setExistingPaths] = useState([]); const [isRenameRecursively, SetIsRenameRecursively] = useState(true); const [isRenameRedirect, SetIsRenameRedirect] = useState(false); const [isRemainMetadata, SetIsRemainMetadata] = useState(false); const [subordinatedError] = useState(null); const [isRenameRecursivelyWithoutExistPath, setIsRenameRecursivelyWithoutExistPath] = useState(true); function changeIsRenameRecursivelyHandler() { SetIsRenameRecursively(!isRenameRecursively); } function changeIsRenameRecursivelyWithoutExistPathHandler() { setIsRenameRecursivelyWithoutExistPath(!isRenameRecursivelyWithoutExistPath); } function changeIsRenameRedirectHandler() { SetIsRenameRedirect(!isRenameRedirect); } function changeIsRemainMetadataHandler() { SetIsRemainMetadata(!isRemainMetadata); } const updateSubordinatedList = useCallback(async() => { try { const res = await apiv3Get('/pages/subordinated-list', { path }); const { subordinatedPaths } = res.data; setSubordinatedPages(subordinatedPaths); } catch (err) { setErrs(err); toastError(t('modal_rename.label.Fail to get subordinated pages')); } }, [path, t]); useEffect(() => { if (isOpened) { updateSubordinatedList(); setPageNameInput(path); } }, [isOpened, path, updateSubordinatedList]); const checkExistPaths = async(newParentPath) => { try { const res = await apiv3Get('/page/exist-paths', { fromPath: path, toPath: newParentPath }); const { existPaths } = res.data; setExistingPaths(existPaths); } catch (err) { setErrs(err); toastError(t('modal_rename.label.Fail to get exist path')); } }; // eslint-disable-next-line react-hooks/exhaustive-deps const checkExistPathsDebounce = useCallback( debounce(1000, checkExistPaths), [path], ); useEffect(() => { if (pageId != null && pageNameInput !== path) { checkExistPathsDebounce(pageNameInput, subordinatedPages); } }, [pageNameInput, subordinatedPages, pageId, path, checkExistPathsDebounce]); /** * change pageNameInput * @param {string} value */ function inputChangeHandler(value) { setErrs(null); setPageNameInput(value); } async function rename() { setErrs(null); try { const response = await apiv3Put('/pages/rename', { revisionId, pageId, isRecursively: isRenameRecursively, isRenameRedirect, isRemainMetadata, newPagePath: pageNameInput, path, }); const { page } = response.data; const url = new URL(page.path, 'https://dummy'); url.searchParams.append('renamedFrom', path); if (isRenameRedirect) { url.searchParams.append('withRedirect', true); } window.location.href = `${url.pathname}${url.search}`; } catch (err) { setErrs(err); } } return ( { t('modal_rename.label.Move/Rename page') }

{ path }

{crowi.url}
{ e.preventDefault(); rename() }}> inputChangeHandler(e.target.value)} required autoFocus />
{existingPaths.length !== 0 && (
)} {isRenameRecursively && path != null && } {isRenameRecursively && existingPaths.length !== 0 && }
{subordinatedError}
); }; /** * Wrapper component for using unstated */ const PageRenameModalWrapper = withUnstatedContainers(PageRenameModal, [AppContainer]); PageRenameModal.propTypes = { t: PropTypes.func.isRequired, // i18next appContainer: PropTypes.instanceOf(AppContainer).isRequired, }; export default withTranslation()(PageRenameModalWrapper);