From 5f98b70c6a2d4526e9189efbb9a24bce665d826e Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Tue, 11 Jul 2023 03:53:46 +0200 Subject: [PATCH] Fix/scope hotkeys (#581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP * asd * Fix * Fix lint * Removed console log * asd * Removed isDefined * Fix/debounce company card onchange (#580) * Add internal state and debounce for editable text card * Use debounce for date fields too * Update refetch * Nit * Removed comments * Ménage --------- Co-authored-by: Emilien Chauvet --- front/package.json | 1 + front/src/App.tsx | 50 ++++++++----- front/src/AppInternalHooks.tsx | 6 +- .../command-menu/components/CommandMenu.tsx | 27 ++++--- .../CommentThreadRelationPicker.tsx | 16 ++++- .../right-drawer/RightDrawerTimeline.tsx | 7 -- .../create/RightDrawerCreateCommentThread.tsx | 7 -- .../edit/RightDrawerEditCommentThread.tsx | 7 +- .../components/CompanyAccountOwnerPicker.tsx | 2 +- front/src/modules/hotkeys/constants/index.ts | 12 +++- .../hooks/internal/useHotkeysScopeAutoSync.ts | 29 ++++++++ .../internal/useHotkeysScopeStackAutoSync.ts | 36 ---------- ...useHotkeysScope.ts => useHotkeysScopes.ts} | 2 +- .../hooks/internal/usePreviousHotkeysScope.ts | 39 ++++++++++ .../hooks/useAddToHotkeysScopeStack.ts | 48 ------------- .../hotkeys/hooks/useCurrentHotkeysScope.ts | 16 ----- .../hooks/useHotkeysScopeOnBooleanState.ts | 27 ------- .../hooks/useHotkeysScopeOnMountOnly.ts | 32 --------- .../hooks/useRemoveFromHotkeysScopeStack.ts | 54 -------------- .../useRemoveHighestHotkeysScopeStackItem.ts | 42 ----------- .../hooks/useResetHotkeysScopeStack.ts | 18 ----- .../hotkeys/hooks/useSetHotkeysScope.ts | 59 +++++++++++++++ .../internal/currentHotkeysScopeState.ts | 9 +++ .../internal/customHotkeysScopesState.ts | 16 ----- .../states/internal/hotkeysScopeStackState.ts | 9 --- .../src/modules/hotkeys/types/HotkeysScope.ts | 3 - .../types/internal/CustomHotkeysScope.ts | 4 ++ .../hotkeys/types/internal/HotkeysScope.ts | 6 ++ .../types/internal/HotkeysScopeStackItems.ts | 7 -- .../types/internal/InternalHotkeysScope.ts | 1 + .../types/internal/PageHotkeysScope.ts | 15 ++++ .../people/components/PeopleCompanyPicker.tsx | 8 +-- .../components/NewButton.tsx | 42 ++++++++--- .../components/NewCompanyBoardCard.tsx | 4 +- .../components/SingleEntitySelect.tsx | 13 +++- .../components/SingleEntitySelectBase.tsx | 18 ++++- .../hooks/useEntitySelectScroll.ts | 18 ++++- .../BoardCardEditableFieldDateEditMode.tsx | 4 -- .../components/BoardCardEditableFieldText.tsx | 2 + .../components/BoardCardEditableField.tsx | 4 +- .../BoardCardEditableFieldEditMode.tsx | 21 +++--- .../BoardCardEditableFieldInternal.tsx | 26 ++++--- .../components/editable-cell/EditableCell.tsx | 10 +-- .../editable-cell/EditableCellEditMode.tsx | 2 +- .../EditableCellSoftFocusMode.tsx | 6 +- ...loseEditableCell.ts => useEditableCell.ts} | 19 +++-- .../hooks/useSetSoftFocusOnCurrentCell.ts | 8 +-- .../types/EditableCellDateEditMode.tsx | 2 +- .../types/EditableCellDoubleTextEditMode.tsx | 2 +- .../ui/components/inputs/TextInput.tsx | 34 ++++++++- .../table-header/FilterDropdownButton.tsx | 24 ++++--- .../FilterDropdownFilterSelect.tsx | 9 +++ .../ui/tables/hooks/useLeaveTableFocus.ts | 12 ++-- .../tables/hooks/useMapKeyboardToSoftFocus.ts | 8 +-- front/src/pages/auth/CreateProfile.tsx | 5 -- front/src/pages/auth/CreateWorkspace.tsx | 5 -- front/src/pages/auth/Index.tsx | 5 -- front/src/pages/auth/PasswordLogin.tsx | 5 -- front/src/pages/companies/Companies.tsx | 7 -- front/src/pages/companies/CompanyShow.tsx | 7 -- front/src/pages/people/People.tsx | 7 -- front/src/pages/settings/SettingsProfile.tsx | 7 -- .../sync-hooks/HotkeysScopeAutoSyncHook.tsx | 7 ++ .../HotkeysScopeBrowserRouterSync.tsx | 71 +++++++++++++++++++ .../HotkeysScopeStackAutoSyncHook.tsx | 7 -- .../sync-hooks/hooks/useIsMatchingLocation.ts | 16 +++++ front/src/sync-hooks/types/AppBasePath.ts | 5 ++ front/src/sync-hooks/types/AppPath.ts | 9 +++ front/src/sync-hooks/types/AuthPath.ts | 7 ++ front/src/sync-hooks/types/SettingsPath.ts | 5 ++ front/yarn.lock | 12 +++- 71 files changed, 581 insertions(+), 509 deletions(-) create mode 100644 front/src/modules/hotkeys/hooks/internal/useHotkeysScopeAutoSync.ts delete mode 100644 front/src/modules/hotkeys/hooks/internal/useHotkeysScopeStackAutoSync.ts rename front/src/modules/hotkeys/hooks/internal/{useHotkeysScope.ts => useHotkeysScopes.ts} (98%) create mode 100644 front/src/modules/hotkeys/hooks/internal/usePreviousHotkeysScope.ts delete mode 100644 front/src/modules/hotkeys/hooks/useAddToHotkeysScopeStack.ts delete mode 100644 front/src/modules/hotkeys/hooks/useCurrentHotkeysScope.ts delete mode 100644 front/src/modules/hotkeys/hooks/useHotkeysScopeOnBooleanState.ts delete mode 100644 front/src/modules/hotkeys/hooks/useHotkeysScopeOnMountOnly.ts delete mode 100644 front/src/modules/hotkeys/hooks/useRemoveFromHotkeysScopeStack.ts delete mode 100644 front/src/modules/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem.ts delete mode 100644 front/src/modules/hotkeys/hooks/useResetHotkeysScopeStack.ts create mode 100644 front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts create mode 100644 front/src/modules/hotkeys/states/internal/currentHotkeysScopeState.ts delete mode 100644 front/src/modules/hotkeys/states/internal/customHotkeysScopesState.ts delete mode 100644 front/src/modules/hotkeys/states/internal/hotkeysScopeStackState.ts delete mode 100644 front/src/modules/hotkeys/types/HotkeysScope.ts create mode 100644 front/src/modules/hotkeys/types/internal/CustomHotkeysScope.ts create mode 100644 front/src/modules/hotkeys/types/internal/HotkeysScope.ts delete mode 100644 front/src/modules/hotkeys/types/internal/HotkeysScopeStackItems.ts create mode 100644 front/src/modules/hotkeys/types/internal/PageHotkeysScope.ts rename front/src/modules/ui/components/editable-cell/hooks/{useCloseEditableCell.ts => useEditableCell.ts} (62%) create mode 100644 front/src/sync-hooks/HotkeysScopeAutoSyncHook.tsx create mode 100644 front/src/sync-hooks/HotkeysScopeBrowserRouterSync.tsx delete mode 100644 front/src/sync-hooks/HotkeysScopeStackAutoSyncHook.tsx create mode 100644 front/src/sync-hooks/hooks/useIsMatchingLocation.ts create mode 100644 front/src/sync-hooks/types/AppBasePath.ts create mode 100644 front/src/sync-hooks/types/AppPath.ts create mode 100644 front/src/sync-hooks/types/AuthPath.ts create mode 100644 front/src/sync-hooks/types/SettingsPath.ts diff --git a/front/package.json b/front/package.json index 75a30dd48a..9aedd8b990 100644 --- a/front/package.json +++ b/front/package.json @@ -42,6 +42,7 @@ "recoil": "^0.7.7", "scroll-into-view": "^1.16.2", "ts-key-enum": "^2.0.12", + "url": "^0.11.1", "uuid": "^9.0.0", "web-vitals": "^2.1.4" }, diff --git a/front/src/App.tsx b/front/src/App.tsx index be23b8ac9b..2cce1173bd 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -20,6 +20,9 @@ import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMemb import { CompanyShow } from './pages/companies/CompanyShow'; import { PersonShow } from './pages/people/PersonShow'; import { SettingsWorksapce } from './pages/settings/SettingsWorkspace'; +import { AppPath } from './sync-hooks/types/AppPath'; +import { AuthPath } from './sync-hooks/types/AuthPath'; +import { SettingsPath } from './sync-hooks/types/SettingsPath'; import { AppInternalHooks } from './AppInternalHooks'; /** @@ -33,11 +36,14 @@ function AuthRoutes() { - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } + /> + } /> @@ -52,7 +58,7 @@ export function App() { @@ -66,27 +72,39 @@ export function App() { element={ - } /> - } /> - } /> - } /> } + /> + } /> + } + /> + } /> + } /> - } /> } + /> + - } /> } + /> + } /> } /> diff --git a/front/src/AppInternalHooks.tsx b/front/src/AppInternalHooks.tsx index 5df7c173aa..1c70b13728 100644 --- a/front/src/AppInternalHooks.tsx +++ b/front/src/AppInternalHooks.tsx @@ -1,13 +1,15 @@ import { AnalyticsHook } from './sync-hooks/AnalyticsHook'; import { GotoHotkeysHooks } from './sync-hooks/GotoHotkeysHooks'; -import { HotkeysScopeStackAutoSyncHook } from './sync-hooks/HotkeysScopeStackAutoSyncHook'; +import { HotkeysScopeAutoSyncHook } from './sync-hooks/HotkeysScopeAutoSyncHook'; +import { HotkeysScopeBrowserRouterSync } from './sync-hooks/HotkeysScopeBrowserRouterSync'; export function AppInternalHooks() { return ( <> - + + ); } diff --git a/front/src/modules/command-menu/components/CommandMenu.tsx b/front/src/modules/command-menu/components/CommandMenu.tsx index dcdb1bddde..a7b2c149d1 100644 --- a/front/src/modules/command-menu/components/CommandMenu.tsx +++ b/front/src/modules/command-menu/components/CommandMenu.tsx @@ -1,6 +1,6 @@ import { useRecoilState } from 'recoil'; -import { useHotkeysScopeOnBooleanState } from '@/hotkeys/hooks/useHotkeysScopeOnBooleanState'; +import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; @@ -13,7 +13,6 @@ import { StyledGroup, StyledInput, StyledList, - // StyledSeparator, } from './CommandMenuStyles'; export function CommandMenu() { @@ -22,16 +21,26 @@ export function CommandMenu() { useScopedHotkeys( 'ctrl+k,meta+k', () => { - setOpen((prevOpen) => !prevOpen); + handleOpenChange(!open); }, InternalHotkeysScope.CommandMenu, - [setOpen], + [setOpen, open, handleOpenChange], ); - useHotkeysScopeOnBooleanState( - { scope: InternalHotkeysScope.CommandMenu }, - open, - ); + const { + setHotkeysScopeAndMemorizePreviousScope, + goBackToPreviousHotkeysScope, + } = usePreviousHotkeysScope(); + + function handleOpenChange(newOpenState: boolean) { + if (newOpenState) { + setOpen(true); + setHotkeysScopeAndMemorizePreviousScope(InternalHotkeysScope.CommandMenu); + } else { + setOpen(false); + goBackToPreviousHotkeysScope(); + } + } /* TODO: Allow performing actions on page through CommandBar @@ -73,7 +82,7 @@ export function CommandMenu() { return ( diff --git a/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx b/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx index 4eb6233014..2790f1a828 100644 --- a/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx +++ b/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx @@ -11,6 +11,7 @@ import { import { useHandleCheckableCommentThreadTargetChange } from '@/comments/hooks/useHandleCheckableCommentThreadTargetChange'; import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect'; import { CompanyChip } from '@/companies/components/CompanyChip'; +import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { PersonChip } from '@/people/components/PersonChip'; @@ -120,8 +121,20 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) { searchFilter, }); + const { + setHotkeysScopeAndMemorizePreviousScope, + goBackToPreviousHotkeysScope, + } = usePreviousHotkeysScope(); + function handleRelationContainerClick() { - setIsMenuOpen((isOpen) => !isOpen); + if (isMenuOpen) { + exitEditMode(); + } else { + setIsMenuOpen(true); + setHotkeysScopeAndMemorizePreviousScope( + InternalHotkeysScope.RelationPicker, + ); + } } // TODO: Place in a scoped recoil atom family @@ -134,6 +147,7 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) { }); function exitEditMode() { + goBackToPreviousHotkeysScope(); setIsMenuOpen(false); setSearchFilter(''); } diff --git a/front/src/modules/comments/components/right-drawer/RightDrawerTimeline.tsx b/front/src/modules/comments/components/right-drawer/RightDrawerTimeline.tsx index 52b36be41e..2925cafeaf 100644 --- a/front/src/modules/comments/components/right-drawer/RightDrawerTimeline.tsx +++ b/front/src/modules/comments/components/right-drawer/RightDrawerTimeline.tsx @@ -1,8 +1,6 @@ import { useRecoilState } from 'recoil'; import { commentableEntityArrayState } from '@/comments/states/commentableEntityArrayState'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody'; import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage'; import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar'; @@ -12,11 +10,6 @@ import { Timeline } from '../timeline/Timeline'; export function RightDrawerTimeline() { const [commentableEntityArray] = useRecoilState(commentableEntityArrayState); - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.RightDrawer, - customScopes: { goto: false, 'command-menu': true }, - }); - return ( diff --git a/front/src/modules/comments/components/right-drawer/create/RightDrawerCreateCommentThread.tsx b/front/src/modules/comments/components/right-drawer/create/RightDrawerCreateCommentThread.tsx index e1b418251a..a4daf4ca4a 100644 --- a/front/src/modules/comments/components/right-drawer/create/RightDrawerCreateCommentThread.tsx +++ b/front/src/modules/comments/components/right-drawer/create/RightDrawerCreateCommentThread.tsx @@ -1,8 +1,6 @@ import { useRecoilValue } from 'recoil'; import { viewableCommentThreadIdState } from '@/comments/states/viewableCommentThreadIdState'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody'; import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage'; import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar'; @@ -12,11 +10,6 @@ import { CommentThread } from '../CommentThread'; export function RightDrawerCreateCommentThread() { const commentThreadId = useRecoilValue(viewableCommentThreadIdState); - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.RightDrawer, - customScopes: { goto: false, 'command-menu': true }, - }); - return ( diff --git a/front/src/modules/comments/components/right-drawer/edit/RightDrawerEditCommentThread.tsx b/front/src/modules/comments/components/right-drawer/edit/RightDrawerEditCommentThread.tsx index 4fa175b628..7074853f0b 100644 --- a/front/src/modules/comments/components/right-drawer/edit/RightDrawerEditCommentThread.tsx +++ b/front/src/modules/comments/components/right-drawer/edit/RightDrawerEditCommentThread.tsx @@ -1,8 +1,6 @@ import { useRecoilValue } from 'recoil'; import { viewableCommentThreadIdState } from '@/comments/states/viewableCommentThreadIdState'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody'; import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage'; import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar'; @@ -10,11 +8,8 @@ import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDraw import { CommentThread } from '../CommentThread'; export function RightDrawerEditCommentThread() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.RightDrawer, - customScopes: { goto: false, 'command-menu': true }, - }); const commentThreadId = useRecoilValue(viewableCommentThreadIdState); + return ( diff --git a/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx b/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx index d64d11c707..f4286142a5 100644 --- a/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx +++ b/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx @@ -4,7 +4,7 @@ import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFiltere import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState'; import { EntityForSelect } from '@/relation-picker/types/EntityForSelect'; import { Entity } from '@/relation-picker/types/EntityTypeForSelect'; -import { useEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell'; +import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell'; import { Company, User, diff --git a/front/src/modules/hotkeys/constants/index.ts b/front/src/modules/hotkeys/constants/index.ts index ecf2d20cc7..12484dd42c 100644 --- a/front/src/modules/hotkeys/constants/index.ts +++ b/front/src/modules/hotkeys/constants/index.ts @@ -1,4 +1,5 @@ -import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems'; +import { CustomHotkeysScopes } from '../types/internal/CustomHotkeysScope'; +import { HotkeysScope } from '../types/internal/HotkeysScope'; import { InternalHotkeysScope } from '../types/internal/InternalHotkeysScope'; export const INITIAL_HOTKEYS_SCOPES: string[] = [InternalHotkeysScope.App]; @@ -8,10 +9,15 @@ export const ALWAYS_ON_HOTKEYS_SCOPES: string[] = [ InternalHotkeysScope.App, ]; -export const DEFAULT_HOTKEYS_SCOPE_STACK_ITEM: HotkeysScopeStackItem = { +export const DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES: CustomHotkeysScopes = { + commandMenu: true, + goto: false, +}; + +export const INITIAL_HOTKEYS_SCOPE: HotkeysScope = { scope: InternalHotkeysScope.App, customScopes: { - 'command-menu': true, + commandMenu: true, goto: true, }, }; diff --git a/front/src/modules/hotkeys/hooks/internal/useHotkeysScopeAutoSync.ts b/front/src/modules/hotkeys/hooks/internal/useHotkeysScopeAutoSync.ts new file mode 100644 index 0000000000..575e348845 --- /dev/null +++ b/front/src/modules/hotkeys/hooks/internal/useHotkeysScopeAutoSync.ts @@ -0,0 +1,29 @@ +import { useEffect } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState'; +import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; + +import { useHotkeysScopes } from './useHotkeysScopes'; + +export function useHotkeysScopeAutoSync() { + const { setHotkeysScopes } = useHotkeysScopes(); + + const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState); + + useEffect(() => { + const scopesToSet: string[] = []; + + if (currentHotkeysScope.customScopes?.commandMenu) { + scopesToSet.push(InternalHotkeysScope.CommandMenu); + } + + if (currentHotkeysScope?.customScopes?.goto) { + scopesToSet.push(InternalHotkeysScope.Goto); + } + + scopesToSet.push(currentHotkeysScope.scope); + + setHotkeysScopes(scopesToSet); + }, [setHotkeysScopes, currentHotkeysScope]); +} diff --git a/front/src/modules/hotkeys/hooks/internal/useHotkeysScopeStackAutoSync.ts b/front/src/modules/hotkeys/hooks/internal/useHotkeysScopeStackAutoSync.ts deleted file mode 100644 index b9a1f45a39..0000000000 --- a/front/src/modules/hotkeys/hooks/internal/useHotkeysScopeStackAutoSync.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; - -import { customHotkeysScopesState } from '@/hotkeys/states/internal/customHotkeysScopesState'; -import { hotkeysScopeStackState } from '@/hotkeys/states/internal/hotkeysScopeStackState'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; - -import { useHotkeysScope } from './useHotkeysScope'; - -export function useHotkeysScopeStackAutoSync() { - const { setHotkeysScopes } = useHotkeysScope(); - - const hotkeysScopeStack = useRecoilValue(hotkeysScopeStackState); - const customHotkeysScopes = useRecoilValue(customHotkeysScopesState); - useEffect(() => { - if (hotkeysScopeStack.length === 0) { - return; - } - - const scopesToSet: string[] = []; - - const currentHotkeysScope = hotkeysScopeStack[hotkeysScopeStack.length - 1]; - - if (currentHotkeysScope.customScopes?.['command-menu']) { - scopesToSet.push(InternalHotkeysScope.CommandMenu); - } - - if (currentHotkeysScope?.customScopes?.goto) { - scopesToSet.push(InternalHotkeysScope.Goto); - } - - scopesToSet.push(currentHotkeysScope.scope); - - setHotkeysScopes(scopesToSet); - }, [setHotkeysScopes, customHotkeysScopes, hotkeysScopeStack]); -} diff --git a/front/src/modules/hotkeys/hooks/internal/useHotkeysScope.ts b/front/src/modules/hotkeys/hooks/internal/useHotkeysScopes.ts similarity index 98% rename from front/src/modules/hotkeys/hooks/internal/useHotkeysScope.ts rename to front/src/modules/hotkeys/hooks/internal/useHotkeysScopes.ts index 8129c5f79c..89be27b719 100644 --- a/front/src/modules/hotkeys/hooks/internal/useHotkeysScope.ts +++ b/front/src/modules/hotkeys/hooks/internal/useHotkeysScopes.ts @@ -3,7 +3,7 @@ import { useRecoilCallback } from 'recoil'; import { internalHotkeysEnabledScopesState } from '@/hotkeys/states/internal/internalHotkeysEnabledScopesState'; -export function useHotkeysScope() { +export function useHotkeysScopes() { const { disableScope, enableScope } = useHotkeysContext(); const disableAllHotkeysScopes = useRecoilCallback( diff --git a/front/src/modules/hotkeys/hooks/internal/usePreviousHotkeysScope.ts b/front/src/modules/hotkeys/hooks/internal/usePreviousHotkeysScope.ts new file mode 100644 index 0000000000..af0c9e2aec --- /dev/null +++ b/front/src/modules/hotkeys/hooks/internal/usePreviousHotkeysScope.ts @@ -0,0 +1,39 @@ +import { useState } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState'; +import { CustomHotkeysScopes } from '@/hotkeys/types/internal/CustomHotkeysScope'; +import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope'; + +import { useSetHotkeysScope } from '../useSetHotkeysScope'; + +export function usePreviousHotkeysScope() { + const [previousHotkeysScope, setPreviousHotkeysScope] = + useState(); + + const setHotkeysScope = useSetHotkeysScope(); + + const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState); + + function goBackToPreviousHotkeysScope() { + if (previousHotkeysScope) { + setHotkeysScope( + previousHotkeysScope.scope, + previousHotkeysScope.customScopes, + ); + } + } + + function setHotkeysScopeAndMemorizePreviousScope( + scope: string, + customScopes?: CustomHotkeysScopes, + ) { + setPreviousHotkeysScope(currentHotkeysScope); + setHotkeysScope(scope, customScopes); + } + + return { + setHotkeysScopeAndMemorizePreviousScope, + goBackToPreviousHotkeysScope, + }; +} diff --git a/front/src/modules/hotkeys/hooks/useAddToHotkeysScopeStack.ts b/front/src/modules/hotkeys/hooks/useAddToHotkeysScopeStack.ts deleted file mode 100644 index e18c6ed3eb..0000000000 --- a/front/src/modules/hotkeys/hooks/useAddToHotkeysScopeStack.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { produce } from 'immer'; -import { useRecoilCallback } from 'recoil'; - -import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState'; -import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems'; - -export function useAddToHotkeysScopeStack() { - return useRecoilCallback( - ({ snapshot, set }) => - async ({ - scope, - customScopes = { - 'command-menu': true, - goto: false, - }, - ancestorScope, - }: HotkeysScopeStackItem) => { - const hotkeysScopeStack = await snapshot.getPromise( - hotkeysScopeStackState, - ); - - const currentHotkeysScope = - hotkeysScopeStack.length > 0 - ? hotkeysScopeStack[hotkeysScopeStack.length - 1] - : null; - - const previousHotkeysScope = - hotkeysScopeStack.length > 1 - ? hotkeysScopeStack[hotkeysScopeStack.length - 2] - : null; - - if ( - scope === currentHotkeysScope?.scope || - scope === previousHotkeysScope?.scope - ) { - return; - } - - set( - hotkeysScopeStackState, - produce(hotkeysScopeStack, (draft) => { - draft.push({ scope, customScopes, ancestorScope }); - }), - ); - }, - [], - ); -} diff --git a/front/src/modules/hotkeys/hooks/useCurrentHotkeysScope.ts b/front/src/modules/hotkeys/hooks/useCurrentHotkeysScope.ts deleted file mode 100644 index 5d3b141970..0000000000 --- a/front/src/modules/hotkeys/hooks/useCurrentHotkeysScope.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; - -import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState'; - -export function useCurrentHotkeysScope() { - const hotkeysScopeStack = useRecoilValue(hotkeysScopeStackState); - - return useMemo(() => { - if (hotkeysScopeStack.length === 0) { - return null; - } else { - return hotkeysScopeStack[hotkeysScopeStack.length - 1]; - } - }, [hotkeysScopeStack]); -} diff --git a/front/src/modules/hotkeys/hooks/useHotkeysScopeOnBooleanState.ts b/front/src/modules/hotkeys/hooks/useHotkeysScopeOnBooleanState.ts deleted file mode 100644 index fd0eb74c4f..0000000000 --- a/front/src/modules/hotkeys/hooks/useHotkeysScopeOnBooleanState.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect } from 'react'; - -import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems'; - -import { useAddToHotkeysScopeStack } from './useAddToHotkeysScopeStack'; -import { useRemoveFromHotkeysScopeStack } from './useRemoveFromHotkeysScopeStack'; - -export function useHotkeysScopeOnBooleanState( - hotkeysScopeStackItem: HotkeysScopeStackItem, - booleanState: boolean, -) { - const addToHotkeysScopeStack = useAddToHotkeysScopeStack(); - const removeFromHotkeysScopeStack = useRemoveFromHotkeysScopeStack(); - - useEffect(() => { - if (booleanState) { - addToHotkeysScopeStack(hotkeysScopeStackItem); - } else { - removeFromHotkeysScopeStack(hotkeysScopeStackItem.scope); - } - }, [ - hotkeysScopeStackItem, - removeFromHotkeysScopeStack, - addToHotkeysScopeStack, - booleanState, - ]); -} diff --git a/front/src/modules/hotkeys/hooks/useHotkeysScopeOnMountOnly.ts b/front/src/modules/hotkeys/hooks/useHotkeysScopeOnMountOnly.ts deleted file mode 100644 index aa5f39dbe4..0000000000 --- a/front/src/modules/hotkeys/hooks/useHotkeysScopeOnMountOnly.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useEffect } from 'react'; -import { useRecoilState } from 'recoil'; - -import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState'; -import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems'; - -import { useAddToHotkeysScopeStack } from './useAddToHotkeysScopeStack'; - -export function useHotkeysScopeOnMountOnly( - hotkeysScopeStackItem: HotkeysScopeStackItem, - enabled = true, -) { - const addToHotkeysScopeStack = useAddToHotkeysScopeStack(); - - const [hotkeysScopeStack] = useRecoilState(hotkeysScopeStackState); - - const hotkeysScopeAlreadyInStack = hotkeysScopeStack.some( - (hotkeysScopeStackItemToFind) => - hotkeysScopeStackItemToFind.scope === hotkeysScopeStackItem.scope, - ); - - useEffect(() => { - if (!hotkeysScopeAlreadyInStack && enabled) { - addToHotkeysScopeStack(hotkeysScopeStackItem); - } - }, [ - enabled, - addToHotkeysScopeStack, - hotkeysScopeStackItem, - hotkeysScopeAlreadyInStack, - ]); -} diff --git a/front/src/modules/hotkeys/hooks/useRemoveFromHotkeysScopeStack.ts b/front/src/modules/hotkeys/hooks/useRemoveFromHotkeysScopeStack.ts deleted file mode 100644 index bc8d9344eb..0000000000 --- a/front/src/modules/hotkeys/hooks/useRemoveFromHotkeysScopeStack.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { produce } from 'immer'; -import { useRecoilCallback } from 'recoil'; - -import { DEFAULT_HOTKEYS_SCOPE_STACK_ITEM } from '../constants'; -import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState'; -import { InternalHotkeysScope } from '../types/internal/InternalHotkeysScope'; - -export function useRemoveFromHotkeysScopeStack() { - return useRecoilCallback( - ({ snapshot, set }) => - async (hotkeysScopeToRemove: string) => { - const hotkeysScopeStack = await snapshot.getPromise( - hotkeysScopeStackState, - ); - - if (hotkeysScopeStack.length < 1) { - set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]); - - return; - } - - const currentHotkeysScope = - hotkeysScopeStack[hotkeysScopeStack.length - 1]; - - if (hotkeysScopeStack.length === 1) { - if (currentHotkeysScope?.scope !== InternalHotkeysScope.App) { - set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]); - } - - return; - } - - const previousHotkeysScope = - hotkeysScopeStack[hotkeysScopeStack.length - 2]; - - if ( - previousHotkeysScope.scope === hotkeysScopeToRemove || - currentHotkeysScope.scope !== hotkeysScopeToRemove - ) { - return; - } - - set( - hotkeysScopeStackState, - produce(hotkeysScopeStack, (draft) => { - return draft.filter( - (hotkeysScope) => hotkeysScope.scope !== hotkeysScopeToRemove, - ); - }), - ); - }, - [], - ); -} diff --git a/front/src/modules/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem.ts b/front/src/modules/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem.ts deleted file mode 100644 index 84aca2de1b..0000000000 --- a/front/src/modules/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { produce } from 'immer'; -import { useRecoilCallback } from 'recoil'; - -import { DEFAULT_HOTKEYS_SCOPE_STACK_ITEM } from '../constants'; -import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState'; -import { InternalHotkeysScope } from '../types/internal/InternalHotkeysScope'; - -export function useRemoveHighestHotkeysScopeStackItem() { - return useRecoilCallback( - ({ snapshot, set }) => - async () => { - const hotkeysScopeStack = await snapshot.getPromise( - hotkeysScopeStackState, - ); - - if (hotkeysScopeStack.length < 1) { - set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]); - - return; - } - - const currentHotkeysScope = - hotkeysScopeStack[hotkeysScopeStack.length - 1]; - - if (hotkeysScopeStack.length === 1) { - if (currentHotkeysScope?.scope !== InternalHotkeysScope.App) { - set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]); - } - - return; - } - - set( - hotkeysScopeStackState, - produce(hotkeysScopeStack, (draft) => { - draft.pop(); - }), - ); - }, - [], - ); -} diff --git a/front/src/modules/hotkeys/hooks/useResetHotkeysScopeStack.ts b/front/src/modules/hotkeys/hooks/useResetHotkeysScopeStack.ts deleted file mode 100644 index 424fb48c2c..0000000000 --- a/front/src/modules/hotkeys/hooks/useResetHotkeysScopeStack.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useResetRecoilState } from 'recoil'; - -import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState'; - -import { useAddToHotkeysScopeStack } from './useAddToHotkeysScopeStack'; - -export function useResetHotkeysScopeStack() { - const resetHotkeysScopeStack = useResetRecoilState(hotkeysScopeStackState); - const addHotkeysScopedStack = useAddToHotkeysScopeStack(); - - return function reset(toFirstScope?: string) { - resetHotkeysScopeStack(); - - if (toFirstScope) { - addHotkeysScopedStack({ scope: toFirstScope }); - } - }; -} diff --git a/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts b/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts new file mode 100644 index 0000000000..9dc9f930e5 --- /dev/null +++ b/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts @@ -0,0 +1,59 @@ +import { useRecoilCallback } from 'recoil'; + +import { isDefined } from '@/utils/type-guards/isDefined'; + +import { DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES } from '../constants'; +import { currentHotkeysScopeState } from '../states/internal/currentHotkeysScopeState'; +import { CustomHotkeysScopes } from '../types/internal/CustomHotkeysScope'; + +export function useSetHotkeysScope() { + return useRecoilCallback( + ({ snapshot, set }) => + async (hotkeysScopeToSet: string, customScopes?: CustomHotkeysScopes) => { + const currentHotkeysScope = await snapshot.getPromise( + currentHotkeysScopeState, + ); + + function isCustomScopesEqual( + customScopesA: CustomHotkeysScopes | undefined, + customScopesB: CustomHotkeysScopes | undefined, + ) { + return ( + customScopesA?.commandMenu === customScopesB?.commandMenu && + customScopesA?.goto === customScopesB?.goto + ); + } + + if (currentHotkeysScope.scope === hotkeysScopeToSet) { + if (!isDefined(customScopes)) { + if ( + isCustomScopesEqual( + currentHotkeysScope?.customScopes, + DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES, + ) + ) { + return; + } + } else { + if ( + isCustomScopesEqual( + currentHotkeysScope?.customScopes, + customScopes, + ) + ) { + return; + } + } + } + + set(currentHotkeysScopeState, { + scope: hotkeysScopeToSet, + customScopes: { + commandMenu: customScopes?.commandMenu ?? true, + goto: customScopes?.goto ?? false, + }, + }); + }, + [], + ); +} diff --git a/front/src/modules/hotkeys/states/internal/currentHotkeysScopeState.ts b/front/src/modules/hotkeys/states/internal/currentHotkeysScopeState.ts new file mode 100644 index 0000000000..f88f88e64f --- /dev/null +++ b/front/src/modules/hotkeys/states/internal/currentHotkeysScopeState.ts @@ -0,0 +1,9 @@ +import { atom } from 'recoil'; + +import { INITIAL_HOTKEYS_SCOPE } from '@/hotkeys/constants'; +import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope'; + +export const currentHotkeysScopeState = atom({ + key: 'currentHotkeysScopeState', + default: INITIAL_HOTKEYS_SCOPE, +}); diff --git a/front/src/modules/hotkeys/states/internal/customHotkeysScopesState.ts b/front/src/modules/hotkeys/states/internal/customHotkeysScopesState.ts deleted file mode 100644 index 8b67d1c9b0..0000000000 --- a/front/src/modules/hotkeys/states/internal/customHotkeysScopesState.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { atom } from 'recoil'; - -import { InternalHotkeysScope } from '../../types/internal/InternalHotkeysScope'; - -export type CustomHotkeysScopes = { - [InternalHotkeysScope.Goto]: boolean; - [InternalHotkeysScope.CommandMenu]: boolean; -}; - -export const customHotkeysScopesState = atom({ - key: 'customHotkeysScopesState', - default: { - 'command-menu': true, - goto: false, - }, -}); diff --git a/front/src/modules/hotkeys/states/internal/hotkeysScopeStackState.ts b/front/src/modules/hotkeys/states/internal/hotkeysScopeStackState.ts deleted file mode 100644 index dec50f6cc1..0000000000 --- a/front/src/modules/hotkeys/states/internal/hotkeysScopeStackState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { atom } from 'recoil'; - -import { DEFAULT_HOTKEYS_SCOPE_STACK_ITEM } from '@/hotkeys/constants'; -import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems'; - -export const hotkeysScopeStackState = atom({ - key: 'hotkeysScopeStackState', - default: [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM], -}); diff --git a/front/src/modules/hotkeys/types/HotkeysScope.ts b/front/src/modules/hotkeys/types/HotkeysScope.ts deleted file mode 100644 index b5d4606ac1..0000000000 --- a/front/src/modules/hotkeys/types/HotkeysScope.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum HotkeysScope { - CompanyPage = 'company-page', -} diff --git a/front/src/modules/hotkeys/types/internal/CustomHotkeysScope.ts b/front/src/modules/hotkeys/types/internal/CustomHotkeysScope.ts new file mode 100644 index 0000000000..3573eca085 --- /dev/null +++ b/front/src/modules/hotkeys/types/internal/CustomHotkeysScope.ts @@ -0,0 +1,4 @@ +export type CustomHotkeysScopes = { + goto?: boolean; + commandMenu?: boolean; +}; diff --git a/front/src/modules/hotkeys/types/internal/HotkeysScope.ts b/front/src/modules/hotkeys/types/internal/HotkeysScope.ts new file mode 100644 index 0000000000..00e47d19e0 --- /dev/null +++ b/front/src/modules/hotkeys/types/internal/HotkeysScope.ts @@ -0,0 +1,6 @@ +import { CustomHotkeysScopes } from './CustomHotkeysScope'; + +export type HotkeysScope = { + scope: string; + customScopes?: CustomHotkeysScopes; +}; diff --git a/front/src/modules/hotkeys/types/internal/HotkeysScopeStackItems.ts b/front/src/modules/hotkeys/types/internal/HotkeysScopeStackItems.ts deleted file mode 100644 index 2caaaf735b..0000000000 --- a/front/src/modules/hotkeys/types/internal/HotkeysScopeStackItems.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { CustomHotkeysScopes } from '@/hotkeys/states/internal/customHotkeysScopesState'; - -export type HotkeysScopeStackItem = { - scope: string; - customScopes?: CustomHotkeysScopes; - ancestorScope?: string | null; -}; diff --git a/front/src/modules/hotkeys/types/internal/InternalHotkeysScope.ts b/front/src/modules/hotkeys/types/internal/InternalHotkeysScope.ts index 1c46dee4c5..41b846338c 100644 --- a/front/src/modules/hotkeys/types/internal/InternalHotkeysScope.ts +++ b/front/src/modules/hotkeys/types/internal/InternalHotkeysScope.ts @@ -11,6 +11,7 @@ export enum InternalHotkeysScope { TableHeaderDropdownButton = 'table-header-dropdown-button', RelationPicker = 'relation-picker', CellDoubleTextInput = 'cell-double-text-input', + TextInput = 'text-input', Settings = 'settings', CreateWokspace = 'create-workspace', PasswordLogin = 'password-login', diff --git a/front/src/modules/hotkeys/types/internal/PageHotkeysScope.ts b/front/src/modules/hotkeys/types/internal/PageHotkeysScope.ts new file mode 100644 index 0000000000..19ee0f1fe8 --- /dev/null +++ b/front/src/modules/hotkeys/types/internal/PageHotkeysScope.ts @@ -0,0 +1,15 @@ +export enum PageHotkeysScope { + Settings = 'settings', + CreateWokspace = 'create-workspace', + PasswordLogin = 'password-login', + AuthIndex = 'auth-index', + CreateProfile = 'create-profile', + ShowPage = 'show-page', + PersonShowPage = 'person-show-page', + CompanyShowPage = 'company-show-page', + CompaniesPage = 'companies-page', + PeoplePage = 'people-page', + OpportunitiesPage = 'opportunities-page', + ProfilePage = 'profile-page', + WorkspaceMemberPage = 'workspace-member-page', +} diff --git a/front/src/modules/people/components/PeopleCompanyPicker.tsx b/front/src/modules/people/components/PeopleCompanyPicker.tsx index fa469bf252..78971f50cf 100644 --- a/front/src/modules/people/components/PeopleCompanyPicker.tsx +++ b/front/src/modules/people/components/PeopleCompanyPicker.tsx @@ -1,13 +1,13 @@ import { Key } from 'ts-key-enum'; -import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect'; import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery'; import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState'; -import { useEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell'; +import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell'; import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState'; import { getLogoUrlFromDomainName } from '@/utils/utils'; import { @@ -32,7 +32,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) { const { closeEditableCell } = useEditableCell(); - const addToScopeStack = useAddToHotkeysScopeStack(); + const addToScopeStack = useSetHotkeysScope(); const companies = useFilteredSearchEntityQuery({ queryHook: useSearchCompanyQuery, @@ -62,7 +62,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) { function handleCreate() { setIsCreating(true); - addToScopeStack({ scope: InternalHotkeysScope.CellDoubleTextInput }); + addToScopeStack(InternalHotkeysScope.CellDoubleTextInput); } useScopedHotkeys( diff --git a/front/src/modules/pipeline-progress/components/NewButton.tsx b/front/src/modules/pipeline-progress/components/NewButton.tsx index 09f67430ff..1ac8cebd03 100644 --- a/front/src/modules/pipeline-progress/components/NewButton.tsx +++ b/front/src/modules/pipeline-progress/components/NewButton.tsx @@ -1,9 +1,9 @@ -import { useCallback, useState } from 'react'; +import { useCallback, useRef, useState } from 'react'; import { getOperationName } from '@apollo/client/utilities'; import { useRecoilState } from 'recoil'; import { v4 as uuidv4 } from 'uuid'; -import { useHotkeysScopeOnBooleanState } from '@/hotkeys/hooks/useHotkeysScopeOnBooleanState'; +import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { RecoilScope } from '@/recoil-scope/components/RecoilScope'; import { Column } from '@/ui/board/components/Board'; @@ -26,16 +26,27 @@ type OwnProps = { }; export function NewButton({ pipelineId, columnId }: OwnProps) { + const containerRef = useRef(null); const [isCreatingCard, setIsCreatingCard] = useState(false); const [board, setBoard] = useRecoilState(boardColumnsState); const [boardItems, setBoardItems] = useRecoilState(boardItemsState); + const { + goBackToPreviousHotkeysScope, + setHotkeysScopeAndMemorizePreviousScope, + } = usePreviousHotkeysScope(); + const [createOnePipelineProgress] = useCreateOnePipelineProgressMutation({ refetchQueries: [getOperationName(GET_PIPELINES) ?? ''], }); - const onEntitySelect = useCallback( + + const handleEntitySelect = useCallback( async (company: Pick) => { + if (!company || !company.name || !company.domainName) return; + setIsCreatingCard(false); + goBackToPreviousHotkeysScope(); + const newUuid = uuidv4(); const newBoard = JSON.parse(JSON.stringify(board)); const destinationColumnIndex = newBoard.findIndex( @@ -71,26 +82,35 @@ export function NewButton({ pipelineId, columnId }: OwnProps) { setBoard, boardItems, setBoardItems, + goBackToPreviousHotkeysScope, ], ); - const onNewClick = useCallback(() => { + const handleNewClick = useCallback(() => { setIsCreatingCard(true); - }, [setIsCreatingCard]); + setHotkeysScopeAndMemorizePreviousScope( + InternalHotkeysScope.RelationPicker, + ); + }, [setIsCreatingCard, setHotkeysScopeAndMemorizePreviousScope]); - useHotkeysScopeOnBooleanState( - { scope: InternalHotkeysScope.RelationPicker }, - isCreatingCard, - ); + function handleCancel() { + goBackToPreviousHotkeysScope(); + setIsCreatingCard(false); + } return ( <> {isCreatingCard && ( - +
+ +
)} - + ); } diff --git a/front/src/modules/pipeline-progress/components/NewCompanyBoardCard.tsx b/front/src/modules/pipeline-progress/components/NewCompanyBoardCard.tsx index cddc735981..804fbbf7b4 100644 --- a/front/src/modules/pipeline-progress/components/NewCompanyBoardCard.tsx +++ b/front/src/modules/pipeline-progress/components/NewCompanyBoardCard.tsx @@ -13,9 +13,10 @@ type OwnProps = { onEntitySelect: ( company: Pick, ) => void; + onCancel: () => void; }; -export function NewCompanyBoardCard({ onEntitySelect }: OwnProps) { +export function NewCompanyBoardCard({ onEntitySelect, onCancel }: OwnProps) { const [searchFilter] = useRecoilScopedState( relationPickerSearchFilterScopedState, ); @@ -39,6 +40,7 @@ export function NewCompanyBoardCard({ onEntitySelect }: OwnProps) { return ( onEntitySelect(value)} + onCancel={onCancel} entities={{ entitiesToSelect: companies.entitiesToSelect, selectedEntity: companies.selectedEntities[0], diff --git a/front/src/modules/relation-picker/components/SingleEntitySelect.tsx b/front/src/modules/relation-picker/components/SingleEntitySelect.tsx index b8f49fe35a..2476a4da7f 100644 --- a/front/src/modules/relation-picker/components/SingleEntitySelect.tsx +++ b/front/src/modules/relation-picker/components/SingleEntitySelect.tsx @@ -1,3 +1,4 @@ +import { useRef } from 'react'; import { useTheme } from '@emotion/react'; import { IconPlus } from '@tabler/icons-react'; @@ -7,6 +8,7 @@ import { DropdownMenuButton } from '@/ui/components/menu/DropdownMenuButton'; import { DropdownMenuItemContainer } from '@/ui/components/menu/DropdownMenuItemContainer'; import { DropdownMenuSearch } from '@/ui/components/menu/DropdownMenuSearch'; import { DropdownMenuSeparator } from '@/ui/components/menu/DropdownMenuSeparator'; +import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef'; import { isDefined } from '@/utils/type-guards/isDefined'; import { useEntitySelectSearch } from '../hooks/useEntitySelectSearch'; @@ -27,19 +29,27 @@ export function SingleEntitySelect< entities, onEntitySelected, onCreate, + onCancel, }: { + onCancel?: () => void; onCreate?: () => void; entities: EntitiesForSingleEntitySelect; onEntitySelected: (entity: CustomEntityForSelect) => void; }) { + const containerRef = useRef(null); + const theme = useTheme(); const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch(); const showCreateButton = isDefined(onCreate) && searchFilter !== ''; + useListenClickOutsideArrayOfRef([containerRef], () => { + onCancel?.(); + }); + return ( - + ); diff --git a/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx b/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx index 193391a3d5..615977eff4 100644 --- a/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx +++ b/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx @@ -1,4 +1,5 @@ import { useRef } from 'react'; +import { Key } from 'ts-key-enum'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; @@ -27,30 +28,41 @@ export function SingleEntitySelectBase< >({ entities, onEntitySelected, + onCancel, }: { entities: EntitiesForSingleEntitySelect; onEntitySelected: (entity: CustomEntityForSelect) => void; + onCancel?: () => void; }) { const containerRef = useRef(null); const entitiesInDropdown = isDefined(entities.selectedEntity) ? [entities.selectedEntity, ...(entities.entitiesToSelect ?? [])] : entities.entitiesToSelect ?? []; - const { hoveredIndex } = useEntitySelectScroll({ + const { hoveredIndex, resetScroll } = useEntitySelectScroll({ entities: entitiesInDropdown, containerRef, }); - // TODO: move to better place for scopping useScopedHotkeys( - 'enter', + Key.Enter, () => { onEntitySelected(entitiesInDropdown[hoveredIndex]); + resetScroll(); }, InternalHotkeysScope.RelationPicker, [entitiesInDropdown, hoveredIndex, onEntitySelected], ); + useScopedHotkeys( + Key.Escape, + () => { + onCancel?.(); + }, + InternalHotkeysScope.RelationPicker, + [onCancel], + ); + return ( {entities.loading ? ( diff --git a/front/src/modules/relation-picker/hooks/useEntitySelectScroll.ts b/front/src/modules/relation-picker/hooks/useEntitySelectScroll.ts index c17ae97903..fffe5547ab 100644 --- a/front/src/modules/relation-picker/hooks/useEntitySelectScroll.ts +++ b/front/src/modules/relation-picker/hooks/useEntitySelectScroll.ts @@ -21,6 +21,22 @@ export function useEntitySelectScroll< relationPickerHoverIndexScopedState, ); + function resetScroll() { + setHoveredIndex(0); + + const currentHoveredRef = containerRef.current?.children[0] as HTMLElement; + + scrollIntoView(currentHoveredRef, { + align: { + top: 0, + }, + isScrollable: (target) => { + return target === containerRef.current; + }, + time: 0, + }); + } + useScopedHotkeys( Key.ArrowUp, () => { @@ -60,7 +76,6 @@ export function useEntitySelectScroll< ] as HTMLElement; if (currentHoveredRef) { - console.log({ currentHoveredRef, containerRef }); scrollIntoView(currentHoveredRef, { align: { top: 0.15, @@ -78,5 +93,6 @@ export function useEntitySelectScroll< return { hoveredIndex, + resetScroll, }; } diff --git a/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldDateEditMode.tsx b/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldDateEditMode.tsx index 16b1c3833b..3e6f719adc 100644 --- a/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldDateEditMode.tsx +++ b/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldDateEditMode.tsx @@ -1,4 +1,3 @@ -import { useBoardCardField } from '@/ui/board-card-field/hooks/useBoardCardField'; import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode'; type OwnProps = { @@ -10,11 +9,8 @@ export function BoardCardEditableFieldDateEditMode({ value, onChange, }: OwnProps) { - const { closeBoardCardField } = useBoardCardField(); - function handleDateChange(newDate: Date) { onChange(newDate); - closeBoardCardField(); } return ; diff --git a/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldText.tsx b/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldText.tsx index 587d403550..cffb48bed9 100644 --- a/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldText.tsx +++ b/front/src/modules/ui/board-card-field-inputs/components/BoardCardEditableFieldText.tsx @@ -19,9 +19,11 @@ export function BoardCardEditableFieldText({ editModeHorizontalAlign, }: OwnProps) { const [internalValue, setInternalValue] = useState(value); + const debouncedOnChange = useMemo(() => { return debounce(onChange, 200); }, [onChange]); + return ( ` +export const BoardCardFieldEditModeContainer = styled.div< + Omit +>` align-items: center; border: 1px solid ${({ theme }) => theme.border.color.light}; border-radius: ${({ theme }) => theme.border.radius.sm}; @@ -31,38 +31,37 @@ type OwnProps = { children: ReactElement; editModeHorizontalAlign?: 'left' | 'right'; editModeVerticalPosition?: 'over' | 'below'; - onOutsideClick?: () => void; + onExit: () => void; }; export function BoardCardEditableFieldEditMode({ editModeHorizontalAlign, editModeVerticalPosition, children, + onExit, }: OwnProps) { const wrapperRef = useRef(null); - const { closeBoardCardField } = useBoardCardField(); - useListenClickOutsideArrayOfRef([wrapperRef], () => { - closeBoardCardField(); + onExit(); }); useScopedHotkeys( 'enter', () => { - closeBoardCardField(); + onExit(); }, InternalHotkeysScope.BoardCardFieldEditMode, - [closeBoardCardField], + [onExit], ); useScopedHotkeys( 'esc', () => { - closeBoardCardField(); + onExit(); }, InternalHotkeysScope.BoardCardFieldEditMode, - [closeBoardCardField], + [onExit], ); return ( diff --git a/front/src/modules/ui/board-card-field/components/BoardCardEditableFieldInternal.tsx b/front/src/modules/ui/board-card-field/components/BoardCardEditableFieldInternal.tsx index c55ae87920..36d3b34b80 100644 --- a/front/src/modules/ui/board-card-field/components/BoardCardEditableFieldInternal.tsx +++ b/front/src/modules/ui/board-card-field/components/BoardCardEditableFieldInternal.tsx @@ -1,8 +1,8 @@ import { ReactElement } from 'react'; import styled from '@emotion/styled'; -import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack'; -import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems'; +import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope'; +import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useBoardCardField } from '../hooks/useBoardCardField'; @@ -26,7 +26,7 @@ type OwnProps = { nonEditModeContent: ReactElement; editModeHorizontalAlign?: 'left' | 'right'; editModeVerticalPosition?: 'over' | 'below'; - editHotkeysScope?: HotkeysScopeStackItem; + editHotkeysScope?: HotkeysScope; }; export function BoardCardEditableFieldInternal({ @@ -39,25 +39,35 @@ export function BoardCardEditableFieldInternal({ const { openBoardCardField, isBoardCardFieldInEditMode } = useBoardCardField(); - const addToHotkeysScopeStack = useAddToHotkeysScopeStack(); + const { closeBoardCardField } = useBoardCardField(); + + const { + goBackToPreviousHotkeysScope, + setHotkeysScopeAndMemorizePreviousScope, + } = usePreviousHotkeysScope(); function handleOnClick() { if (!isBoardCardFieldInEditMode) { openBoardCardField(); - addToHotkeysScopeStack( - editHotkeysScope ?? { - scope: InternalHotkeysScope.BoardCardFieldEditMode, - }, + setHotkeysScopeAndMemorizePreviousScope( + editHotkeysScope?.scope ?? InternalHotkeysScope.BoardCardFieldEditMode, + editHotkeysScope?.customScopes ?? {}, ); } } + function handleEditModeExit() { + goBackToPreviousHotkeysScope(); + closeBoardCardField(); + } + return ( {isBoardCardFieldInEditMode ? ( {editModeContent} diff --git a/front/src/modules/ui/components/editable-cell/EditableCell.tsx b/front/src/modules/ui/components/editable-cell/EditableCell.tsx index 5dbd101714..1736323f30 100644 --- a/front/src/modules/ui/components/editable-cell/EditableCell.tsx +++ b/front/src/modules/ui/components/editable-cell/EditableCell.tsx @@ -1,11 +1,11 @@ import { ReactElement } from 'react'; import styled from '@emotion/styled'; -import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems'; +import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; -import { useEditableCell } from './hooks/useCloseEditableCell'; import { useCurrentCellEditMode } from './hooks/useCurrentCellEditMode'; +import { useEditableCell } from './hooks/useEditableCell'; import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell'; import { useSetSoftFocusOnCurrentCell } from './hooks/useSetSoftFocusOnCurrentCell'; import { EditableCellDisplayMode } from './EditableCellDisplayMode'; @@ -28,7 +28,7 @@ type OwnProps = { nonEditModeContent: ReactElement; editModeHorizontalAlign?: 'left' | 'right'; editModeVerticalPosition?: 'over' | 'below'; - editHotkeysScope?: HotkeysScopeStackItem; + editHotkeysScope?: HotkeysScope; }; export function EditableCell({ @@ -60,9 +60,9 @@ export function EditableCell({ scope: InternalHotkeysScope.CellEditMode, }, ); + } else { + setSoftFocusOnCurrentCell(); } - - setSoftFocusOnCurrentCell(); } return ( diff --git a/front/src/modules/ui/components/editable-cell/EditableCellEditMode.tsx b/front/src/modules/ui/components/editable-cell/EditableCellEditMode.tsx index 44cdbc0503..f610b5ab45 100644 --- a/front/src/modules/ui/components/editable-cell/EditableCellEditMode.tsx +++ b/front/src/modules/ui/components/editable-cell/EditableCellEditMode.tsx @@ -7,7 +7,7 @@ import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsid import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus'; import { overlayBackground } from '@/ui/themes/effects'; -import { useEditableCell } from './hooks/useCloseEditableCell'; +import { useEditableCell } from './hooks/useEditableCell'; export const EditableCellEditModeContainer = styled.div` align-items: center; diff --git a/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx b/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx index 653dba3de3..dad7d19de6 100644 --- a/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx +++ b/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx @@ -1,17 +1,17 @@ import React from 'react'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; -import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems'; +import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { isNonTextWritingKey } from '@/utils/hotkeys/isNonTextWritingKey'; -import { useEditableCell } from './hooks/useCloseEditableCell'; +import { useEditableCell } from './hooks/useEditableCell'; import { EditableCellDisplayMode } from './EditableCellDisplayMode'; export function EditableCellSoftFocusMode({ children, editHotkeysScope, -}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScopeStackItem }>) { +}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScope }>) { const { closeEditableCell, openEditableCell } = useEditableCell(); useScopedHotkeys( diff --git a/front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts b/front/src/modules/ui/components/editable-cell/hooks/useEditableCell.ts similarity index 62% rename from front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts rename to front/src/modules/ui/components/editable-cell/hooks/useEditableCell.ts index 6f43d56d99..27c685fbc3 100644 --- a/front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts +++ b/front/src/modules/ui/components/editable-cell/hooks/useEditableCell.ts @@ -1,8 +1,8 @@ import { useRecoilCallback } from 'recoil'; -import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack'; -import { useRemoveHighestHotkeysScopeStackItem } from '@/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem'; -import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; +import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope'; +import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useCloseCurrentCellInEditMode } from '@/ui/tables/hooks/useClearCellInEditMode'; import { isSoftFocusActiveState } from '@/ui/tables/states/isSoftFocusActiveState'; import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState'; @@ -12,21 +12,18 @@ import { useCurrentCellEditMode } from './useCurrentCellEditMode'; export function useEditableCell() { const { setCurrentCellInEditMode } = useCurrentCellEditMode(); - const addToHotkeysScopeStack = useAddToHotkeysScopeStack(); + const setHotkeysScope = useSetHotkeysScope(); const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode(); - const removeHighestHotkeysScopedStackItem = - useRemoveHighestHotkeysScopeStackItem(); - function closeEditableCell() { closeCurrentCellInEditMode(); - removeHighestHotkeysScopedStackItem(); + setHotkeysScope(InternalHotkeysScope.TableSoftFocus); } const openEditableCell = useRecoilCallback( ({ snapshot, set }) => - (hotkeysScopeStackItem: HotkeysScopeStackItem) => { + (hotkeysScope: HotkeysScope) => { const isSomeInputInEditMode = snapshot .getLoadable(isSomeInputInEditModeState) .valueOrThrow(); @@ -37,10 +34,10 @@ export function useEditableCell() { setCurrentCellInEditMode(); - addToHotkeysScopeStack(hotkeysScopeStackItem); + setHotkeysScope(hotkeysScope.scope); } }, - [setCurrentCellInEditMode, addToHotkeysScopeStack], + [setCurrentCellInEditMode, setHotkeysScope], ); return { diff --git a/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts b/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts index cbd6b7b254..3f58909664 100644 --- a/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts +++ b/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts @@ -1,7 +1,7 @@ import { useCallback, useMemo } from 'react'; import { useRecoilState } from 'recoil'; -import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useSetSoftFocusPosition } from '@/ui/tables/hooks/useSetSoftFocusPosition'; @@ -34,16 +34,16 @@ export function useSetSoftFocusOnCurrentCell() { const [, setIsSoftFocusActive] = useRecoilState(isSoftFocusActiveState); - const addToHotkeysScopeStack = useAddToHotkeysScopeStack(); + const setHotkeysScope = useSetHotkeysScope(); return useCallback(() => { setSoftFocusPosition(currentTablePosition); setIsSoftFocusActive(true); - addToHotkeysScopeStack({ scope: InternalHotkeysScope.TableSoftFocus }); + setHotkeysScope(InternalHotkeysScope.TableSoftFocus); }, [ setSoftFocusPosition, currentTablePosition, setIsSoftFocusActive, - addToHotkeysScopeStack, + setHotkeysScope, ]); } diff --git a/front/src/modules/ui/components/editable-cell/types/EditableCellDateEditMode.tsx b/front/src/modules/ui/components/editable-cell/types/EditableCellDateEditMode.tsx index f072c6a60e..a258e2ae79 100644 --- a/front/src/modules/ui/components/editable-cell/types/EditableCellDateEditMode.tsx +++ b/front/src/modules/ui/components/editable-cell/types/EditableCellDateEditMode.tsx @@ -1,6 +1,6 @@ import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode'; -import { useEditableCell } from '../hooks/useCloseEditableCell'; +import { useEditableCell } from '../hooks/useEditableCell'; export type EditableDateProps = { value: Date; diff --git a/front/src/modules/ui/components/editable-cell/types/EditableCellDoubleTextEditMode.tsx b/front/src/modules/ui/components/editable-cell/types/EditableCellDoubleTextEditMode.tsx index 7daba68065..e5103a649e 100644 --- a/front/src/modules/ui/components/editable-cell/types/EditableCellDoubleTextEditMode.tsx +++ b/front/src/modules/ui/components/editable-cell/types/EditableCellDoubleTextEditMode.tsx @@ -7,7 +7,7 @@ import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysSc import { InplaceInputTextEditMode } from '@/ui/inplace-inputs/components/InplaceInputTextEditMode'; import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus'; -import { useEditableCell } from '../hooks/useCloseEditableCell'; +import { useEditableCell } from '../hooks/useEditableCell'; type OwnProps = { firstValue: string; diff --git a/front/src/modules/ui/components/inputs/TextInput.tsx b/front/src/modules/ui/components/inputs/TextInput.tsx index 3248e048be..1fbb0d68d8 100644 --- a/front/src/modules/ui/components/inputs/TextInput.tsx +++ b/front/src/modules/ui/components/inputs/TextInput.tsx @@ -1,5 +1,10 @@ -import { ChangeEvent } from 'react'; +import { ChangeEvent, useRef } from 'react'; import styled from '@emotion/styled'; +import { Key } from 'ts-key-enum'; + +import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope'; +import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; +import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; type OwnProps = Omit< React.InputHTMLAttributes, @@ -52,10 +57,37 @@ export function TextInput({ fullWidth, ...props }: OwnProps): JSX.Element { + const inputRef = useRef(null); + + const { + goBackToPreviousHotkeysScope, + setHotkeysScopeAndMemorizePreviousScope, + } = usePreviousHotkeysScope(); + + function handleFocus() { + setHotkeysScopeAndMemorizePreviousScope(InternalHotkeysScope.TextInput); + } + + function handleBlur() { + goBackToPreviousHotkeysScope(); + } + + useScopedHotkeys( + [Key.Enter, Key.Escape], + () => { + inputRef.current?.blur(); + }, + InternalHotkeysScope.TextInput, + ); + return ( {label && {label}} ) => { diff --git a/front/src/modules/ui/components/table/table-header/FilterDropdownButton.tsx b/front/src/modules/ui/components/table/table-header/FilterDropdownButton.tsx index 0fb171e5f5..8514c42c58 100644 --- a/front/src/modules/ui/components/table/table-header/FilterDropdownButton.tsx +++ b/front/src/modules/ui/components/table/table-header/FilterDropdownButton.tsx @@ -1,11 +1,13 @@ import { useCallback, useState } from 'react'; +import { Key } from 'ts-key-enum'; import { activeTableFiltersScopedState } from '@/filters-and-sorts/states/activeTableFiltersScopedState'; import { filterDropdownSearchInputScopedState } from '@/filters-and-sorts/states/filterDropdownSearchInputScopedState'; import { isFilterDropdownOperandSelectUnfoldedScopedState } from '@/filters-and-sorts/states/isFilterDropdownOperandSelectUnfoldedScopedState'; import { selectedOperandInDropdownScopedState } from '@/filters-and-sorts/states/selectedOperandInDropdownScopedState'; import { tableFilterDefinitionUsedInDropdownScopedState } from '@/filters-and-sorts/states/tableFilterDefinitionUsedInDropdownScopedState'; -import { useHotkeysScopeOnBooleanState } from '@/hotkeys/hooks/useHotkeysScopeOnBooleanState'; +import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { TableContext } from '@/ui/tables/states/TableContext'; @@ -23,11 +25,6 @@ import { FilterDropdownTextSearchInput } from './FilterDropdownTextSearchInput'; export function FilterDropdownButton() { const [isUnfolded, setIsUnfolded] = useState(false); - useHotkeysScopeOnBooleanState( - { scope: InternalHotkeysScope.TableHeaderDropdownButton }, - isUnfolded, - ); - const [ isFilterDropdownOperandSelectUnfolded, setIsFilterDropdownOperandSelectUnfolded, @@ -71,18 +68,27 @@ export function FilterDropdownButton() { const isFilterSelected = (activeTableFilters?.length ?? 0) > 0; + const setHotkeysScope = useSetHotkeysScope(); + function handleIsUnfoldedChange(newIsUnfolded: boolean) { if (newIsUnfolded) { setIsUnfolded(true); } else { + if (tableFilterDefinitionUsedInDropdown?.type === 'entity') { + setHotkeysScope(InternalHotkeysScope.Table); + } setIsUnfolded(false); resetState(); } } - useHotkeysScopeOnBooleanState( - { scope: InternalHotkeysScope.RelationPicker }, - tableFilterDefinitionUsedInDropdown?.type === 'entity', + useScopedHotkeys( + [Key.Escape], + () => { + handleIsUnfoldedChange(false); + }, + InternalHotkeysScope.RelationPicker, + [handleIsUnfoldedChange], ); return ( diff --git a/front/src/modules/ui/components/table/table-header/FilterDropdownFilterSelect.tsx b/front/src/modules/ui/components/table/table-header/FilterDropdownFilterSelect.tsx index b4d4674210..8a7ecd60b1 100644 --- a/front/src/modules/ui/components/table/table-header/FilterDropdownFilterSelect.tsx +++ b/front/src/modules/ui/components/table/table-header/FilterDropdownFilterSelect.tsx @@ -3,6 +3,8 @@ import { filterDropdownSearchInputScopedState } from '@/filters-and-sorts/states import { selectedOperandInDropdownScopedState } from '@/filters-and-sorts/states/selectedOperandInDropdownScopedState'; import { tableFilterDefinitionUsedInDropdownScopedState } from '@/filters-and-sorts/states/tableFilterDefinitionUsedInDropdownScopedState'; import { getOperandsForFilterType } from '@/filters-and-sorts/utils/getOperandsForFilterType'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; +import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedValue } from '@/recoil-scope/hooks/useRecoilScopedValue'; import { TableContext } from '@/ui/tables/states/TableContext'; @@ -33,6 +35,8 @@ export function FilterDropdownFilterSelect() { TableContext, ); + const setHotkeysScope = useSetHotkeysScope(); + return ( {availableTableFilters.map((availableTableFilter, index) => ( @@ -40,6 +44,11 @@ export function FilterDropdownFilterSelect() { key={`select-filter-${index}`} onClick={() => { setTableFilterDefinitionUsedInDropdown(availableTableFilter); + + if (availableTableFilter.type === 'entity') { + setHotkeysScope(InternalHotkeysScope.RelationPicker); + } + setSelectedOperandInDropdown( getOperandsForFilterType(availableTableFilter.type)?.[0], ); diff --git a/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts b/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts index 9bf5c61d41..1249b8ba6b 100644 --- a/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts +++ b/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts @@ -1,7 +1,7 @@ import { useRecoilValue } from 'recoil'; -import { useCurrentHotkeysScope } from '@/hotkeys/hooks/useCurrentHotkeysScope'; -import { useResetHotkeysScopeStack } from '@/hotkeys/hooks/useResetHotkeysScopeStack'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; +import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { isSoftFocusActiveState } from '../states/isSoftFocusActiveState'; @@ -11,12 +11,13 @@ import { useCloseCurrentCellInEditMode } from './useClearCellInEditMode'; import { useDisableSoftFocus } from './useDisableSoftFocus'; export function useLeaveTableFocus() { - const resetHotkeysScopeStack = useResetHotkeysScopeStack(); - const currentHotkeysScope = useCurrentHotkeysScope(); + const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState); const disableSoftFocus = useDisableSoftFocus(); const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode(); + const setHotkeysScope = useSetHotkeysScope(); + const isSoftFocusActive = useRecoilValue(isSoftFocusActiveState); const isSomeInputInEditMode = useRecoilValue(isSomeInputInEditModeState); @@ -32,6 +33,7 @@ export function useLeaveTableFocus() { closeCurrentCellInEditMode(); disableSoftFocus(); - resetHotkeysScopeStack(InternalHotkeysScope.Table); + + setHotkeysScope(InternalHotkeysScope.Table, { goto: true }); }; } diff --git a/front/src/modules/ui/tables/hooks/useMapKeyboardToSoftFocus.ts b/front/src/modules/ui/tables/hooks/useMapKeyboardToSoftFocus.ts index 28d538c83a..de1a88b36f 100644 --- a/front/src/modules/ui/tables/hooks/useMapKeyboardToSoftFocus.ts +++ b/front/src/modules/ui/tables/hooks/useMapKeyboardToSoftFocus.ts @@ -1,8 +1,8 @@ import { useRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; -import { useRemoveFromHotkeysScopeStack } from '@/hotkeys/hooks/useRemoveFromHotkeysScopeStack'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState'; @@ -13,8 +13,8 @@ import { useMoveSoftFocus } from './useMoveSoftFocus'; export function useMapKeyboardToSoftFocus() { const { moveDown, moveLeft, moveRight, moveUp } = useMoveSoftFocus(); - const removeFromHotkeysScopedStack = useRemoveFromHotkeysScopeStack(); const disableSoftFocus = useDisableSoftFocus(); + const setHotkeysScope = useSetHotkeysScope(); const [isSomeInputInEditMode] = useRecoilState(isSomeInputInEditModeState); @@ -65,10 +65,10 @@ export function useMapKeyboardToSoftFocus() { useScopedHotkeys( [Key.Escape], () => { - removeFromHotkeysScopedStack(InternalHotkeysScope.TableSoftFocus); + setHotkeysScope(InternalHotkeysScope.Table, { goto: true }); disableSoftFocus(); }, InternalHotkeysScope.TableSoftFocus, - [removeFromHotkeysScopedStack, disableSoftFocus], + [disableSoftFocus], ); } diff --git a/front/src/pages/auth/CreateProfile.tsx b/front/src/pages/auth/CreateProfile.tsx index b83ac72f4c..6964892fa3 100644 --- a/front/src/pages/auth/CreateProfile.tsx +++ b/front/src/pages/auth/CreateProfile.tsx @@ -11,7 +11,6 @@ import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { currentUserState } from '@/auth/states/currentUserState'; import { isMockModeState } from '@/auth/states/isMockModeState'; import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { NameFields } from '@/settings/profile/components/NameFields'; @@ -39,10 +38,6 @@ const StyledButtonContainer = styled.div` `; export function CreateProfile() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.CreateProfile, - customScopes: { 'command-menu': false, goto: false }, - }); const navigate = useNavigate(); const [, setMockMode] = useRecoilState(isMockModeState); const onboardingStatus = useOnboardingStatus(); diff --git a/front/src/pages/auth/CreateWorkspace.tsx b/front/src/pages/auth/CreateWorkspace.tsx index 2990242a37..68bef6b3bc 100644 --- a/front/src/pages/auth/CreateWorkspace.tsx +++ b/front/src/pages/auth/CreateWorkspace.tsx @@ -9,7 +9,6 @@ import { Title } from '@/auth/components/ui/Title'; import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; import { isMockModeState } from '@/auth/states/isMockModeState'; import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader'; @@ -37,10 +36,6 @@ const StyledButtonContainer = styled.div` `; export function CreateWorkspace() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.CreateWokspace, - customScopes: { 'command-menu': false, goto: false }, - }); const [, setMockMode] = useRecoilState(isMockModeState); const navigate = useNavigate(); const onboardingStatus = useOnboardingStatus(); diff --git a/front/src/pages/auth/Index.tsx b/front/src/pages/auth/Index.tsx index f311f95ae8..f19120edec 100644 --- a/front/src/pages/auth/Index.tsx +++ b/front/src/pages/auth/Index.tsx @@ -13,7 +13,6 @@ import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState'; import { isMockModeState } from '@/auth/states/isMockModeState'; import { authProvidersState } from '@/client-config/states/authProvidersState'; import { isDemoModeState } from '@/client-config/states/isDemoModeState'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { MainButton } from '@/ui/components/buttons/MainButton'; @@ -33,10 +32,6 @@ const StyledFooterNote = styled(FooterNote)` `; export function Index() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.AuthIndex, - customScopes: { 'command-menu': false, goto: false }, - }); const navigate = useNavigate(); const theme = useTheme(); const [, setMockMode] = useRecoilState(isMockModeState); diff --git a/front/src/pages/auth/PasswordLogin.tsx b/front/src/pages/auth/PasswordLogin.tsx index 8fb966dc23..341f49e932 100644 --- a/front/src/pages/auth/PasswordLogin.tsx +++ b/front/src/pages/auth/PasswordLogin.tsx @@ -11,7 +11,6 @@ import { useAuth } from '@/auth/hooks/useAuth'; import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState'; import { isMockModeState } from '@/auth/states/isMockModeState'; import { isDemoModeState } from '@/client-config/states/isDemoModeState'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { MainButton } from '@/ui/components/buttons/MainButton'; @@ -51,10 +50,6 @@ const StyledErrorContainer = styled.div` `; export function PasswordLogin() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.PasswordLogin, - customScopes: { 'command-menu': false, goto: false }, - }); const navigate = useNavigate(); const [isDemoMode] = useRecoilState(isDemoModeState); diff --git a/front/src/pages/companies/Companies.tsx b/front/src/pages/companies/Companies.tsx index 45c26fad43..38d6f56bb4 100644 --- a/front/src/pages/companies/Companies.tsx +++ b/front/src/pages/companies/Companies.tsx @@ -4,8 +4,6 @@ import styled from '@emotion/styled'; import { v4 as uuidv4 } from 'uuid'; import { GET_COMPANIES } from '@/companies/services'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { RecoilScope } from '@/recoil-scope/components/RecoilScope'; import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar'; import { IconBuildingSkyscraper } from '@/ui/icons/index'; @@ -26,11 +24,6 @@ const StyledTableContainer = styled.div` `; export function Companies() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.Table, - customScopes: { 'command-menu': true, goto: true }, - }); - const [insertCompany] = useInsertCompanyMutation(); async function handleAddButtonClick() { diff --git a/front/src/pages/companies/CompanyShow.tsx b/front/src/pages/companies/CompanyShow.tsx index 09ea094ef1..fdcec17b70 100644 --- a/front/src/pages/companies/CompanyShow.tsx +++ b/front/src/pages/companies/CompanyShow.tsx @@ -3,8 +3,6 @@ import { useTheme } from '@emotion/react'; import { Timeline } from '@/comments/components/timeline/Timeline'; import { useCompanyQuery } from '@/companies/services'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { RawLink } from '@/ui/components/links/RawLink'; import { PropertyBox } from '@/ui/components/property-box/PropertyBox'; import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem'; @@ -19,11 +17,6 @@ import { CommentableType } from '~/generated/graphql'; export function CompanyShow() { const companyId = useParams().companyId ?? ''; - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.ShowPage, - customScopes: { 'command-menu': true, goto: true }, - }); - const { data } = useCompanyQuery(companyId); const company = data?.findUniqueCompany; diff --git a/front/src/pages/people/People.tsx b/front/src/pages/people/People.tsx index b79cb6142e..708fc9c3e7 100644 --- a/front/src/pages/people/People.tsx +++ b/front/src/pages/people/People.tsx @@ -3,8 +3,6 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { v4 as uuidv4 } from 'uuid'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { GET_PEOPLE } from '@/people/services'; import { RecoilScope } from '@/recoil-scope/components/RecoilScope'; import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar'; @@ -24,11 +22,6 @@ const StyledPeopleContainer = styled.div` `; export function People() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.Table, - customScopes: { 'command-menu': true, goto: true }, - }); - const [insertPersonMutation] = useInsertPersonMutation(); async function handleAddButtonClick() { diff --git a/front/src/pages/settings/SettingsProfile.tsx b/front/src/pages/settings/SettingsProfile.tsx index 5db4f645ce..3485147cc9 100644 --- a/front/src/pages/settings/SettingsProfile.tsx +++ b/front/src/pages/settings/SettingsProfile.tsx @@ -1,7 +1,5 @@ import styled from '@emotion/styled'; -import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly'; -import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { EmailField } from '@/settings/profile/components/EmailField'; import { NameFields } from '@/settings/profile/components/NameFields'; import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader'; @@ -27,11 +25,6 @@ const StyledSectionContainer = styled.div` `; export function SettingsProfile() { - useHotkeysScopeOnMountOnly({ - scope: InternalHotkeysScope.Settings, - customScopes: { 'command-menu': true, goto: false }, - }); - return (
diff --git a/front/src/sync-hooks/HotkeysScopeAutoSyncHook.tsx b/front/src/sync-hooks/HotkeysScopeAutoSyncHook.tsx new file mode 100644 index 0000000000..c4e0932016 --- /dev/null +++ b/front/src/sync-hooks/HotkeysScopeAutoSyncHook.tsx @@ -0,0 +1,7 @@ +import { useHotkeysScopeAutoSync } from '@/hotkeys/hooks/internal/useHotkeysScopeAutoSync'; + +export function HotkeysScopeAutoSyncHook() { + useHotkeysScopeAutoSync(); + + return <>; +} diff --git a/front/src/sync-hooks/HotkeysScopeBrowserRouterSync.tsx b/front/src/sync-hooks/HotkeysScopeBrowserRouterSync.tsx new file mode 100644 index 0000000000..1b29e6da41 --- /dev/null +++ b/front/src/sync-hooks/HotkeysScopeBrowserRouterSync.tsx @@ -0,0 +1,71 @@ +import { useEffect } from 'react'; + +import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope'; +import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; +import { PageHotkeysScope } from '@/hotkeys/types/internal/PageHotkeysScope'; + +import { useIsMatchingLocation } from './hooks/useIsMatchingLocation'; +import { AppBasePath } from './types/AppBasePath'; +import { AppPath } from './types/AppPath'; +import { AuthPath } from './types/AuthPath'; +import { SettingsPath } from './types/SettingsPath'; + +export function HotkeysScopeBrowserRouterSync() { + const isMatchingLocation = useIsMatchingLocation(); + + const setHotkeysScope = useSetHotkeysScope(); + + useEffect(() => { + switch (true) { + case isMatchingLocation(AppBasePath.Root, AppPath.CompaniesPage): { + setHotkeysScope(InternalHotkeysScope.Table, { goto: true }); + break; + } + case isMatchingLocation(AppBasePath.Root, AppPath.PeoplePage): { + setHotkeysScope(InternalHotkeysScope.Table, { goto: true }); + break; + } + case isMatchingLocation(AppBasePath.Root, AppPath.CompanyShowPage): { + setHotkeysScope(PageHotkeysScope.CompanyShowPage, { goto: true }); + break; + } + case isMatchingLocation(AppBasePath.Root, AppPath.PersonShowPage): { + setHotkeysScope(PageHotkeysScope.PersonShowPage, { goto: true }); + break; + } + case isMatchingLocation(AppBasePath.Root, AppPath.OpportunitiesPage): { + setHotkeysScope(PageHotkeysScope.OpportunitiesPage, { goto: true }); + break; + } + case isMatchingLocation(AppBasePath.Auth, AuthPath.Index): { + setHotkeysScope(InternalHotkeysScope.AuthIndex); + break; + } + case isMatchingLocation(AppBasePath.Auth, AuthPath.CreateProfile): { + setHotkeysScope(InternalHotkeysScope.CreateProfile); + break; + } + case isMatchingLocation(AppBasePath.Auth, AuthPath.CreateWorkspace): { + setHotkeysScope(InternalHotkeysScope.CreateWokspace); + break; + } + case isMatchingLocation(AppBasePath.Auth, AuthPath.PasswordLogin): { + setHotkeysScope(InternalHotkeysScope.PasswordLogin); + break; + } + case isMatchingLocation(AppBasePath.Settings, SettingsPath.ProfilePage): { + setHotkeysScope(PageHotkeysScope.ProfilePage, { goto: true }); + break; + } + case isMatchingLocation( + AppBasePath.Settings, + SettingsPath.WorkspaceMembersPage, + ): { + setHotkeysScope(PageHotkeysScope.WorkspaceMemberPage, { goto: true }); + break; + } + } + }, [isMatchingLocation, setHotkeysScope]); + + return <>; +} diff --git a/front/src/sync-hooks/HotkeysScopeStackAutoSyncHook.tsx b/front/src/sync-hooks/HotkeysScopeStackAutoSyncHook.tsx deleted file mode 100644 index 95135b2594..0000000000 --- a/front/src/sync-hooks/HotkeysScopeStackAutoSyncHook.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { useHotkeysScopeStackAutoSync } from '@/hotkeys/hooks/internal/useHotkeysScopeStackAutoSync'; - -export function HotkeysScopeStackAutoSyncHook() { - useHotkeysScopeStackAutoSync(); - - return <>; -} diff --git a/front/src/sync-hooks/hooks/useIsMatchingLocation.ts b/front/src/sync-hooks/hooks/useIsMatchingLocation.ts new file mode 100644 index 0000000000..3db913d010 --- /dev/null +++ b/front/src/sync-hooks/hooks/useIsMatchingLocation.ts @@ -0,0 +1,16 @@ +import { matchPath, useLocation } from 'react-router-dom'; +import { parse } from 'url'; + +import { AppBasePath } from '../types/AppBasePath'; + +export function useIsMatchingLocation() { + const location = useLocation(); + + return function isMatchingLocation(basePath: AppBasePath, path: string) { + const constructedPath = basePath + ? parse(`${basePath}/${path}`).pathname ?? '' + : path; + + return !!matchPath(constructedPath, location.pathname); + }; +} diff --git a/front/src/sync-hooks/types/AppBasePath.ts b/front/src/sync-hooks/types/AppBasePath.ts new file mode 100644 index 0000000000..a9ae5f7579 --- /dev/null +++ b/front/src/sync-hooks/types/AppBasePath.ts @@ -0,0 +1,5 @@ +export enum AppBasePath { + Auth = '/auth', + Settings = '/settings', + Root = '/', +} diff --git a/front/src/sync-hooks/types/AppPath.ts b/front/src/sync-hooks/types/AppPath.ts new file mode 100644 index 0000000000..1702647635 --- /dev/null +++ b/front/src/sync-hooks/types/AppPath.ts @@ -0,0 +1,9 @@ +export enum AppPath { + AuthCatchAll = `/auth/*`, + PeoplePage = '/people', + CompaniesPage = '/companies', + CompanyShowPage = '/companies/:companyId', + PersonShowPage = '/person/:personId', + OpportunitiesPage = '/opportunities', + SettingsCatchAll = `/settings/*`, +} diff --git a/front/src/sync-hooks/types/AuthPath.ts b/front/src/sync-hooks/types/AuthPath.ts new file mode 100644 index 0000000000..e528e46ada --- /dev/null +++ b/front/src/sync-hooks/types/AuthPath.ts @@ -0,0 +1,7 @@ +export enum AuthPath { + Index = '', + Callback = 'callback', + PasswordLogin = 'password-login', + CreateWorkspace = 'create/workspace', + CreateProfile = 'create/profile', +} diff --git a/front/src/sync-hooks/types/SettingsPath.ts b/front/src/sync-hooks/types/SettingsPath.ts new file mode 100644 index 0000000000..dcf282e032 --- /dev/null +++ b/front/src/sync-hooks/types/SettingsPath.ts @@ -0,0 +1,5 @@ +export enum SettingsPath { + ProfilePage = 'profile', + WorkspaceMembersPage = 'workspace-members', + Workspace = 'workspace', +} diff --git a/front/yarn.lock b/front/yarn.lock index 744a627391..ae321e62ad 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -15589,7 +15589,7 @@ pumpify@^1.3.3: inherits "^2.0.3" pump "^2.0.0" -punycode@^1.3.2: +punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== @@ -15639,7 +15639,7 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" -qs@^6.10.0, qs@^6.11.1, qs@^6.4.0: +qs@^6.10.0, qs@^6.11.0, qs@^6.11.1, qs@^6.4.0: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== @@ -18285,6 +18285,14 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +url@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.1.tgz#26f90f615427eca1b9f4d6a28288c147e2302a32" + integrity sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA== + dependencies: + punycode "^1.4.1" + qs "^6.11.0" + urlpattern-polyfill@^8.0.0: version "8.0.2" resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz#99f096e35eff8bf4b5a2aa7d58a1523d6ebc7ce5"