Taichi Masuyama 3 سال پیش
والد
کامیت
560668b21d

+ 43 - 30
packages/app/src/components/Me/EditorSettings.tsx

@@ -1,12 +1,13 @@
 import React, {
-  Dispatch,
+  Dispatch, memo,
   FC, SetStateAction, useCallback, useEffect, useState,
+  useMemo,
 } from 'react';
 
 import { useTranslation } from 'next-i18next';
 
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
-import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
+import { useEditorSettings } from '~/stores/editor';
 
 
 type EditorSettingsBodyProps = Record<string, never>;
@@ -194,51 +195,62 @@ const RuleListGroup: FC<RuleListGroupProps> = ({
   );
 };
 
+const createRulesFromDefaultList = (rule: { name: string }) => (
+  {
+    name: rule.name,
+    isEnabled: true,
+  }
+);
+
 
-export const EditorSettings: FC<EditorSettingsBodyProps> = () => {
+export const EditorSettings = memo((): JSX.Element => {
   const { t } = useTranslation();
   const [textlintRules, setTextlintRules] = useState<LintRule[]>([]);
 
-  const initializeEditorSettings = useCallback(async() => {
-    const { data } = await apiv3Get('/personal-setting/editor-settings');
-    const retrievedRules: LintRule[] = data?.textlintSettings?.textlintRules;
+  const { data: dataEditorSettings, update: updateEditorSettings } = useEditorSettings();
 
-    // If database is empty, add default rules to state
-    if (retrievedRules != null && retrievedRules.length > 0) {
-      setTextlintRules(retrievedRules);
-    }
-    else {
-      const createRulesFromDefaultList = (rule: { name: string }) => (
-        {
-          name: rule.name,
-          isEnabled: true,
-        }
-      );
+  const defaultRules = useMemo(() => {
+    const defaultCommonRules = commonRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
+    const defaultJapaneseRules = japaneseRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
+
+    return [...defaultCommonRules, ...defaultJapaneseRules];
+  }, []);
 
-      const defaultCommonRules = commonRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
-      const defaultJapaneseRules = japaneseRulesMenuItems.map(rule => createRulesFromDefaultList(rule));
-      setTextlintRules([...defaultCommonRules, ...defaultJapaneseRules]);
+  const initializeEditorSettings = useCallback(() => {
+    if (dataEditorSettings == null) {
+      return;
     }
 
-  }, []);
+    const retrievedRules: LintRule[] | undefined = dataEditorSettings?.textlintSettings?.textlintRules;
 
-  useEffect(() => {
-    initializeEditorSettings();
-  }, [initializeEditorSettings]);
+    // If database is empty, add default rules to state
+    if (retrievedRules != null && retrievedRules.length > 0) {
+      setTextlintRules(retrievedRules);
+      return;
+    }
+    setTextlintRules(defaultRules);
+  }, [dataEditorSettings, defaultRules]);
 
-  const updateRulesHandler = async() => {
+  const updateRulesHandler = useCallback(async() => {
     try {
-      const { data } = await apiv3Put('/personal-setting/editor-settings', { textlintSettings: { textlintRules: [...textlintRules] } });
-      setTextlintRules(data.textlintSettings.textlintRules);
+      await updateEditorSettings({ textlintSettings: { textlintRules } });
       toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
     }
     catch (err) {
       toastError(err);
     }
-  };
+  }, [t, textlintRules, updateEditorSettings]);
+
+  useEffect(() => {
+    initializeEditorSettings();
+  }, [initializeEditorSettings]);
 
   if (textlintRules == null) {
-    return <></>;
+    return (
+      <div className="text-muted text-center">
+        <i className="fa fa-2x fa-spinner fa-pulse"></i>
+      </div>
+    );
   }
 
   return (
@@ -270,4 +282,5 @@ export const EditorSettings: FC<EditorSettingsBodyProps> = () => {
       </div>
     </div>
   );
-};
+});
+EditorSettings.displayName = 'EditorSettings';

+ 1 - 1
packages/app/src/interfaces/editor-settings.ts

@@ -5,7 +5,7 @@ export interface ILintRule {
 }
 
 export interface ITextlintSettings {
-  neverAskBeforeDownloadLargeFiles: boolean;
+  neverAskBeforeDownloadLargeFiles?: boolean;
   textlintRules: ILintRule[];
 }
 

+ 7 - 6
packages/app/src/stores/editor.tsx

@@ -10,16 +10,17 @@ import { SlackChannels } from '~/interfaces/user-trigger-notification';
 import {
   useCurrentUser, useDefaultIndentSize, useIsGuestUser,
 } from './context';
-import { localStorageMiddleware } from './middlewares/sync-to-storage';
+// import { localStorageMiddleware } from './middlewares/sync-to-storage';
 import { useSWRxTagsInfo } from './page';
 import { useStaticSWR } from './use-static-swr';
 
 
 type EditorSettingsOperation = {
-  update: (updateData: Partial<IEditorSettings>) => void,
+  update: (updateData: Partial<IEditorSettings>) => Promise<void>,
   turnOffAskingBeforeDownloadLargeFiles: () => void,
 }
 
+// TODO: Enable localStorageMiddleware
 export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperation, IEditorSettings, Error> => {
   const { data: currentUser } = useCurrentUser();
   const { data: isGuestUser } = useIsGuestUser();
@@ -28,13 +29,13 @@ export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperatio
     isGuestUser ? null : ['/personal-setting/editor-settings', currentUser?.username],
     endpoint => apiv3Get(endpoint).then(result => result.data),
     {
-      use: [localStorageMiddleware], // store to localStorage for initialization fastly
-      fallbackData: undefined,
+      // use: [localStorageMiddleware], // store to localStorage for initialization fastly
+      // fallbackData: undefined,
     },
   );
 
   return withUtils<EditorSettingsOperation, IEditorSettings, Error>(swrResult, {
-    update: (updateData) => {
+    update: async(updateData) => {
       const { data, mutate } = swrResult;
 
       if (data == null) {
@@ -44,7 +45,7 @@ export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperatio
       mutate({ ...data, ...updateData }, false);
 
       // invoke API
-      apiv3Put('/personal-setting/editor-settings', updateData);
+      await apiv3Put('/personal-setting/editor-settings', updateData);
     },
     turnOffAskingBeforeDownloadLargeFiles: async() => {
       const { data, mutate } = swrResult;

+ 4 - 8
packages/app/src/stores/middlewares/sync-to-storage.ts

@@ -33,14 +33,10 @@ export const createSyncToStorageMiddlware = (
         initData = storageSerializer.deserialize(itemInStorage);
       }
 
-      const swrNext = useSWRNext(key, fetcher, {
-        ...config,
-        fallbackData: initData,
-      });
+      config.fallbackData = initData;
+      const swrNext = useSWRNext(key, fetcher, config);
 
-      return {
-        ...swrNext,
-        // override mutate
+      return Object.assign(swrNext, {
         mutate: (data, shouldRevalidate) => {
           return swrNext.mutate(data, shouldRevalidate)
             .then((value) => {
@@ -48,7 +44,7 @@ export const createSyncToStorageMiddlware = (
               return value;
             });
         },
-      };
+      });
     };
   };
 };