Преглед изворни кода

WIP: refactor DisplaySwitcher

Yuki Takei пре 3 година
родитељ
комит
0ae015194f

+ 10 - 4
packages/app/src/components/Comments.tsx

@@ -1,15 +1,19 @@
 import React from 'react';
 
-import { IRevisionHasId } from '@growi/core';
+import { type IRevisionHasId, pagePathUtils } from '@growi/core';
 import dynamic from 'next/dynamic';
 
-import { PageCommentProps } from '~/components/PageComment';
+import type { PageCommentProps } from '~/components/PageComment';
 import { useSWRxPageComment } from '~/stores/comment';
 import { useIsTrashPage } from '~/stores/page';
 
 import { useCurrentUser } from '../stores/context';
 
-import { CommentEditorProps } from './PageComment/CommentEditor';
+import type { CommentEditorProps } from './PageComment/CommentEditor';
+
+
+const { isTopPage } = pagePathUtils;
+
 
 const PageComment = dynamic<PageCommentProps>(() => import('~/components/PageComment').then(mod => mod.PageComment), { ssr: false });
 const CommentEditor = dynamic<CommentEditorProps>(() => import('./PageComment/CommentEditor').then(mod => mod.CommentEditor), { ssr: false });
@@ -28,7 +32,9 @@ export const Comments = (props: CommentsProps): JSX.Element => {
   const { data: isDeleted } = useIsTrashPage();
   const { data: currentUser } = useCurrentUser();
 
-  if (pageId == null) {
+  const isTopPagePath = isTopPage(pagePath);
+
+  if (pageId == null || isTopPagePath) {
     return <></>;
   }
 

+ 102 - 29
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -1,5 +1,6 @@
 import React, { useMemo } from 'react';
 
+import { type IPagePopulatedToShowRevision, pagePathUtils } from '@growi/core';
 import dynamic from 'next/dynamic';
 
 
@@ -10,15 +11,90 @@ import { useIsEditable } from '~/stores/context';
 import { EditorMode, useEditorMode } from '~/stores/ui';
 
 import CustomTabContent from '../CustomNavigation/CustomTabContent';
+import { MainPane } from '../Layout/MainPane';
 import { Page } from '../Page';
+import { PageAlerts } from '../PageAlert/PageAlerts';
+import { PageContentFooter } from '../PageContentFooter';
+import type { PageSideContentsProps } from '../PageSideContents';
+import type { UsersHomePageFooterProps } from '../UsersHomePageFooter';
 
+const { isUsersHomePage } = pagePathUtils;
+
+
+const NotCreatablePage = dynamic(() => import('../NotCreatablePage').then(mod => mod.NotCreatablePage), { ssr: false });
+const ForbiddenPage = dynamic(() => import('../ForbiddenPage'), { ssr: false });
+const PageSideContents = dynamic<PageSideContentsProps>(() => import('../PageSideContents').then(mod => mod.PageSideContents), { ssr: false });
+const Comments = dynamic(() => import('../Comments').then(mod => mod.Comments), { ssr: false });
+const UsersHomePageFooter = dynamic<UsersHomePageFooterProps>(() => import('../UsersHomePageFooter')
+  .then(mod => mod.UsersHomePageFooter), { ssr: false });
 
 const PageEditor = dynamic(() => import('../PageEditor'), { ssr: false });
 const PageEditorByHackmd = dynamic(() => import('../PageEditorByHackmd').then(mod => mod.PageEditorByHackmd), { ssr: false });
 const EditorNavbarBottom = dynamic(() => import('../PageEditor/EditorNavbarBottom'), { ssr: false });
 
 
-const DisplaySwitcher = React.memo((): JSX.Element => {
+const IdenticalPathPage = (): JSX.Element => {
+  const IdenticalPathPage = dynamic(() => import('../IdenticalPathPage').then(mod => mod.IdenticalPathPage), { ssr: false });
+  return <IdenticalPathPage />;
+};
+
+
+type Props = {
+  page?: IPagePopulatedToShowRevision,
+  isIdenticalPathPage?: boolean,
+  isNotFound?: boolean,
+  isForbidden?: boolean,
+  isNotCreatable?: boolean,
+}
+
+const View = (props: Props): JSX.Element => {
+  const {
+    page,
+    isIdenticalPathPage, isNotFound, isForbidden, isNotCreatable,
+  } = props;
+
+  const pageId = page?._id;
+  const pagePath = page?.path;
+
+  const sideContents = !isNotFound && !isNotCreatable
+    ? (
+      <PageSideContents page={page} />
+    )
+    : <></>;
+
+  const footerContents = !isIdenticalPathPage && !isNotFound && page != null
+    ? (
+      <>
+        { pageId != null && pagePath != null && (
+          <Comments pageId={pageId} pagePath={pagePath} revision={page.revision} />
+        ) }
+        { pagePath != null && isUsersHomePage(pagePath) && (
+          <UsersHomePageFooter creatorId={page.creator._id}/>
+        ) }
+        <PageContentFooter page={page} />
+      </>
+    )
+    : <></>;
+
+  return (
+    <MainPane
+      sideContents={sideContents}
+      footerContents={footerContents}
+    >
+      <PageAlerts />
+      { props.isIdenticalPathPage && <IdenticalPathPage />}
+      { !props.isIdenticalPathPage && (
+        <>
+          { isForbidden && <ForbiddenPage /> }
+          { isNotCreatable && <NotCreatablePage />}
+          { !isForbidden && !props.isNotCreatable && <Page /> }
+        </>
+      ) }
+    </MainPane>
+  );
+};
+
+export const DisplaySwitcher = (props: Props): JSX.Element => {
 
   const { data: editorMode = EditorMode.View } = useEditorMode();
   const { data: isEditable } = useIsEditable();
@@ -29,39 +105,39 @@ const DisplaySwitcher = React.memo((): JSX.Element => {
 
   const isViewMode = editorMode === EditorMode.View;
 
+  const view = useMemo(() => <View {...props} />, [props]);
+  const editor = useMemo(() => {
+    return isEditable
+      ? (
+        <div data-testid="page-editor" id="page-editor">
+          <PageEditor />
+        </div>
+      )
+      : <></>;
+  }, [isEditable]);
+  const hackmd = useMemo(() => {
+    return isEditable
+      ? (
+        <div id="page-editor-with-hackmd">
+          <PageEditorByHackmd />
+        </div>
+      )
+      : <></>;
+  }, [isEditable]);
+
   const navTabMapping = useMemo(() => {
     return {
       [EditorMode.View]: {
-        Content: () => (
-          <div data-testid="page-view" id="page-view">
-            <Page />
-          </div>
-        ),
+        Content: () => view,
       },
       [EditorMode.Editor]: {
-        Content: () => (
-          isEditable
-            ? (
-              <div data-testid="page-editor" id="page-editor">
-                <PageEditor />
-              </div>
-            )
-            : <></>
-        ),
+        Content: () => editor,
       },
       [EditorMode.HackMD]: {
-        Content: () => (
-          isEditable
-            ? (
-              <div id="page-editor-with-hackmd">
-                <PageEditorByHackmd />
-              </div>
-            )
-            : <></>
-        ),
+        Content: () => hackmd,
       },
     };
-  }, [isEditable]);
+  }, [editor, hackmd, view]);
 
 
   return (
@@ -71,7 +147,4 @@ const DisplaySwitcher = React.memo((): JSX.Element => {
       { isEditable && !isViewMode && <EditorNavbarBottom /> }
     </>
   );
-});
-DisplaySwitcher.displayName = 'DisplaySwitcher';
-
-export default DisplaySwitcher;
+};

+ 10 - 48
packages/app/src/pages/[[...path]].page.tsx

@@ -20,11 +20,9 @@ import { useRouter } from 'next/router';
 import superjson from 'superjson';
 
 import { useCurrentGrowiLayoutFluidClassName } from '~/client/services/layout';
-import { Comments } from '~/components/Comments';
 import { MainPane } from '~/components/Layout/MainPane';
 import { PageAlerts } from '~/components/PageAlert/PageAlerts';
 // import { useTranslation } from '~/i18n';
-import { PageContentFooter } from '~/components/PageContentFooter';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
 import { UsersHomePageFooterProps } from '~/components/UsersHomePageFooter';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
@@ -58,7 +56,7 @@ import loggerFactory from '~/utils/logger';
 import { DescendantsPageListModal } from '../components/DescendantsPageListModal';
 import { BasicLayoutWithEditorMode } from '../components/Layout/BasicLayout';
 import GrowiContextualSubNavigationSubstance from '../components/Navbar/GrowiContextualSubNavigation';
-import DisplaySwitcher from '../components/Page/DisplaySwitcher';
+import { DisplaySwitcher } from '../components/Page/DisplaySwitcher';
 // import { serializeUserSecurely } from '../server/models/serializers/user-serializer';
 // import PageStatusAlert from '../client/js/components/PageStatusAlert';
 import type { PageSideContentsProps } from '../components/PageSideContents';
@@ -87,14 +85,9 @@ declare global {
 }
 
 
-const NotCreatablePage = dynamic(() => import('../components/NotCreatablePage').then(mod => mod.NotCreatablePage), { ssr: false });
-const ForbiddenPage = dynamic(() => import('../components/ForbiddenPage'), { ssr: false });
 const UnsavedAlertDialog = dynamic(() => import('../components/UnsavedAlertDialog'), { ssr: false });
-const PageSideContents = dynamic<PageSideContentsProps>(() => import('../components/PageSideContents').then(mod => mod.PageSideContents), { ssr: false });
 const GrowiSubNavigationSwitcher = dynamic(() => import('../components/Navbar/GrowiSubNavigationSwitcher')
   .then(mod => mod.GrowiSubNavigationSwitcher), { ssr: false });
-const UsersHomePageFooter = dynamic<UsersHomePageFooterProps>(() => import('../components/UsersHomePageFooter')
-  .then(mod => mod.UsersHomePageFooter), { ssr: false });
 const DrawioModal = dynamic(() => import('../components/PageEditor/DrawioModal').then(mod => mod.DrawioModal), { ssr: false });
 const HandsontableModal = dynamic(() => import('../components/PageEditor/HandsontableModal').then(mod => mod.HandsontableModal), { ssr: false });
 const PageStatusAlert = dynamic(() => import('../components/PageStatusAlert').then(mod => mod.PageStatusAlert), { ssr: false });
@@ -148,11 +141,6 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
   );
 };
 
-const IdenticalPathPage = (): JSX.Element => {
-  const IdenticalPathPage = dynamic(() => import('../components/IdenticalPathPage').then(mod => mod.IdenticalPathPage), { ssr: false });
-  return <IdenticalPathPage />;
-};
-
 const PutbackPageModal = (): JSX.Element => {
   const PutbackPageModal = dynamic(() => import('../components/PutbackPageModal'), { ssr: false });
   return <PutbackPageModal />;
@@ -319,26 +307,6 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {
   const title = generateCustomTitleForPage(props, pagePath ?? '');
 
 
-  const sideContents = !props.isNotFound && !props.isNotCreatable
-    ? (
-      <PageSideContents page={pageWithMeta?.data} />
-    )
-    : <></>;
-
-  const footerContents = !props.isIdenticalPathPage && !props.isNotFound && pageWithMeta != null
-    ? (
-      <>
-        { pagePath != null && !isTopPagePath && (
-          <Comments pageId={pageId} pagePath={pagePath} revision={pageWithMeta.data.revision} />
-        ) }
-        { isUsersHomePage(pageWithMeta.data.path) && (
-          <UsersHomePageFooter creatorId={pageWithMeta.data.creator._id}/>
-        ) }
-        <PageContentFooter page={pageWithMeta.data} />
-      </>
-    )
-    : <></>;
-
   return (
     <>
       <Head>
@@ -357,21 +325,15 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {
         <div id="grw-subnav-sticky-trigger" className="sticky-top"></div>
         <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
 
-        <MainPane
-          sideContents={sideContents}
-          footerContents={footerContents}
-        >
-          <PageAlerts />
-          { props.isIdenticalPathPage && <IdenticalPathPage />}
-          { !props.isIdenticalPathPage && (
-            <>
-              { props.isForbidden && <ForbiddenPage /> }
-              { props.isNotCreatable && <NotCreatablePage />}
-              { !props.isForbidden && !props.isNotCreatable && <DisplaySwitcher />}
-            </>
-          ) }
-          <PageStatusAlert />
-        </MainPane>
+        <DisplaySwitcher
+          page={pageWithMeta?.data}
+          isIdenticalPathPage={props.isIdenticalPathPage}
+          isNotFound={props.isNotFound}
+          isForbidden={props.isForbidden}
+          isNotCreatable={props.isNotCreatable}
+        />
+
+        <PageStatusAlert />
 
         {shouldRenderPutbackPageModal && <PutbackPageModal />}
       </div>