ShareLinkPageView.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { useMemo, memo, type JSX } from 'react';
  2. import { useSlidesByFrontmatter } from '@growi/presentation/dist/services';
  3. import dynamic from 'next/dynamic';
  4. import { PagePathNavTitle } from '~/components/Common/PagePathNavTitle';
  5. import type { RendererConfig } from '~/interfaces/services/renderer';
  6. import type { IShareLinkHasId } from '~/interfaces/share-link';
  7. import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
  8. import { generateSSRViewOptions } from '~/services/renderer/renderer';
  9. import { useCurrentPageData, usePageNotFound } from '~/states/page';
  10. import { useViewOptions } from '~/stores/renderer';
  11. import loggerFactory from '~/utils/logger';
  12. import { PageContentFooter } from '../PageView/PageContentFooter';
  13. import { PageViewLayout } from '../PageView/PageViewLayout';
  14. import RevisionRenderer from '../PageView/RevisionRenderer';
  15. import ShareLinkAlert from './ShareLinkAlert';
  16. const logger = loggerFactory('growi:components:ShareLinkPageView');
  17. const PageSideContents = dynamic(() => import('~/client/components/PageSideContents').then(mod => mod.PageSideContents), { ssr: false });
  18. const ForbiddenPage = dynamic(() => import('~/client/components/ForbiddenPage'), { ssr: false });
  19. const SlideRenderer = dynamic(() => import('~/client/components/Page/SlideRenderer').then(mod => mod.SlideRenderer), { ssr: false });
  20. type Props = {
  21. pagePath: string,
  22. rendererConfig: RendererConfig,
  23. shareLink?: IShareLinkHasId,
  24. isExpired?: boolean,
  25. disableLinkSharing: boolean,
  26. }
  27. export const ShareLinkPageView = memo((props: Props): JSX.Element => {
  28. const {
  29. pagePath, rendererConfig,
  30. shareLink,
  31. isExpired, disableLinkSharing,
  32. } = props;
  33. const [isNotFoundMeta] = usePageNotFound();
  34. const [page] = useCurrentPageData();
  35. const { data: viewOptions } = useViewOptions();
  36. const shouldExpandContent = useShouldExpandContent(page);
  37. const markdown = page?.revision?.body;
  38. const isSlide = useSlidesByFrontmatter(markdown, rendererConfig.isEnabledMarp);
  39. const isNotFound = isNotFoundMeta || page == null || shareLink == null;
  40. const specialContents = useMemo(() => {
  41. if (disableLinkSharing) {
  42. return <ForbiddenPage isLinkSharingDisabled={props.disableLinkSharing} />;
  43. }
  44. }, [disableLinkSharing, props.disableLinkSharing]);
  45. const headerContents = <PagePathNavTitle pageId={page?._id} pagePath={pagePath} isWipPage={page?.wip} />;
  46. const sideContents = !isNotFound
  47. ? (
  48. <PageSideContents page={page} />
  49. )
  50. : null;
  51. const footerContents = !isNotFound
  52. ? (
  53. <PageContentFooter page={page} />
  54. )
  55. : null;
  56. const Contents = () => {
  57. if (isNotFound || page.revision == null) {
  58. return <></>;
  59. }
  60. if (isExpired) {
  61. return (
  62. <>
  63. <h2 className="text-muted mt-4">
  64. <span className="material-symbols-outlined" aria-hidden="true">block</span>
  65. <span> Page is expired</span>
  66. </h2>
  67. </>
  68. );
  69. }
  70. const rendererOptions = viewOptions ?? generateSSRViewOptions(rendererConfig, pagePath);
  71. const markdown = page.revision.body;
  72. return isSlide != null
  73. ? <SlideRenderer marp={isSlide.marp} markdown={markdown} />
  74. : <RevisionRenderer rendererOptions={rendererOptions} markdown={markdown} />;
  75. };
  76. return (
  77. <PageViewLayout
  78. headerContents={headerContents}
  79. sideContents={sideContents}
  80. expandContentWidth={shouldExpandContent}
  81. footerContents={footerContents}
  82. >
  83. { specialContents }
  84. { specialContents == null && (
  85. <>
  86. { isNotFound && (
  87. <h2 className="text-muted mt-4">
  88. <span className="material-symbols-outlined" aria-hidden="true">block</span>
  89. <span> Page is not found</span>
  90. </h2>
  91. ) }
  92. { !isNotFound && (
  93. <>
  94. <ShareLinkAlert expiredAt={shareLink.expiredAt} createdAt={shareLink.createdAt} />
  95. <div className="mb-5">
  96. <Contents />
  97. </div>
  98. </>
  99. ) }
  100. </>
  101. ) }
  102. </PageViewLayout>
  103. );
  104. });
  105. ShareLinkPageView.displayName = 'ShareLinkPageView';