import React, { useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { DropdownItem } from 'reactstrap';
import { withUnstatedContainers } from '../UnstatedUtils';
import EditorContainer from '~/client/services/EditorContainer';
import {
EditorMode, useDrawerMode, useEditorMode, useIsDeviceSmallerThanMd, useIsAbleToShowPageManagement, useIsAbleToShowTagLabel,
useIsAbleToShowPageEditorModeManager, useIsAbleToShowPageAuthors,
} from '~/stores/ui';
import {
usePageAccessoriesModal, PageAccessoriesModalContents,
usePageDuplicateModal, usePageRenameModal, usePageDeleteModal, OnDeletedFunction, usePagePresentationModal,
} from '~/stores/modal';
import { useSWRxPageChildren } from '~/stores/page-listing';
import {
useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath,
useCreator, useRevisionAuthor, useCurrentUser, useIsGuestUser, useIsSharedUser, useShareLinkId,
} from '~/stores/context';
import { useSWRTagsInfo } from '~/stores/page';
import { toastSuccess, toastError } from '~/client/util/apiNotification';
import { apiPost } from '~/client/util/apiv1-client';
import { IPageHasId } from '~/interfaces/page';
import HistoryIcon from '../Icons/HistoryIcon';
import AttachmentIcon from '../Icons/AttachmentIcon';
import ShareLinkIcon from '../Icons/ShareLinkIcon';
import { AdditionalMenuItemsRendererProps } from '../Common/Dropdown/PageItemControl';
import { SubNavButtons } from './SubNavButtons';
import PageEditorModeManager from './PageEditorModeManager';
import { GrowiSubNavigation } from './GrowiSubNavigation';
import PresentationIcon from '../Icons/PresentationIcon';
import CreateTemplateModal from '../CreateTemplateModal';
import { exportAsMarkdown } from '~/client/services/page-operation';
type AdditionalMenuItemsProps = AdditionalMenuItemsRendererProps & {
pageId: string,
revisionId: string,
isLinkSharingDisabled?: boolean,
onClickTemplateMenuItem: (isPageTemplateModalShown: boolean) => void,
}
const AdditionalMenuItems = (props: AdditionalMenuItemsProps): JSX.Element => {
const { t } = useTranslation();
const {
pageId, revisionId, isLinkSharingDisabled, onClickTemplateMenuItem,
} = props;
const openPageTemplateModalHandler = () => {
onClickTemplateMenuItem(true);
};
const { data: isGuestUser } = useIsGuestUser();
const { data: isSharedUser } = useIsSharedUser();
const { open: openPresentationModal } = usePagePresentationModal();
const { open: openAccessoriesModal } = usePageAccessoriesModal();
const hrefForPresentationModal = '?presentation=1';
return (
<>
{/* Presentation */}
openPresentationModal(hrefForPresentationModal)}>
{ t('Presentation Mode') }
{/* Export markdown */}
exportAsMarkdown(pageId, revisionId, 'md')}>
{t('export_bulk.export_page_markdown')}
{/*
TODO: show Tooltip when menu is disabled
refs: PageAccessoriesModalControl
*/}
openAccessoriesModal(PageAccessoriesModalContents.PageHistory)}
disabled={isGuestUser || isSharedUser}
>
{t('History')}
openAccessoriesModal(PageAccessoriesModalContents.Attachment)}
>
{t('attachment_data')}
openAccessoriesModal(PageAccessoriesModalContents.ShareLink)}
disabled={isGuestUser || isSharedUser || isLinkSharingDisabled}
>
{t('share_links.share_link_management')}
{/* Create template */}
{ t('template.option_label.create/edit') }
>
);
};
const GrowiContextualSubNavigation = (props) => {
const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
const { data: isDrawerMode } = useDrawerMode();
const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
const { data: createdAt } = useCurrentCreatedAt();
const { data: updatedAt } = useCurrentUpdatedAt();
const { data: pageId } = useCurrentPageId();
const { data: revisionId } = useRevisionId();
const { data: path } = useCurrentPagePath();
const { data: creator } = useCreator();
const { data: revisionAuthor } = useRevisionAuthor();
const { data: currentUser } = useCurrentUser();
const { data: isGuestUser } = useIsGuestUser();
const { data: isSharedUser } = useIsSharedUser();
const { data: shareLinkId } = useShareLinkId();
const { data: isAbleToShowPageManagement } = useIsAbleToShowPageManagement();
const { data: isAbleToShowTagLabel } = useIsAbleToShowTagLabel();
const { data: isAbleToShowPageEditorModeManager } = useIsAbleToShowPageEditorModeManager();
const { data: isAbleToShowPageAuthors } = useIsAbleToShowPageAuthors();
const { mutate: mutateChildren } = useSWRxPageChildren(path);
const { mutate: mutateSWRTagsInfo, data: tagsInfoData } = useSWRTagsInfo(pageId);
const { open: openDuplicateModal } = usePageDuplicateModal();
const { open: openRenameModal } = usePageRenameModal();
const { open: openDeleteModal } = usePageDeleteModal();
const [isPageTemplateModalShown, setIsPageTempleteModalShown] = useState(false);
const {
editorContainer, isCompactMode, isLinkSharingDisabled,
} = props;
const isViewMode = editorMode === EditorMode.View;
const tagsUpdatedHandler = useCallback(async(newTags: string[]) => {
// It will not be reflected in the DB until the page is refreshed
if (editorMode === EditorMode.Editor) {
return editorContainer.setState({ tags: newTags });
}
try {
const { tags } = await apiPost('/tags.update', { pageId, revisionId, tags: newTags }) as { tags };
// revalidate SWRTagsInfo
mutateSWRTagsInfo();
// update editorContainer.state
editorContainer.setState({ tags });
toastSuccess('updated tags successfully');
}
catch (err) {
toastError(err, 'fail to update tags');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageId]);
const duplicateItemClickedHandler = useCallback(async(pageId, path) => {
openDuplicateModal(pageId, path);
}, [openDuplicateModal]);
const renameItemClickedHandler = useCallback(async(pageId, revisionId, path) => {
openRenameModal(pageId, revisionId, path);
}, [openRenameModal]);
const onDeletedHandler: OnDeletedFunction = useCallback((pathOrPathsToDelete, isRecursively, isCompletely) => {
if (typeof pathOrPathsToDelete !== 'string') {
return;
}
mutateChildren();
const path = pathOrPathsToDelete;
if (isCompletely) {
// redirect to NotFound Page
window.location.href = path;
}
else {
window.location.reload();
}
}, [mutateChildren]);
const deleteItemClickedHandler = useCallback(async(pageToDelete, isAbleToDeleteCompletely) => {
openDeleteModal([pageToDelete], onDeletedHandler, isAbleToDeleteCompletely);
}, [onDeletedHandler, openDeleteModal]);
const templateMenuItemClickHandler = useCallback(() => {
setIsPageTempleteModalShown(true);
}, []);
const ControlComponents = useCallback(() => {
function onPageEditorModeButtonClicked(viewType) {
mutateEditorMode(viewType);
}
const className = `d-flex flex-column align-items-end justify-content-center ${isViewMode ? ' h-50' : ''}`;
return (
<>
{ pageId != null && isViewMode && (
(
)}
onClickDuplicateMenuItem={duplicateItemClickedHandler}
onClickRenameMenuItem={renameItemClickedHandler}
onClickDeleteMenuItem={deleteItemClickedHandler}
/>
) }
{isAbleToShowPageEditorModeManager && (
)}
{currentUser != null && (
setIsPageTempleteModalShown(false)}
/>
)}
>
);
}, [
pageId, revisionId, shareLinkId, editorMode, mutateEditorMode, isCompactMode,
isLinkSharingDisabled, isDeviceSmallerThanMd, isGuestUser, isSharedUser, currentUser,
isViewMode, isAbleToShowPageEditorModeManager, isAbleToShowPageManagement,
duplicateItemClickedHandler, renameItemClickedHandler, deleteItemClickedHandler,
path, templateMenuItemClickHandler, isPageTemplateModalShown,
]);
if (path == null) {
return <>>;
}
const currentPage: Partial = {
_id: pageId ?? undefined,
path,
revision: revisionId ?? undefined,
creator: creator ?? undefined,
lastUpdateUser: revisionAuthor,
createdAt: createdAt ?? undefined,
updatedAt: updatedAt ?? undefined,
};
return (
);
};
/**
* Wrapper component for using unstated
*/
const GrowiContextualSubNavigationWrapper = withUnstatedContainers(GrowiContextualSubNavigation, [EditorContainer]);
GrowiContextualSubNavigation.propTypes = {
editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
isCompactMode: PropTypes.bool,
isLinkSharingDisabled: PropTypes.bool,
};
export default GrowiContextualSubNavigationWrapper;