import type React from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { Origin } from '@growi/core'; import { pagePathUtils, pathUtils } from '@growi/core/dist/utils'; import { normalizePath } from '@growi/core/dist/utils/path-utils'; import { format } from 'date-fns/format'; import { useAtomValue } from 'jotai'; import { useTranslation } from 'next-i18next'; import path from 'path'; import { DropdownItem, DropdownMenu, DropdownToggle, Modal, ModalBody, ModalHeader, UncontrolledButtonDropdown, } from 'reactstrap'; import { debounce } from 'throttle-debounce'; import { useCreateTemplatePage } from '~/client/services/create-page'; import { useCreatePage } from '~/client/services/create-page/use-create-page'; import { useToastrOnError } from '~/client/services/use-toastr-on-error'; import { useCurrentUser } from '~/states/global'; import { isSearchServiceReachableAtom } from '~/states/server-configurations'; import { usePageCreateModalActions, usePageCreateModalStatus, } from '~/states/ui/modal/page-create'; import PagePathAutoComplete from './PagePathAutoComplete'; import styles from './PageCreateModal.module.scss'; const { isCreatablePage, isUsersHomepage } = pagePathUtils; const PageCreateModal: React.FC = () => { const { t } = useTranslation(); const currentUser = useCurrentUser(); const { isOpened, path: pathname = '' } = usePageCreateModalStatus(); const { close: closeCreateModal } = usePageCreateModalActions(); const { create } = useCreatePage(); const { createTemplate } = useCreateTemplatePage(); const isReachable = useAtomValue(isSearchServiceReachableAtom); // Memoize computed values const userHomepagePath = useMemo( () => pagePathUtils.userHomepagePath(currentUser), [currentUser], ); const isCreatable = useMemo( () => isCreatablePage(pathname) || isUsersHomepage(pathname), [pathname], ); const pageNameInputInitialValue = useMemo( () => (isCreatable ? pathUtils.addTrailingSlash(pathname) : '/'), [isCreatable, pathname], ); const now = useMemo(() => format(new Date(), 'yyyy/MM/dd'), []); const todaysParentPath = useMemo( () => [ userHomepagePath, t('create_page_dropdown.todays.memo', { ns: 'commons' }), now, ].join('/'), [userHomepagePath, t, now], ); const [todayInput, setTodayInput] = useState(''); const [pageNameInput, setPageNameInput] = useState(pageNameInputInitialValue); const [template, setTemplate] = useState(null); const [isMatchedWithUserHomepagePath, setIsMatchedWithUserHomepagePath] = useState(false); const checkIsUsersHomepageDebounce = useMemo(() => { return debounce(1000, (input: string) => { setIsMatchedWithUserHomepagePath(isUsersHomepage(input)); }); }, []); useEffect(() => { if (isOpened) { checkIsUsersHomepageDebounce(pageNameInput); } }, [isOpened, checkIsUsersHomepageDebounce, pageNameInput]); const transitBySubmitEvent = useCallback((e, transitHandler) => { // prevent page transition by submit e.preventDefault(); transitHandler(); }, []); /** * change todayInput * @param {string} value */ const onChangeTodayInputHandler = useCallback((value) => { setTodayInput(value); }, []); /** * change template * @param {string} value */ const onChangeTemplateHandler = useCallback((value) => { setTemplate(value); }, []); /** * access today page */ const createTodayPage = useCallback(async () => { const joinedPath = [todaysParentPath, todayInput].join('/'); return create( { path: joinedPath, parentPath: todaysParentPath, wip: true, origin: Origin.View, }, { onTerminated: closeCreateModal }, ); }, [closeCreateModal, create, todayInput, todaysParentPath]); /** * access input page */ const createInputPage = useCallback(async () => { const targetPath = normalizePath(pageNameInput); const parentPath = path.dirname(targetPath); return create( { path: targetPath, parentPath, wip: true, origin: Origin.View, }, { onTerminated: closeCreateModal }, ); }, [closeCreateModal, create, pageNameInput]); /** * access template page */ const createTemplatePage = useCallback(async () => { const label = template === 'children' ? '_template' : '__template'; await createTemplate?.(label); closeCreateModal(); }, [closeCreateModal, createTemplate, template]); const createTodaysMemoWithToastr = useToastrOnError(createTodayPage); const createInputPageWithToastr = useToastrOnError(createInputPage); const createTemplateWithToastr = useToastrOnError(createTemplatePage); const renderCreateTodayForm = useMemo(() => { if (!isOpened) { return <>>; } return (