From d47e5ec47db6f065c1653860869b280e605d542d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:52:44 +0100 Subject: [PATCH] Fix command menu closing and opening (#10497) Since I introduced AnimatePresence to animate the exit of the command menu, the command menu wasn't working properly. By adding this animation, I had to reset the command menu states at the end of the animation, otherwise, the component inside the command menu would throw errors. The problem was that, by closing and instantly reopening the command menu, the `onExitComplete` wasn't triggered and the states weren't reset before the opening. By introducing a new state `isCommandMenuClosingState`, I can reset those states at the beginning of the opening if the animation didn't have the time to finish. --- .../command-menu/hooks/useCommandMenu.ts | 89 ++++++++++++------- .../states/isCommandMenuClosingState.ts | 6 ++ 2 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts index a67bd6020..56535c135 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts @@ -19,6 +19,7 @@ import { import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; +import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState'; import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; @@ -48,42 +49,20 @@ export const useCommandMenu = () => { const { closeDropdown } = useDropdownV2(); - const openCommandMenu = useRecoilCallback( - ({ snapshot, set }) => - () => { - const isCommandMenuOpened = snapshot - .getLoadable(isCommandMenuOpenedState) - .getValue(); - - setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen); - - if (isCommandMenuOpened) { - return; - } - - copyContextStoreStates({ - instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID, - instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }); - - set(isCommandMenuOpenedState, true); - set(hasUserSelectedCommandState, false); - }, - [copyContextStoreStates, setHotkeyScopeAndMemorizePreviousScope], - ); - const closeCommandMenu = useRecoilCallback( ({ set }) => () => { set(isCommandMenuOpenedState, false); - closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID); + set(isCommandMenuClosingState, true); }, - [closeDropdown], + [], ); const onCommandMenuCloseAnimationComplete = useRecoilCallback( ({ set }) => () => { + closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID); + resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID); resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID); @@ -101,8 +80,50 @@ export const useCommandMenu = () => { goBackToPreviousHotkeyScope(); emitRightDrawerCloseEvent(); + set(isCommandMenuClosingState, false); }, - [goBackToPreviousHotkeyScope, resetContextStoreStates, resetSelectedItem], + [ + closeDropdown, + goBackToPreviousHotkeyScope, + resetContextStoreStates, + resetSelectedItem, + ], + ); + + const openCommandMenu = useRecoilCallback( + ({ snapshot, set }) => + () => { + const isCommandMenuOpened = snapshot + .getLoadable(isCommandMenuOpenedState) + .getValue(); + + const isCommandMenuClosing = snapshot + .getLoadable(isCommandMenuClosingState) + .getValue(); + + if (isCommandMenuClosing) { + onCommandMenuCloseAnimationComplete(); + } + + setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen); + + if (isCommandMenuOpened) { + return; + } + + copyContextStoreStates({ + instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID, + instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }); + + set(isCommandMenuOpenedState, true); + set(hasUserSelectedCommandState, false); + }, + [ + copyContextStoreStates, + onCommandMenuCloseAnimationComplete, + setHotkeyScopeAndMemorizePreviousScope, + ], ); const navigateCommandMenu = useRecoilCallback( @@ -115,17 +136,21 @@ export const useCommandMenu = () => { }: CommandMenuNavigationStackItem & { resetNavigationStack?: boolean; }) => { - closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID); + openCommandMenu(); set(commandMenuPageState, page); set(commandMenuPageInfoState, { title: pageTitle, Icon: pageIcon, }); - const currentNavigationStack = snapshot - .getLoadable(commandMenuNavigationStackState) + const isCommandMenuClosing = snapshot + .getLoadable(isCommandMenuClosingState) .getValue(); + const currentNavigationStack = isCommandMenuClosing + ? [] + : snapshot.getLoadable(commandMenuNavigationStackState).getValue(); + if (resetNavigationStack) { set(commandMenuNavigationStackState, [{ page, pageTitle, pageIcon }]); } else { @@ -134,10 +159,9 @@ export const useCommandMenu = () => { { page, pageTitle, pageIcon }, ]); } - openCommandMenu(); }; }, - [closeDropdown, openCommandMenu], + [openCommandMenu], ); const openRootCommandMenu = useCallback(() => { @@ -259,6 +283,7 @@ export const useCommandMenu = () => { ? t`New ${capitalizedObjectNameSingular}` : capitalizedObjectNameSingular, pageIcon: Icon, + // TODO: remove this once we can store the navigation stack page states resetNavigationStack: true, }); }; diff --git a/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts b/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts new file mode 100644 index 000000000..fac28fa44 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const isCommandMenuClosingState = createState({ + key: 'command-menu/isCommandMenuClosingState', + defaultValue: false, +});