import type { FC } from 'react'; import React, { useCallback, useState, } from 'react'; import nodePath from 'path'; import type { IPageInfoAll, IPageToDeleteWithMeta } from '@growi/core'; import { pathUtils } from '@growi/core/dist/utils'; import { useTranslation } from 'next-i18next'; import { DropdownToggle } from 'reactstrap'; import { bookmark, unbookmark, resumeRenameOperation } from '~/client/services/page-operation'; import { apiv3Put } from '~/client/util/apiv3-client'; import { ValidationTarget } from '~/client/util/input-validator'; import { toastError, toastSuccess } from '~/client/util/toastr'; import { NotAvailableForGuest } from '~/components/NotAvailableForGuest'; import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark'; import { useSWRMUTxPageInfo } from '~/stores/page'; import ClosableTextInput from '../../Common/ClosableTextInput'; import { PageItemControl } from '../../Common/Dropdown/PageItemControl'; import { type TreeItemToolProps, NotDraggableForClosableTextInput, SimpleItemTool, } from '../../TreeItem'; export const Ellipsis: FC = (props) => { const [isRenameInputShown, setRenameInputShown] = useState(false); const { t } = useTranslation(); const { itemNode, onRenamed, onClickDuplicateMenuItem, onClickDeleteMenuItem, isEnableActions, isReadOnlyUser, } = props; const { page } = itemNode; const { trigger: mutateCurrentUserBookmarks } = useSWRMUTxCurrentUserBookmarks(); const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(page._id ?? null); const bookmarkMenuItemClickHandler = async(_pageId: string, _newValue: boolean): Promise => { const bookmarkOperation = _newValue ? bookmark : unbookmark; await bookmarkOperation(_pageId); mutateCurrentUserBookmarks(); mutatePageInfo(); }; const duplicateMenuItemClickHandler = useCallback((): void => { if (onClickDuplicateMenuItem == null) { return; } const { _id: pageId, path } = page; if (pageId == null || path == null) { throw Error('Any of _id and path must not be null.'); } const pageToDuplicate = { pageId, path }; onClickDuplicateMenuItem(pageToDuplicate); }, [onClickDuplicateMenuItem, page]); const renameMenuItemClickHandler = useCallback(() => { setRenameInputShown(true); }, []); const onPressEnterForRenameHandler = async(inputText: string) => { const parentPath = pathUtils.addTrailingSlash(nodePath.dirname(page.path ?? '')); const newPagePath = nodePath.resolve(parentPath, inputText); if (newPagePath === page.path) { setRenameInputShown(false); return; } try { setRenameInputShown(false); await apiv3Put('/pages/rename', { pageId: page._id, revisionId: page.revision, newPagePath, }); if (onRenamed != null) { onRenamed(page.path, newPagePath); } toastSuccess(t('renamed_pages', { path: page.path })); } catch (err) { setRenameInputShown(true); toastError(err); } }; const deleteMenuItemClickHandler = useCallback(async(_pageId: string, pageInfo: IPageInfoAll | undefined): Promise => { if (onClickDeleteMenuItem == null) { return; } if (page._id == null || page.path == null) { throw Error('_id and path must not be null.'); } const pageToDelete: IPageToDeleteWithMeta = { data: { _id: page._id, revision: page.revision as string, path: page.path, }, meta: pageInfo, }; onClickDeleteMenuItem(pageToDelete); }, [onClickDeleteMenuItem, page]); const pathRecoveryMenuItemClickHandler = async(pageId: string): Promise => { try { await resumeRenameOperation(pageId); toastSuccess(t('page_operation.paths_recovered')); } catch { toastError(t('page_operation.path_recovery_failed')); } }; const hasChildren = page.descendantCount ? page.descendantCount > 0 : false; return ( <> {isRenameInputShown ? (
{ setRenameInputShown(false) }} onPressEnter={onPressEnterForRenameHandler} validationTarget={ValidationTarget.PAGE} />
) : ( )}
{/* pass the color property to reactstrap dropdownToggle props. https://6-4-0--reactstrap.netlify.app/components/dropdowns/ */} more_vert
); };