| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import { type JSX, useCallback } from 'react';
- import { useRouter } from 'next/router';
- import { UserPicture } from '@growi/ui/dist/components';
- import { format } from 'date-fns/format';
- import { useTranslation } from 'react-i18next';
- import {
- useCurrentPageData,
- useCurrentPagePath,
- useFetchCurrentPage,
- useIsTrashPage,
- } from '~/states/page';
- import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
- import { usePutBackPageModalActions } from '~/states/ui/modal/put-back-page';
- import { useIsAbleToShowTrashPageManagementButtons } from '~/states/ui/page-abilities';
- import { useSWRxPageInfo } from '~/stores/page';
- import { mutateRecentlyUpdated } from '~/stores/page-listing';
- const onDeletedHandler = (pathOrPathsToDelete) => {
- if (typeof pathOrPathsToDelete !== 'string') {
- return;
- }
- window.location.href = '/';
- };
- type SubstanceProps = {
- pageId: string;
- pagePath: string;
- revisionId: string;
- };
- const TrashPageAlertSubstance = (props: SubstanceProps): JSX.Element => {
- const { t } = useTranslation();
- const router = useRouter();
- const { pageId, pagePath, revisionId } = props;
- const pageData = useCurrentPageData();
- const isAbleToShowTrashPageManagementButtons =
- useIsAbleToShowTrashPageManagementButtons();
- // useSWRxPageInfo is executed only when Substance is rendered
- const { data: pageInfo } = useSWRxPageInfo(pageId);
- const { open: openDeleteModal } = usePageDeleteModalActions();
- const { open: openPutBackPageModal } = usePutBackPageModalActions();
- const currentPagePath = useCurrentPagePath();
- const { fetchCurrentPage } = useFetchCurrentPage();
- const deleteUser = pageData?.deleteUser;
- const deletedAt = pageData?.deletedAt
- ? format(new Date(pageData.deletedAt), 'yyyy/MM/dd HH:mm')
- : '';
- const openPutbackPageModalHandler = useCallback(() => {
- const putBackedHandler = async () => {
- if (currentPagePath == null) {
- return;
- }
- try {
- // biome-ignore lint/style/noRestrictedImports: no-problem dynamic import
- const unlink = (await import('~/client/services/page-operation'))
- .unlink;
- unlink(currentPagePath);
- router.push(`/${pageId}`);
- fetchCurrentPage();
- mutateRecentlyUpdated();
- } catch (err) {
- // biome-ignore lint/style/noRestrictedImports: no-problem dynamic import
- const toastError = (await import('~/client/util/toastr')).toastError;
- toastError(err);
- }
- };
- openPutBackPageModal(
- { pageId, path: pagePath },
- { onPutBacked: putBackedHandler },
- );
- }, [
- openPutBackPageModal,
- pageId,
- pagePath,
- currentPagePath,
- router,
- fetchCurrentPage,
- ]);
- const openPageDeleteModalHandler = useCallback(() => {
- const pageToDelete = {
- data: {
- _id: pageId,
- revision: revisionId,
- path: pagePath,
- },
- meta: pageInfo,
- };
- openDeleteModal([pageToDelete], { onDeleted: onDeletedHandler });
- }, [openDeleteModal, pageId, pageInfo, pagePath, revisionId]);
- const renderTrashPageManagementButtons = useCallback(() => {
- return (
- <>
- <button
- type="button"
- className="btn btn-info rounded-pill btn-sm ms-auto me-2"
- onClick={openPutbackPageModalHandler}
- data-testid="put-back-button"
- >
- <span className="material-symbols-outlined" aria-hidden="true">
- undo
- </span>{' '}
- {t('Put Back')}
- </button>
- <button
- type="button"
- className="btn btn-danger rounded-pill btn-sm"
- disabled={!(pageInfo?.isAbleToDeleteCompletely ?? false)}
- onClick={openPageDeleteModalHandler}
- >
- <span className="material-symbols-outlined" aria-hidden="true">
- delete_forever
- </span>{' '}
- {t('Delete Completely')}
- </button>
- </>
- );
- }, [
- openPageDeleteModalHandler,
- openPutbackPageModalHandler,
- pageInfo?.isAbleToDeleteCompletely,
- t,
- ]);
- return (
- <div
- className="alert alert-warning py-3 ps-4 d-flex flex-column flex-lg-row"
- data-testid="trash-page-alert"
- >
- <div className="flex-grow-1">
- This page is in the trash{' '}
- <span className="material-symbols-outlined" aria-hidden="true">
- delete
- </span>
- .
- <br />
- <UserPicture user={deleteUser} />
- <span className="ms-2">
- Deleted by {deleteUser?.name} at{' '}
- <span data-vrt-blackout-datetime>
- {deletedAt ?? pageData?.updatedAt}
- </span>
- </span>
- </div>
- <div className="pt-1 d-flex align-items-end align-items-lg-center">
- {isAbleToShowTrashPageManagementButtons &&
- renderTrashPageManagementButtons()}
- </div>
- </div>
- );
- };
- export const TrashPageAlert = (): JSX.Element => {
- const pageData = useCurrentPageData();
- const isTrashPage = useIsTrashPage();
- const pageId = pageData?._id;
- const pagePath = pageData?.path;
- const revisionId = pageData?.revision?._id;
- // Lightweight condition checks in Container
- const isEmptyPage = pageId == null || revisionId == null || pagePath == null;
- // Show this alert only for non-empty pages in trash.
- if (!isTrashPage || isEmptyPage) {
- // biome-ignore lint/complexity/noUselessFragments: ignore
- return <></>;
- }
- // Render Substance only when conditions are met
- // useSWRxPageInfo will be executed only here
- return (
- <TrashPageAlertSubstance
- pageId={pageId}
- pagePath={pagePath}
- revisionId={revisionId}
- />
- );
- };
|