Yuki Takei 4 лет назад
Родитель
Сommit
79590dc62d

+ 22 - 4
packages/app/src/components/CustomNavigation/CustomTabContent.jsx → packages/app/src/components/CustomNavigation/CustomTabContent.tsx

@@ -1,22 +1,40 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
 import PropTypes from 'prop-types';
 import {
   TabContent, TabPane,
 } from 'reactstrap';
 
-const CustomTabContent = (props) => {
+import { ICustomNavTabMappings } from '~/interfaces/ui';
+
+
+type Props = {
+  activeTab: string,
+  navTabMapping: ICustomNavTabMappings,
+  additionalClassNames?: string[],
+
+}
+
+const CustomTabContent = (props: Props): JSX.Element => {
 
   const { activeTab, navTabMapping, additionalClassNames } = props;
 
+  const [activatedContent, setActivatedContent] = useState<Set<string>>(new Set<string>());
+
+  // add activated content to Set
+  useEffect(() => {
+    setActivatedContent(activatedContent.add(activeTab));
+  }, [activatedContent, activeTab]);
+
   return (
-    <TabContent activeTab={activeTab} className={additionalClassNames.join(' ')}>
+    <TabContent activeTab={activeTab} className={additionalClassNames != null ? additionalClassNames.join(' ') : ''}>
       {Object.entries(navTabMapping).map(([key, value]) => {
 
+        const shouldRender = key === activeTab || activatedContent.has(key);
         const { Content } = value;
 
         return (
           <TabPane key={key} tabId={key}>
-            <Content />
+            { shouldRender && <Content /> }
           </TabPane>
         );
       })}

+ 15 - 22
packages/app/src/components/PageAccessoriesModal.tsx

@@ -1,7 +1,7 @@
 import React, { useMemo, useState } from 'react';
 
 import {
-  Modal, ModalBody, ModalHeader, TabContent, TabPane,
+  Modal, ModalBody, ModalHeader,
 } from 'reactstrap';
 
 import { useTranslation } from 'react-i18next';
@@ -19,6 +19,7 @@ import PageHistory from './PageHistory';
 import ShareLink from './ShareLink/ShareLink';
 import { CustomNavTab } from './CustomNavigation/CustomNav';
 import ExpandOrContractButton from './ExpandOrContractButton';
+import CustomTabContent from './CustomNavigation/CustomTabContent';
 
 
 type Props = {
@@ -35,29 +36,38 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
 
   const { t } = useTranslation();
 
-  const [activeTab, setActiveTab] = useState(PageAccessoriesModalContents.PageHistory);
+  const [activeTab, setActiveTab] = useState<PageAccessoriesModalContents>(PageAccessoriesModalContents.PageHistory);
   const [isWindowExpanded, setIsWindowExpanded] = useState(false);
 
   const { data: isSharedUser } = useIsSharedUser();
   const { data: isGuestUser } = useIsGuestUser();
 
-  const { data: status, open, close } = usePageAccessoriesModal();
+  // const { data: status, close } = usePageAccessoriesModal({
+  //   isOpened: false,
+  //   onOpened: (activatedContents) => {
+  //     setActiveTab(activatedContents);
+  //   },
+  // });
+  const { data: status, close } = usePageAccessoriesModal();
 
   const navTabMapping = useMemo(() => {
     return {
       [PageAccessoriesModalContents.PageHistory]: {
         Icon: HistoryIcon,
+        Content: () => <PageHistory />,
         i18n: t('History'),
         index: 0,
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
       },
       [PageAccessoriesModalContents.Attachment]: {
         Icon: AttachmentIcon,
+        Content: () => <PageAttachment />,
         i18n: t('attachment_data'),
         index: 1,
       },
       [PageAccessoriesModalContents.ShareLink]: {
         Icon: ShareLinkIcon,
+        Content: () => <ShareLink />,
         i18n: t('share_links.share_link_management'),
         index: 2,
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
@@ -82,7 +92,7 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
     return <></>;
   }
 
-  const { isOpened, activatedContents } = status;
+  const { isOpened } = status;
 
   return (
     <Modal
@@ -98,29 +108,12 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
           breakpointToHideInactiveTabsDown="md"
           onNavSelected={(v) => {
             setActiveTab(v);
-            open(v);
           }}
           hideBorderBottom
         />
       </ModalHeader>
       <ModalBody className="overflow-auto grw-modal-body-style">
-        {/* Do not use CustomTabContent because of performance problem:
-            the 'navTabMapping[tabId].Content' for PageAccessoriesModal depends on activatedContents */}
-        <TabContent activeTab={activeTab}>
-          {!isGuestUser && (
-            <TabPane tabId={PageAccessoriesModalContents.PageHistory}>
-              {activatedContents.has(PageAccessoriesModalContents.PageHistory) && <PageHistory /> }
-            </TabPane>
-          )}
-          <TabPane tabId={PageAccessoriesModalContents.Attachment}>
-            {activatedContents.has(PageAccessoriesModalContents.Attachment) && <PageAttachment />}
-          </TabPane>
-          {!isGuestUser && (
-            <TabPane tabId={PageAccessoriesModalContents.ShareLink}>
-              {activatedContents.has(PageAccessoriesModalContents.ShareLink) && <ShareLink />}
-            </TabPane>
-          )}
-        </TabContent>
+        <CustomTabContent activeTab={activeTab} navTabMapping={navTabMapping} />
       </ModalBody>
     </Modal>
   );

+ 11 - 0
packages/app/src/interfaces/ui.ts

@@ -6,3 +6,14 @@ export const SidebarContentsType = {
 } as const;
 export const AllSidebarContentsType = Object.values(SidebarContentsType);
 export type SidebarContentsType = typeof SidebarContentsType[keyof typeof SidebarContentsType];
+
+
+export type ICustomTabContent = {
+  Content: () => JSX.Element,
+  i18n: string,
+  Icon?: () => JSX.Element,
+  index?: number,
+  isLinkEnabled?: boolean | ((content: ICustomTabContent) => boolean),
+};
+
+export type ICustomNavTabMappings = { [key: string]: ICustomTabContent };

+ 12 - 14
packages/app/src/stores/ui.tsx

@@ -457,40 +457,38 @@ export type PageAccessoriesModalContents = typeof PageAccessoriesModalContents[k
 
 type PageAccessoriesModalStatus = {
   isOpened: boolean,
-  activatedContents: Set<PageAccessoriesModalContents>,
+  // onOpened?: (initialActivatedContents: PageAccessoriesModalContents) => void,
 }
 
 type PageAccessoriesModalUtils = {
-  open(activatedContent: PageAccessoriesModalContents): Promise<PageAccessoriesModalStatus> | void
-  close(): Promise<PageAccessoriesModalStatus> | void
+  open(activatedContents: PageAccessoriesModalContents): void
+  close(): void
 }
 
 export const usePageAccessoriesModal = (
     status?: PageAccessoriesModalStatus,
 ): SWRResponse<PageAccessoriesModalStatus, Error> & PageAccessoriesModalUtils => {
 
-  const initialData: PageAccessoriesModalStatus = { isOpened: false, activatedContents: new Set<PageAccessoriesModalContents>() };
-  const swrResponse = useStaticSWR<PageAccessoriesModalStatus, Error>('pageAccessoriesModalStatus', status, { fallbackData: initialData });
+  const initialStatus = { isOpened: false };
+  const swrResponse = useStaticSWR<PageAccessoriesModalStatus, Error>('pageAccessoriesModalStatus', status, { fallbackData: initialStatus });
 
   return {
     ...swrResponse,
-    open: (activatedContent: PageAccessoriesModalContents) => {
+    open: (activatedContents: PageAccessoriesModalContents) => {
       if (swrResponse.data == null) {
         return;
       }
-      swrResponse.mutate({
-        isOpened: true,
-        activatedContents: swrResponse.data.activatedContents.add(activatedContent),
-      });
+      swrResponse.mutate({ isOpened: true });
+
+      // if (swrResponse.data.onOpened != null) {
+      //   swrResponse.data.onOpened(activatedContents);
+      // }
     },
     close: () => {
       if (swrResponse.data == null) {
         return;
       }
-      swrResponse.mutate({
-        isOpened: false,
-        activatedContents: swrResponse.data.activatedContents,
-      });
+      swrResponse.mutate({ isOpened: false });
     },
   };
 };