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

Refactor project-wide settings:

- Change api function argument (readability)
- create a new wrapper hooks for saving the project to both server-side and angular scope
- Implement the new save project settings hooks on project-wide settings update
- On spell check language update function, add new comment to give more context about the decision

GitOrigin-RevId: 93d558d1e1d4db265a943eeb4366842430900c43
M Fahru 3 лет назад
Родитель
Сommit
7475237170

+ 10 - 23
services/web/frontend/js/features/editor-left-menu/hooks/use-project-wide-settings.tsx

@@ -1,40 +1,27 @@
 import { useCallback } from 'react'
-import { useProjectContext } from '../../../shared/context/project-context'
 import useScopeValue from '../../../shared/hooks/use-scope-value'
-import { type ProjectSettings, saveProjectSettings } from '../utils/api'
+import type { ProjectSettings } from '../utils/api'
 import useRootDocId from './use-root-doc-id'
+import useSaveProjectSettings from './use-save-project-settings'
 import useSetSpellCheckLanguage from './use-set-spell-check-language'
 
 export default function useProjectWideSettings() {
   // The value will be undefined on mount
-  const [project, setProject] = useScopeValue<ProjectSettings | undefined>(
-    'project',
-    true
-  )
-  const { _id: projectId } = useProjectContext()
+  const [project] = useScopeValue<ProjectSettings | undefined>('project', true)
+  const saveProjectSettings = useSaveProjectSettings()
 
   const setCompiler = useCallback(
-    (compiler: ProjectSettings['compiler']) => {
-      const allowUpdate = project?.compiler
-
-      if (allowUpdate) {
-        setProject({ ...project, compiler })
-        saveProjectSettings({ projectId, compiler })
-      }
+    (newCompiler: ProjectSettings['compiler']) => {
+      saveProjectSettings('compiler', newCompiler)
     },
-    [projectId, project, setProject]
+    [saveProjectSettings]
   )
 
   const setImageName = useCallback(
-    (imageName: ProjectSettings['imageName']) => {
-      const allowUpdate = project?.imageName
-
-      if (allowUpdate) {
-        setProject({ ...project, imageName })
-        saveProjectSettings({ projectId, imageName })
-      }
+    (newImageName: ProjectSettings['imageName']) => {
+      saveProjectSettings('imageName', newImageName)
     },
-    [projectId, project, setProject]
+    [saveProjectSettings]
   )
 
   const { setRootDocId, rootDocId } = useRootDocId()

+ 8 - 10
services/web/frontend/js/features/editor-left-menu/hooks/use-root-doc-id.tsx

@@ -1,32 +1,30 @@
 import { useCallback } from 'react'
 import { useEditorContext } from '../../../shared/context/editor-context'
-import { useProjectContext } from '../../../shared/context/project-context'
 import useScopeValue from '../../../shared/hooks/use-scope-value'
-import { type ProjectSettings, saveProjectSettings } from '../utils/api'
+import type { ProjectSettings } from '../utils/api'
+import useSaveProjectSettings from './use-save-project-settings'
 
 export default function useRootDocId() {
-  const [rootDocId, setRootDocId] =
+  const [rootDocId] =
     useScopeValue<ProjectSettings['rootDocId']>('project.rootDoc_id')
   const { permissionsLevel } = useEditorContext()
-  const { _id: projectId } = useProjectContext()
+  const saveProjectSettings = useSaveProjectSettings()
 
   const setRootDocIdFunc = useCallback(
     async (newRootDocId: ProjectSettings['rootDocId']) => {
+      // rootDoc_id will be undefined on angular scope on initialisation
       const allowUpdate =
-        typeof rootDocId !== 'undefined' &&
-        permissionsLevel !== 'readOnly' &&
-        rootDocId !== newRootDocId
+        typeof rootDocId !== 'undefined' && permissionsLevel !== 'readOnly'
 
       if (allowUpdate) {
         try {
-          await saveProjectSettings({ projectId, rootDocId: newRootDocId })
-          setRootDocId(newRootDocId)
+          await saveProjectSettings('rootDocId', newRootDocId)
         } catch (err) {
           // TODO: retry mechanism (max 10x before failed completely and rollback the old value)
         }
       }
     },
-    [permissionsLevel, projectId, rootDocId, setRootDocId]
+    [permissionsLevel, rootDocId, saveProjectSettings]
   )
 
   return {

+ 28 - 0
services/web/frontend/js/features/editor-left-menu/hooks/use-save-project-settings.tsx

@@ -0,0 +1,28 @@
+import { type ProjectSettings, saveProjectSettings } from '../utils/api'
+import { useProjectContext } from '../../../shared/context/project-context'
+import useScopeValue from '../../../shared/hooks/use-scope-value'
+
+export default function useSaveProjectSettings() {
+  // projectSettings value will be undefined on mount
+  const [projectSettings, setProjectSettings] = useScopeValue<
+    ProjectSettings | undefined
+  >('project', true)
+  const { _id: projectId } = useProjectContext()
+
+  return async (
+    key: keyof ProjectSettings,
+    newSetting: ProjectSettings[keyof ProjectSettings]
+  ) => {
+    if (projectSettings) {
+      const currentSetting = projectSettings[key]
+
+      if (currentSetting !== newSetting) {
+        await saveProjectSettings(projectId, {
+          [key]: newSetting,
+        })
+
+        setProjectSettings({ ...projectSettings, [key]: newSetting })
+      }
+    }
+  }
+}

+ 10 - 13
services/web/frontend/js/features/editor-left-menu/hooks/use-set-spell-check-language.tsx

@@ -1,17 +1,13 @@
 import { useCallback } from 'react'
-import { useProjectContext } from '../../../shared/context/project-context'
 import useScopeValue from '../../../shared/hooks/use-scope-value'
-import {
-  type ProjectSettings,
-  saveProjectSettings,
-  saveUserSettings,
-} from '../utils/api'
+import { type ProjectSettings, saveUserSettings } from '../utils/api'
+import useSaveProjectSettings from './use-save-project-settings'
 
 export default function useSetSpellCheckLanguage() {
   const [spellCheckLanguage, setSpellCheckLanguage] = useScopeValue<
     ProjectSettings['spellCheckLanguage']
   >('project.spellCheckLanguage')
-  const { _id: projectId } = useProjectContext()
+  const saveProjectSettings = useSaveProjectSettings()
 
   return useCallback(
     (newSpellCheckLanguage: ProjectSettings['spellCheckLanguage']) => {
@@ -21,14 +17,15 @@ export default function useSetSpellCheckLanguage() {
       if (allowUpdate) {
         setSpellCheckLanguage(newSpellCheckLanguage)
 
-        // save to both project setting and user setting
-        saveProjectSettings({
-          projectId,
-          spellCheckLanguage: newSpellCheckLanguage,
-        })
+        // Save project settings is created from hooks because it will save the value on
+        // both server-side and client-side (angular scope)
+        saveProjectSettings('spellCheckLanguage', newSpellCheckLanguage)
+
+        // For user settings, we only need to save it on server-side,
+        // so we import the function directly without hooks
         saveUserSettings('spellCheckLanguage', newSpellCheckLanguage)
       }
     },
-    [projectId, setSpellCheckLanguage, spellCheckLanguage]
+    [setSpellCheckLanguage, spellCheckLanguage, saveProjectSettings]
   )
 }

+ 4 - 8
services/web/frontend/js/features/editor-left-menu/utils/api.ts

@@ -53,14 +53,10 @@ export function saveUserSettings(
   })
 }
 
-type SaveProjectSettings = {
-  projectId: string
-} & Partial<ProjectSettings>
-
-export const saveProjectSettings = async ({
-  projectId,
-  ...data
-}: SaveProjectSettings) => {
+export const saveProjectSettings = async (
+  projectId: string,
+  data: Partial<ProjectSettings>
+) => {
   await postJSON<never>(`/project/${projectId}/settings`, {
     body: {
       ...data,