Просмотр исходного кода

omit container from PageEditorByHackmd

yuken 3 лет назад
Родитель
Сommit
61d7be7576

+ 3 - 0
packages/app/src/client/util/editor.ts

@@ -5,6 +5,7 @@ type OptionsToSave = {
   pageTags: string[] | null;
   grantUserGroupId?: string | null;
   grantUserGroupName?: string | null;
+  isSyncRevisionToHackmd?: boolean;
 };
 
 export const getOptionsToSave = (
@@ -14,6 +15,7 @@ export const getOptionsToSave = (
     grantUserGroupId: string | null | undefined,
     grantUserGroupName: string | null | undefined,
     pageTags: string[],
+    isSyncRevisionToHackmd?: boolean,
 ): OptionsToSave => {
   return {
     pageTags,
@@ -22,5 +24,6 @@ export const getOptionsToSave = (
     grant,
     grantUserGroupId,
     grantUserGroupName,
+    isSyncRevisionToHackmd,
   };
 };

+ 90 - 88
packages/app/src/components/PageEditorByHackmd.tsx

@@ -1,38 +1,32 @@
 import React, {
-  useCallback, useEffect, useRef, useState,
+  useCallback, useRef, useState,
 } from 'react';
 
 import { useTranslation } from 'react-i18next';
 
-
-import AppContainer from '~/client/services/AppContainer';
-import PageContainer from '~/client/services/PageContainer';
+import { toastError, toastSuccess } from '~/client/util/apiNotification';
 import { apiPost } from '~/client/util/apiv1-client';
 import { getOptionsToSave } from '~/client/util/editor';
 import { IResHackmdIntegrated, IResHackmdDiscard } from '~/interfaces/hackmd';
-import { useCurrentPagePath, useCurrentPageId, useHackmdUri } from '~/stores/context';
+import {
+  useCurrentPagePath, useCurrentPageId, useHackmdUri, usePageIdOnHackmd, useHasDraftOnHackmd, useRevisionIdHackmdSynced,
+} from '~/stores/context';
 import { useSWRxSlackChannels, useIsSlackEnabled, usePageTagsForEditors } from '~/stores/editor';
+import { useSWRxCurrentPage } from '~/stores/page';
 import {
   useEditorMode, useSelectedGrant,
 } from '~/stores/ui';
 import loggerFactory from '~/utils/logger';
 
 import HackmdEditor from './PageEditorByHackmd/HackmdEditor';
-import { withUnstatedContainers } from './UnstatedUtils';
 
 const logger = loggerFactory('growi:PageEditorByHackmd');
 
-type PageEditorByHackmdProps = {
-  appContainer: AppContainer,
-  pageContainer: PageContainer,
-};
-
 type HackEditorRef = {
   getValue: () => string
 };
 
-const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
-  const { appContainer, pageContainer } = props; // wip
+export const PageEditorByHackmd = (): JSX.Element => {
 
   const { t } = useTranslation();
   const { data: editorMode } = useEditorMode();
@@ -44,6 +38,10 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
   const { data: grant } = useSelectedGrant();
   const { data: hackmdUri } = useHackmdUri();
 
+  // pageData
+  const { data: pageData, mutate: updatePageData } = useSWRxCurrentPage();
+  const revision = pageData?.revision;
+
   const slackChannels = slackChannelsData?.toString();
 
   const [isInitialized, setIsInitialized] = useState(false);
@@ -53,33 +51,37 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
   const [errorMessage, setErrorMessage] = useState('');
   const [errorReason, setErrorReason] = useState('');
 
+  // state from pageContainer
+  const { data: pageIdOnHackmd, mutate: updatePageIdOnHackmd } = usePageIdOnHackmd();
+  const { data: hasDraftOnHackmd, mutate: updateHasDraftOnHackmd } = useHasDraftOnHackmd();
+  const { data: revisionIdHackmdSynced, mutate: updateRevisionIdHackmdSynced } = useRevisionIdHackmdSynced();
+  const [isHackmdDraftUpdatingInRealtime, setIsHackmdDraftUpdatingInRealtime] = useState(false);
+  const [remoteRevisionId, setRemoteRevisionId] = useState(revision?._id); // initialize
+
   const hackmdEditorRef = useRef<HackEditorRef>(null);
 
-  useEffect(() => {
-    const pageEditorByHackmdInstance = {
-      getMarkdown: () => {
-        if (!isInitialized) {
-          return Promise.reject(new Error(t('hackmd.not_initialized')));
-        }
+  // useEffect(() => {
+  //   const pageEditorByHackmdInstance = {
+  //     getMarkdown: () => {
+  //       if (!isInitialized) {
+  //         return Promise.reject(new Error(t('hackmd.not_initialized')));
+  //       }
 
-        if (hackmdEditorRef.current == null) { return }
+  //       if (hackmdEditorRef.current == null) { return }
 
-        return hackmdEditorRef.current.getValue();
-      },
-      reset: () => {
-        setIsInitialized(false);
-      },
-    };
-    appContainer.registerComponentInstance('PageEditorByHackmd', pageEditorByHackmdInstance);
-  }, [appContainer, isInitialized, t]);
+  //       return hackmdEditorRef.current.getValue();
+  //     },
+  //     reset: () => {
+  //       setIsInitialized(false);
+  //     },
+  //   };
+  //   appContainer.registerComponentInstance('PageEditorByHackmd', pageEditorByHackmdInstance);
+  // }, [appContainer, isInitialized, t]);
 
   const isResume = useCallback(() => {
-    const {
-      pageIdOnHackmd, hasDraftOnHackmd, isHackmdDraftUpdatingInRealtime,
-    } = pageContainer.state;
     const isPageExistsOnHackmd = (pageIdOnHackmd != null);
     return (isPageExistsOnHackmd && hasDraftOnHackmd) || isHackmdDraftUpdatingInRealtime;
-  }, [pageContainer.state]);
+  }, [hasDraftOnHackmd, isHackmdDraftUpdatingInRealtime, pageIdOnHackmd]);
 
   const startToEdit = useCallback(async() => {
 
@@ -98,13 +100,11 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
         throw new Error(res.error);
       }
 
-      await pageContainer.setState({
-        pageIdOnHackmd: res.pageIdOnHackmd,
-        revisionIdHackmdSynced: res.revisionIdHackmdSynced,
-      });
+      updatePageIdOnHackmd(res.pageIdOnHackmd);
+      updateRevisionIdHackmdSynced(res.revisionIdHackmdSynced);
     }
     catch (err) {
-      pageContainer.showErrorToastr(err);
+      toastError(err);
 
       setHasError(true);
       setErrorMessage('GROWI server failed to connect to HackMD.');
@@ -113,7 +113,7 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
 
     setIsInitialized(true);
     setIsInitializing(false);
-  }, [pageContainer, pageId, hackmdUri]);
+  }, [pageId, hackmdUri, updatePageIdOnHackmd, updateRevisionIdHackmdSynced]);
 
   /**
    * Start to edit w/o any api request
@@ -123,7 +123,8 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
   }, []);
 
   const discardChanges = useCallback(async() => {
-    const { pageId } = pageContainer.state;
+
+    if (pageId == null) { return }
 
     try {
       const res = await apiPost<IResHackmdDiscard>('/hackmd.discard', { pageId });
@@ -132,87 +133,96 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
         throw new Error(res.error);
       }
 
-      pageContainer.setState({
-        isHackmdDraftUpdatingInRealtime: false,
-        hasDraftOnHackmd: false,
-        pageIdOnHackmd: res.pageIdOnHackmd,
-        remoteRevisionId: res.revisionIdHackmdSynced,
-        revisionIdHackmdSynced: res.revisionIdHackmdSynced,
-      });
+      setIsHackmdDraftUpdatingInRealtime(false);
+      updateHasDraftOnHackmd(false);
+      updatePageIdOnHackmd(res.pageIdOnHackmd);
+      setRemoteRevisionId(res.revisionIdHackmdSynced);
+      updateRevisionIdHackmdSynced(res.revisionIdHackmdSynced);
+
+
     }
     catch (err) {
       logger.error(err);
-      pageContainer.showErrorToastr(err);
+      toastError(err);
     }
-  }, [pageContainer]);
+  }, [setIsHackmdDraftUpdatingInRealtime, updateHasDraftOnHackmd, updatePageIdOnHackmd, updateRevisionIdHackmdSynced, pageId]);
 
   /**
    * save and update state of containers
    * @param {string} markdown
    */
   const onSaveWithShortcut = useCallback(async(markdown) => {
-    if (isSlackEnabled == null || grant == null || slackChannels == null) { return }
-    const optionsToSave = getOptionsToSave(isSlackEnabled, slackChannels, grant.grant, grant.grantedGroup?.id, grant.grantedGroup?.name, pageTags ?? []);
+    if (isSlackEnabled == null || grant == null || slackChannels == null || pageId == null || revisionIdHackmdSynced == null) { return }
+    const optionsToSave = getOptionsToSave(
+      isSlackEnabled, slackChannels, grant.grant, grant.grantedGroup?.id, grant.grantedGroup?.name, pageTags ?? [], true,
+    );
 
     try {
-      // disable unsaved warning
-      // editorContainer.disableUnsavedWarning(); commentout because disableUnsavedWarning doesn't exitst
 
-      // eslint-disable-next-line no-unused-vars
-      const { page, tags } = await pageContainer.save(markdown, editorMode, optionsToSave);
-      logger.debug('success to save');
+      const params = Object.assign(optionsToSave, {
+        page_id: pageId,
+        revision_id: revisionIdHackmdSynced,
+        body: markdown,
+      });
+
+      const res = await apiPost<any>('/pages.update', params);
+
+      // update pageData
+      updatePageData();
+
+      // set updated data
+      setRemoteRevisionId(res.revision._id);
+      updateRevisionIdHackmdSynced(res.page.revisionHackmdSynced);
+      updateHasDraftOnHackmd(res.page.hasDraftOnHackmd);
+      updatePageTagsForEditors(res.tags);
+
+      // call reset
+      setIsInitialized(false);
 
-      pageContainer.showSuccessToastr();
+      logger.debug('success to save');
 
-      updatePageTagsForEditors(tags);
+      toastSuccess('Saved successfully');
     }
     catch (error) {
       logger.error('failed to save', error);
-      pageContainer.showErrorToastr(error);
+      toastError(error);
     }
-  }, [editorMode, grant, isSlackEnabled, pageContainer, pageTags, slackChannels, updatePageTagsForEditors]);
+  }, [
+    grant, isSlackEnabled, pageTags, slackChannels, updatePageTagsForEditors, pageId,
+    revisionIdHackmdSynced, updatePageData, updateHasDraftOnHackmd, updateRevisionIdHackmdSynced,
+  ]);
 
   /**
    * onChange event of HackmdEditor handler
    */
   const hackmdEditorChangeHandler = useCallback(async(body) => {
 
-    if (hackmdUri == null) {
+    if (hackmdUri == null || pageId == null) {
       // do nothing
       return;
     }
 
-    // do nothing if contents are same
-    if (pageContainer.state.markdown === body) {
+    if (revision?.body === body) {
       return;
     }
 
-    // enable unsaved warning
-    // editorContainer.enableUnsavedWarning(); commentout because enableUnsavedWarning doesn't exitst
-
-    const params = {
-      pageId: pageContainer.state.pageId,
-    };
     try {
-      await apiPost('/hackmd.saveOnHackmd', params);
+      await apiPost('/hackmd.saveOnHackmd', { pageId });
     }
     catch (err) {
       logger.error(err);
     }
-  }, [pageContainer.state.markdown, pageContainer.state.pageId, hackmdUri]);
+  }, [pageId, revision?.body, hackmdUri]);
 
   const penpalErrorOccuredHandler = useCallback((error) => {
-    pageContainer.showErrorToastr(error);
+    toastError(error);
 
     setHasError(true);
     setErrorMessage(t('hackmd.fail_to_connect'));
     setErrorReason(error.toString());
-  }, [pageContainer, t]);
+  }, [t]);
 
   const renderPreInitContent = useCallback(() => {
-    const {
-      revisionId, revisionIdHackmdSynced, remoteRevisionId, pageId,
-    } = pageContainer.state;
     const isPageNotFound = pageId == null;
 
     let content;
@@ -309,7 +319,7 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
      * Start to edit
      */
     else {
-      const isRevisionOutdated = revisionId !== remoteRevisionId;
+      const isRevisionOutdated = revision?._id !== remoteRevisionId;
 
       content = (
         <div>
@@ -335,16 +345,12 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
         {content}
       </div>
     );
-  }, [discardChanges, isInitializing, isResume, pageContainer.state, resumeToEdit, startToEdit, t, hackmdUri]);
+  }, [discardChanges, isInitializing, isResume, resumeToEdit, startToEdit, t, hackmdUri, pageId, remoteRevisionId, revisionIdHackmdSynced, revision?._id]);
 
-  if (editorMode == null) {
-    return null;
+  if (editorMode == null || revision == null) {
+    return <></>;
   }
 
-  const {
-    markdown, pageIdOnHackmd,
-  } = pageContainer.state;
-
   let content;
 
   // TODO: typescriptize
@@ -357,7 +363,7 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
         ref={hackmdEditorRef}
         hackmdUri={hackmdUri}
         pageIdOnHackmd={pageIdOnHackmd}
-        initializationMarkdown={isResume() ? null : markdown}
+        initializationMarkdown={isResume() ? null : revision.body}
         onChange={hackmdEditorChangeHandler}
         onSaveWithShortcut={(document) => {
           onSaveWithShortcut(document);
@@ -395,7 +401,3 @@ const PageEditorByHackmd = (props: PageEditorByHackmdProps) => {
   );
 
 };
-
-const PageEditorByHackmdWrapper = withUnstatedContainers(PageEditorByHackmd, [AppContainer, PageContainer]);
-
-export default PageEditorByHackmdWrapper;