ShareLinkPageView.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import React, { useMemo } from 'react';
  2. import type { IPagePopulatedToShowRevision } from '@growi/core';
  3. import dynamic from 'next/dynamic';
  4. import Sticky from 'react-stickynode';
  5. import type { RendererConfig } from '~/interfaces/services/renderer';
  6. import type { IShareLinkHasId } from '~/interfaces/share-link';
  7. import { generateSSRViewOptions } from '~/services/renderer/renderer';
  8. import { useIsNotFound } from '~/stores/page';
  9. import { useViewOptions } from '~/stores/renderer';
  10. import loggerFactory from '~/utils/logger';
  11. import { PagePathNav } from './Common/PagePathNav';
  12. import { PageViewLayout } from './Layout/PageViewLayout';
  13. import RevisionRenderer from './Page/RevisionRenderer';
  14. import ShareLinkAlert from './Page/ShareLinkAlert';
  15. import { PagePathNav } from './PagePathNav';
  16. import type { PageSideContentsProps } from './PageSideContents';
  17. const logger = loggerFactory('growi:Page');
  18. const PageSideContents = dynamic<PageSideContentsProps>(() => import('./PageSideContents').then(mod => mod.PageSideContents), { ssr: false });
  19. const ForbiddenPage = dynamic(() => import('./ForbiddenPage'), { ssr: false });
  20. type Props = {
  21. pagePath: string,
  22. rendererConfig: RendererConfig,
  23. page?: IPagePopulatedToShowRevision,
  24. shareLink?: IShareLinkHasId,
  25. isExpired: boolean,
  26. disableLinkSharing: boolean,
  27. }
  28. export const ShareLinkPageView = (props: Props): JSX.Element => {
  29. const {
  30. pagePath, rendererConfig,
  31. page, shareLink,
  32. isExpired, disableLinkSharing,
  33. } = props;
  34. const { data: isNotFoundMeta } = useIsNotFound();
  35. const { data: viewOptions } = useViewOptions();
  36. const isNotFound = isNotFoundMeta || page == null || shareLink == null;
  37. const specialContents = useMemo(() => {
  38. if (disableLinkSharing) {
  39. return <ForbiddenPage isLinkSharingDisabled={props.disableLinkSharing} />;
  40. }
  41. }, [disableLinkSharing, props.disableLinkSharing]);
  42. const headerContents = (
  43. <Sticky>
  44. {({ status }: { status: boolean }) => {
  45. const isCollapseParents = status === Sticky.STATUS_FIXED;
  46. return <PagePathNav pageId={page?._id} pagePath={pagePath} isCollapseParents={isCollapseParents} />;
  47. }}
  48. </Sticky>
  49. );
  50. const sideContents = !isNotFound
  51. ? (
  52. <PageSideContents page={page} />
  53. )
  54. : null;
  55. const Contents = () => {
  56. if (isNotFound) {
  57. return <></>;
  58. }
  59. if (isExpired) {
  60. return (
  61. <>
  62. <h2 className="text-muted mt-4">
  63. <i className="icon-ban" aria-hidden="true" />
  64. <span> Page is expired</span>
  65. </h2>
  66. </>
  67. );
  68. }
  69. const rendererOptions = viewOptions ?? generateSSRViewOptions(rendererConfig, pagePath);
  70. const markdown = page.revision.body;
  71. return (
  72. <>
  73. <RevisionRenderer rendererOptions={rendererOptions} markdown={markdown} />
  74. </>
  75. );
  76. };
  77. return (
  78. <PageViewLayout
  79. headerContents={headerContents}
  80. sideContents={sideContents}
  81. >
  82. { specialContents }
  83. { specialContents == null && (
  84. <>
  85. { isNotFound && (
  86. <h2 className="text-muted mt-4">
  87. <i className="icon-ban" aria-hidden="true" />
  88. <span> Page is not found</span>
  89. </h2>
  90. ) }
  91. { !isNotFound && (
  92. <>
  93. <PagePathNav pageId={page?._id} pagePath={pagePath} />
  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. };