From 7475237170cc88e38f7952e65bae2d663413cac8 Mon Sep 17 00:00:00 2001 From: M Fahru Date: Fri, 6 Jan 2023 18:45:37 -0700 Subject: [PATCH] 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 --- .../hooks/use-project-wide-settings.tsx | 33 ++++++------------- .../hooks/use-root-doc-id.tsx | 18 +++++----- .../hooks/use-save-project-settings.tsx | 28 ++++++++++++++++ .../hooks/use-set-spell-check-language.tsx | 23 ++++++------- .../js/features/editor-left-menu/utils/api.ts | 12 +++---- 5 files changed, 60 insertions(+), 54 deletions(-) create mode 100644 services/web/frontend/js/features/editor-left-menu/hooks/use-save-project-settings.tsx diff --git a/services/web/frontend/js/features/editor-left-menu/hooks/use-project-wide-settings.tsx b/services/web/frontend/js/features/editor-left-menu/hooks/use-project-wide-settings.tsx index b78f1bd6b5..9dc63523c7 100644 --- a/services/web/frontend/js/features/editor-left-menu/hooks/use-project-wide-settings.tsx +++ b/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( - 'project', - true - ) - const { _id: projectId } = useProjectContext() + const [project] = useScopeValue('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() diff --git a/services/web/frontend/js/features/editor-left-menu/hooks/use-root-doc-id.tsx b/services/web/frontend/js/features/editor-left-menu/hooks/use-root-doc-id.tsx index 58b6014276..31a5e7e4a2 100644 --- a/services/web/frontend/js/features/editor-left-menu/hooks/use-root-doc-id.tsx +++ b/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('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 { diff --git a/services/web/frontend/js/features/editor-left-menu/hooks/use-save-project-settings.tsx b/services/web/frontend/js/features/editor-left-menu/hooks/use-save-project-settings.tsx new file mode 100644 index 0000000000..6af0a180c9 --- /dev/null +++ b/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 }) + } + } + } +} diff --git a/services/web/frontend/js/features/editor-left-menu/hooks/use-set-spell-check-language.tsx b/services/web/frontend/js/features/editor-left-menu/hooks/use-set-spell-check-language.tsx index 409da6fdea..4e9f2119a8 100644 --- a/services/web/frontend/js/features/editor-left-menu/hooks/use-set-spell-check-language.tsx +++ b/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] ) } diff --git a/services/web/frontend/js/features/editor-left-menu/utils/api.ts b/services/web/frontend/js/features/editor-left-menu/utils/api.ts index a74d76203d..dfce0d8620 100644 --- a/services/web/frontend/js/features/editor-left-menu/utils/api.ts +++ b/services/web/frontend/js/features/editor-left-menu/utils/api.ts @@ -53,14 +53,10 @@ export function saveUserSettings( }) } -type SaveProjectSettings = { - projectId: string -} & Partial - -export const saveProjectSettings = async ({ - projectId, - ...data -}: SaveProjectSettings) => { +export const saveProjectSettings = async ( + projectId: string, + data: Partial +) => { await postJSON(`/project/${projectId}/settings`, { body: { ...data,