diff --git a/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx index f63be138b..2ce91d7c1 100644 --- a/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx @@ -8,7 +8,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; @@ -30,12 +30,14 @@ export const CommandMenuActionMenuDropdown = () => { const dropdownId = getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId); - const { toggleDropdown } = useDropdownV2(); + const { toggleDropdown } = useToggleDropdown(); const hotkeysConfig = { keys: ['ctrl+o', 'meta+o'], callback: () => { - toggleDropdown(dropdownId); + toggleDropdown({ + dropdownComponentInstanceIdFromProps: dropdownId, + }); }, scope: AppHotkeyScope.CommandMenuOpen, dependencies: [toggleDropdown], diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx index 8411e9cbd..ea5993d2e 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx @@ -11,7 +11,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; @@ -48,7 +48,7 @@ export const RecordIndexActionMenuDropdown = () => { ); const dropdownId = getActionMenuDropdownIdFromActionMenuId(actionMenuId); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const actionMenuDropdownPosition = useRecoilValue( extractComponentState( diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx index 6d852e6ca..181b55ea2 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx @@ -9,7 +9,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { AppPath } from '@/types/AppPath'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; @@ -74,7 +74,7 @@ export const RecordShowRightDrawerOpenRecordButton = ({ ActionMenuComponentInstanceContext, ); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const handleOpenRecord = useRecoilCallback( ({ snapshot, reset }) => diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useCloseActionMenu.ts b/packages/twenty-front/src/modules/action-menu/hooks/useCloseActionMenu.ts index d3f8edd2b..29665d703 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useCloseActionMenu.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useCloseActionMenu.ts @@ -3,7 +3,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -19,7 +19,7 @@ export const useCloseActionMenu = ({ const { closeCommandMenu } = useCommandMenu(); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const actionMenuId = useAvailableComponentInstanceIdOrThrow( ActionMenuComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroups.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroups.tsx index 2390a9557..58accdfe2 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroups.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroups.tsx @@ -2,7 +2,7 @@ import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/con import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isDefined } from 'twenty-shared/utils'; import { MenuItem } from 'twenty-ui/navigation'; import { @@ -15,7 +15,7 @@ export const CommandMenuContextChipGroups = ({ }: { contextChips: CommandMenuContextChipProps[]; }) => { - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); if (contextChips.length === 0) { return null; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx index 1752d5540..01e6a1b67 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx @@ -25,8 +25,8 @@ const mockResetContextStoreStates = jest.fn(); const mockResetSelectedItem = jest.fn(); const mockEmitSidePanelCloseEvent = jest.fn(); -jest.mock('@/ui/layout/dropdown/hooks/useDropdownV2', () => ({ - useDropdownV2: () => ({ +jest.mock('@/ui/layout/dropdown/hooks/useCloseDropdown', () => ({ + useCloseDropdown: () => ({ closeDropdown: mockCloseDropdown, }), })); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts index 3d244a49c..6b598b281 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts @@ -13,7 +13,7 @@ import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuCl import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { emitSidePanelCloseEvent } from '@/ui/layout/right-drawer/utils/emitSidePanelCloseEvent'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId'; @@ -27,7 +27,7 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => { const { resetContextStoreStates } = useResetContextStoreStates(); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const commandMenuCloseAnimationCompleteCleanup = useRecoilCallback( ({ snapshot, set }) => diff --git a/packages/twenty-front/src/modules/dropdown/hooks/useCurrentContentId.ts b/packages/twenty-front/src/modules/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId.ts similarity index 90% rename from packages/twenty-front/src/modules/dropdown/hooks/useCurrentContentId.ts rename to packages/twenty-front/src/modules/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId.ts index d19e18dc2..066808653 100644 --- a/packages/twenty-front/src/modules/dropdown/hooks/useCurrentContentId.ts +++ b/packages/twenty-front/src/modules/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId.ts @@ -1,6 +1,6 @@ import { useCallback, useState } from 'react'; -export const useCurrentContentId = () => { +export const useDropdownContextCurrentContentId = () => { const [currentContentId, setCurrentContentId] = useState(null); const [previousContentId, setPreviousContentId] = useState(null); diff --git a/packages/twenty-front/src/modules/dropdown/hooks/useDropdown.ts b/packages/twenty-front/src/modules/dropdown-context-state-management/hooks/useDropdownContextStateManagement.ts similarity index 73% rename from packages/twenty-front/src/modules/dropdown/hooks/useDropdown.ts rename to packages/twenty-front/src/modules/dropdown-context-state-management/hooks/useDropdownContextStateManagement.ts index 14792b216..ee8593b61 100644 --- a/packages/twenty-front/src/modules/dropdown/hooks/useDropdown.ts +++ b/packages/twenty-front/src/modules/dropdown-context-state-management/hooks/useDropdownContextStateManagement.ts @@ -4,7 +4,13 @@ import { RecordTableColumnAggregateFooterDropdownContextValue } from '@/object-r import { useDropdown as useDropdownUi } from '@/ui/layout/dropdown/hooks/useDropdown'; import { Context, useCallback, useContext } from 'react'; -export const useDropdown = < +/** + * + * @deprecated This hook is deprecated because it uses context instead of recoil and synchronous hooks like we do in the application + * + * TODO: refactor this generic way to handle multiple pages in a dropdown with state management and specific code paths in a dedicated module, instead of using context with generic union types. + */ +export const useDropdownContextStateManagement = < T extends | RecordBoardColumnHeaderAggregateDropdownContextValue | RecordTableColumnAggregateFooterDropdownContextValue @@ -18,7 +24,7 @@ export const useDropdown = < if (!dropdownContext) { throw new Error( - `useDropdown must be used within a context provider (${context.Provider.name})`, + `useDropdownContextStateManagement must be used within a context provider (${context.Provider.name})`, ); } const dropdownId = dropdownContext.dropdownId; diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdown.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdown.tsx index ea7388cbc..81235ada4 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdown.tsx @@ -1,5 +1,4 @@ -import { DROPDOWN_OFFSET_Y } from '@/dropdown/constants/DropdownOffsetY'; -import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId'; +import { useDropdownContextCurrentContentId } from '@/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent'; import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; @@ -9,6 +8,7 @@ import { RecordGroupReorderConfirmationModal } from '@/object-record/record-grou import { useRecordGroupReorderConfirmationModal } from '@/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; +import { DROPDOWN_OFFSET_Y } from '@/ui/layout/dropdown/constants/DropdownOffsetY'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { ViewType } from '@/views/types/ViewType'; import { Trans } from '@lingui/react/macro'; @@ -25,7 +25,7 @@ export const ObjectOptionsDropdown = ({ viewType, }: ObjectOptionsDropdownProps) => { const { currentContentId, handleContentChange, handleResetContent } = - useCurrentContentId(); + useDropdownContextCurrentContentId(); const { isDropdownOpen } = useDropdown(OBJECT_OPTIONS_DROPDOWN_ID); const { diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent.tsx index 9c9a2d0bc..c45d8f551 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent.tsx @@ -7,10 +7,10 @@ import { ObjectOptionsDropdownMenuContent } from '@/object-record/object-options import { ObjectOptionsDropdownRecordGroupFieldsContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent'; import { ObjectOptionsDropdownRecordGroupsContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent'; import { ObjectOptionsDropdownRecordGroupSortContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; export const ObjectOptionsDropdownContent = () => { - const { currentContentId } = useOptionsDropdown(); + const { currentContentId } = useObjectOptionsDropdown(); switch (currentContentId) { case 'layout': diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownFieldsContent.tsx index aad3638bd..2569576eb 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownFieldsContent.tsx @@ -1,6 +1,6 @@ +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard'; import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; @@ -20,7 +20,7 @@ export const ObjectOptionsDropdownFieldsContent = () => { objectMetadataItem, onContentChange, resetContent, - } = useOptionsDropdown(); + } = useObjectOptionsDropdown(); const { handleColumnVisibilityChange, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx index 416158520..be7fd12b3 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx @@ -3,9 +3,9 @@ import { useSetRecoilState } from 'recoil'; import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard'; import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; import { SettingsPath } from '@/types/SettingsPath'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; @@ -28,7 +28,7 @@ export const ObjectOptionsDropdownHiddenFieldsContent = () => { objectMetadataItem, onContentChange, closeDropdown, - } = useOptionsDropdown(); + } = useObjectOptionsDropdown(); const { objectNamePlural } = useObjectNamePluralFromSingular({ objectNameSingular: objectMetadataItem.nameSingular, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx index ed12e464b..8258b4fa9 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection'; import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; @@ -30,7 +30,7 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => { objectMetadataItem, onContentChange, closeDropdown, - } = useOptionsDropdown(); + } = useObjectOptionsDropdown(); const recordGroupFieldMetadata = useRecoilComponentValueV2( recordGroupFieldMetadataComponentState, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx index b9d6013eb..9e1c38733 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx @@ -1,6 +1,6 @@ import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; import { useSetViewTypeFromLayoutOptionsMenu } from '@/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; @@ -43,7 +43,7 @@ export const ObjectOptionsDropdownLayoutContent = () => { resetContent, onContentChange, dropdownId, - } = useOptionsDropdown(); + } = useObjectOptionsDropdown(); const { isCompactModeActive, setAndPersistIsCompactModeActive } = useObjectOptionsForBoard({ diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx index db95410a9..1ef5de696 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx @@ -1,5 +1,5 @@ import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; @@ -25,7 +25,7 @@ import { import { MenuItemSelect } from 'twenty-ui/navigation'; export const ObjectOptionsDropdownLayoutOpenInContent = () => { - const { onContentChange } = useOptionsDropdown(); + const { onContentChange } = useObjectOptionsDropdown(); const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); const { currentView } = useGetCurrentViewOnly(); const { setAndPersistOpenRecordIn } = useUpdateObjectViewOptions(); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx index fe77f1cd8..1f0fef757 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx @@ -1,7 +1,7 @@ import { ObjectOptionsDropdownMenuViewName } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName'; import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -33,7 +33,7 @@ import { MenuItem } from 'twenty-ui/navigation'; export const ObjectOptionsDropdownMenuContent = () => { const { t } = useLingui(); const { recordIndexId, objectMetadataItem, onContentChange, closeDropdown } = - useOptionsDropdown(); + useObjectOptionsDropdown(); const { currentView } = useGetCurrentViewOnly(); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx index 6fe0cb354..8445c064b 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx @@ -3,7 +3,7 @@ import { useEffect } from 'react'; import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector'; @@ -42,7 +42,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => { onContentChange, resetContent, closeDropdown, - } = useOptionsDropdown(); + } = useObjectOptionsDropdown(); const { objectNamePlural } = useObjectNamePluralFromSingular({ objectNameSingular: objectMetadataItem.nameSingular, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx index 9f1004ab8..d24df4412 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector'; import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort'; import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState'; @@ -24,7 +24,7 @@ import { import { MenuItemSelect } from 'twenty-ui/navigation'; export const ObjectOptionsDropdownRecordGroupSortContent = () => { - const { currentContentId, onContentChange } = useOptionsDropdown(); + const { currentContentId, onContentChange } = useObjectOptionsDropdown(); const hiddenRecordGroupIds = useRecoilComponentValueV2( hiddenRecordGroupIdsComponentSelector, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx index 89bc57433..f3433210a 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection'; import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; @@ -43,7 +43,7 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => { onContentChange, resetContent, handleRecordGroupOrderChangeWithModal, - } = useOptionsDropdown(); + } = useObjectOptionsDropdown(); const { currentView } = useGetCurrentViewOnly(); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useOptionsDropdown.test.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useOptionsDropdown.test.tsx index 837e1bc69..f90acf927 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useOptionsDropdown.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useOptionsDropdown.test.tsx @@ -3,7 +3,7 @@ import { act } from 'react'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId'; -import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; +import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown'; import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { ViewType } from '@/views/types/ViewType'; @@ -61,7 +61,7 @@ describe('useOptionsDropdown', () => { {children} ); - return renderHook(() => useOptionsDropdown(), { wrapper }); + return renderHook(() => useObjectOptionsDropdown(), { wrapper }); }; it('provides closeDropdown functionality from the context', () => { diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useOptionsDropdown.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown.ts similarity index 52% rename from packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useOptionsDropdown.ts rename to packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown.ts index c8825af6c..241a17307 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useOptionsDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown.ts @@ -1,15 +1,15 @@ -import { useDropdown } from '@/dropdown/hooks/useDropdown'; +import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement'; import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext'; import { useContext } from 'react'; -export const useOptionsDropdown = () => { +export const useObjectOptionsDropdown = () => { const context = useContext(ObjectOptionsDropdownContext); if (!context) { - throw new Error('useOptionsDropdown must be used within a context'); + throw new Error('useObjectOptionsDropdown must be used within a context'); } - const { closeDropdown } = useDropdown({ + const { closeDropdown } = useDropdownContextStateManagement({ context: ObjectOptionsDropdownContext, }); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index ac189d251..4187c46e8 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -4,7 +4,6 @@ import { useContext, useRef } from 'react'; import { useRecoilCallback } from 'recoil'; import { ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID } from '@/action-menu/constants/ActionMenuDropdownClickOutsideId'; -import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { COMMAND_MENU_CLICK_OUTSIDE_ID } from '@/command-menu/constants/CommandMenuClickOutsideId'; import { RecordBoardHeader } from '@/object-record/record-board/components/RecordBoardHeader'; import { RecordBoardScrollToFocusedCardEffect } from '@/object-record/record-board/components/RecordBoardScrollToFocusedCardEffect'; @@ -26,7 +25,7 @@ import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-ind import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; import { MODAL_BACKDROP_CLICK_OUTSIDE_ID } from '@/ui/layout/modal/constants/ModalBackdropClickOutsideId'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { PAGE_ACTION_CONTAINER_CLICK_OUTSIDE_ID } from '@/ui/layout/page/constants/PageActionContainerClickOutsideId'; @@ -81,15 +80,13 @@ export const RecordBoard = () => { RECORD_BOARD_CLICK_OUTSIDE_LISTENER_ID, ); - const actionMenuId = getActionMenuIdFromRecordIndexId(recordBoardId); - - const { closeDropdown } = useDropdownV2(); + const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown(); const { deactivateBoardCard } = useActiveRecordBoardCard(recordBoardId); const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId); const handleDragSelectionStart = () => { - closeDropdown(actionMenuId); + closeAnyOpenDropdown(); toggleClickOutside(false); }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts index f3dea2e17..351fed1e4 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts @@ -5,7 +5,7 @@ import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionM import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; @@ -28,7 +28,7 @@ export const useRecordBoardSelection = (recordBoardId?: string) => { recordBoardId, ); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const dropdownId = getActionMenuDropdownIdFromActionMenuId( getActionMenuIdFromRecordIndexId(instanceIdFromProps), diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx index b6741472c..43ca2e433 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx @@ -15,7 +15,7 @@ import { RecordBoardCardBody } from '@/object-record/record-board/record-board-c import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader'; import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId'; import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2'; @@ -140,22 +140,25 @@ export const RecordBoardCard = () => { ), ); - const { openDropdown } = useDropdownV2(); + const { openDropdown } = useOpenDropdown(); const { openRecordFromIndexView } = useOpenRecordFromIndexView(); const { activateBoardCard } = useActiveRecordBoardCard(recordBoardId); const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId); - const handleActionMenuDropdown = (event: React.MouseEvent) => { + const handleContextMenuOpen = (event: React.MouseEvent) => { event.preventDefault(); setIsCurrentCardSelected(true); setActionMenuDropdownPosition({ x: event.clientX, y: event.clientY, }); - openDropdown(actionMenuDropdownId, { - enableGlobalHotkeysWithModifiers: true, - enableGlobalHotkeysConflictingWithKeyboard: false, + openDropdown({ + dropdownComponentInstanceIdFromProps: actionMenuDropdownId, + globalHotkeysConfig: { + enableGlobalHotkeysWithModifiers: true, + enableGlobalHotkeysConflictingWithKeyboard: false, + }, }); }; @@ -185,7 +188,7 @@ export const RecordBoardCard = () => { return ( (); + } = + useDropdownContextCurrentContentId(); return ( { - const { currentContentId, objectMetadataItem } = useDropdown({ - context: RecordBoardColumnHeaderAggregateDropdownContext, - }); + const { currentContentId, objectMetadataItem } = + useDropdownContextStateManagement({ + context: RecordBoardColumnHeaderAggregateDropdownContext, + }); switch (currentContentId) { case 'countAggregateOperationsOptions': { diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx index c79c80c78..258058d64 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx @@ -1,4 +1,4 @@ -import { useDropdown } from '@/dropdown/hooks/useDropdown'; +import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement'; import { RecordBoardColumnHeaderAggregateDropdownContext } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext'; import { aggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/aggregateOperationComponentState'; import { availableFieldIdsForAggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState'; @@ -27,7 +27,7 @@ export const RecordBoardColumnHeaderAggregateDropdownFieldsContent = () => { onContentChange, resetContent, previousContentId, - } = useDropdown({ + } = useDropdownContextStateManagement({ context: RecordBoardColumnHeaderAggregateDropdownContext, }); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent.tsx index 677737123..f06c970dc 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent.tsx @@ -1,6 +1,6 @@ import { Key } from 'ts-key-enum'; -import { useDropdown } from '@/dropdown/hooks/useDropdown'; +import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement'; import { RecordBoardColumnHeaderAggregateDropdownContext, RecordBoardColumnHeaderAggregateDropdownContextValue, @@ -17,9 +17,11 @@ export const RecordBoardColumnHeaderAggregateDropdownMenuContent = () => { const { t } = useLingui(); const { onContentChange, closeDropdown } = - useDropdown({ - context: RecordBoardColumnHeaderAggregateDropdownContext, - }); + useDropdownContextStateManagement( + { + context: RecordBoardColumnHeaderAggregateDropdownContext, + }, + ); useScopedHotkeys( [Key.Escape], diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx index 5c1e08ced..2892fff36 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx @@ -1,4 +1,4 @@ -import { useDropdown } from '@/dropdown/hooks/useDropdown'; +import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement'; import { RecordBoardColumnHeaderAggregateDropdownContext, RecordBoardColumnHeaderAggregateDropdownContextValue, @@ -32,9 +32,11 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({ title: string; }) => { const { onContentChange, closeDropdown, resetContent } = - useDropdown({ - context: RecordBoardColumnHeaderAggregateDropdownContext, - }); + useDropdownContextStateManagement( + { + context: RecordBoardColumnHeaderAggregateDropdownContext, + }, + ); useScopedHotkeys( [Key.Escape], diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent.tsx index f493465dd..6f038cb2d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent.tsx @@ -1,4 +1,4 @@ -import { useDropdown } from '@/dropdown/hooks/useDropdown'; +import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations'; import { RecordTableColumnAggregateFooterDropdownSubmenuContent } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateDropdownSubmenuContent'; @@ -14,9 +14,10 @@ import { useLingui } from '@lingui/react/macro'; export const RecordTableColumnAggregateFooterDropdownContent = () => { const { t } = useLingui(); - const { currentContentId, fieldMetadataType } = useDropdown({ - context: RecordTableColumnAggregateFooterDropdownContext, - }); + const { currentContentId, fieldMetadataType } = + useDropdownContextStateManagement({ + context: RecordTableColumnAggregateFooterDropdownContext, + }); const availableAggregateOperations = getAvailableAggregateOperationsForFieldMetadataType({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterWithDropdown.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterWithDropdown.tsx index 0b50d7771..8d44124b2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterWithDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterWithDropdown.tsx @@ -1,4 +1,4 @@ -import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId'; +import { useDropdownContextCurrentContentId } from '@/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext'; import { RecordTableColumnAggregateFooterDropdownContent } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent'; @@ -19,7 +19,7 @@ export const RecordTableColumnFooterWithDropdown = ({ isFirstCell, }: RecordTableColumnFooterWithDropdownProps) => { const { currentContentId, handleContentChange, handleResetContent } = - useCurrentContentId(); + useDropdownContextCurrentContentId(); const { fieldMetadataId } = useContext( RecordTableColumnAggregateFooterCellContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts index 061fee4d1..720e750c7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts @@ -2,7 +2,7 @@ import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext'; import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates'; import { isDefined } from 'twenty-shared/utils'; @@ -20,7 +20,7 @@ export const useOpenRecordFilterChipFromTableHeader = () => { const { upsertRecordFilter } = useUpsertRecordFilter(); - const { openDropdown } = useDropdownV2(); + const { openDropdown } = useOpenDropdown(); const { setEditableFilterChipDropdownStates } = useSetEditableFilterChipDropdownStates(); @@ -45,7 +45,10 @@ export const useOpenRecordFilterChipFromTableHeader = () => { if (isDefined(existingNonAdvancedRecordFilter)) { setEditableFilterChipDropdownStates(existingNonAdvancedRecordFilter); - openDropdown(existingNonAdvancedRecordFilter.id); + openDropdown({ + dropdownComponentInstanceIdFromProps: + existingNonAdvancedRecordFilter.id, + }); return; } @@ -56,7 +59,7 @@ export const useOpenRecordFilterChipFromTableHeader = () => { upsertRecordFilter(newRecordFilter); setEditableFilterChipDropdownStates(newRecordFilter); - openDropdown(newRecordFilter.id); + openDropdown({ dropdownComponentInstanceIdFromProps: newRecordFilter.id }); }; return { openRecordFilterChipFromTableHeader }; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx index 05456e07f..3c956392d 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx @@ -2,7 +2,7 @@ import { DropdownOnToggleEffect } from '@/ui/layout/dropdown/components/Dropdown import { DropdownInternalContainer } from '@/ui/layout/dropdown/components/internal/DropdownInternalContainer'; import { DROPDOWN_RESIZE_MIN_HEIGHT } from '@/ui/layout/dropdown/constants/DropdownResizeMinHeight'; import { DROPDOWN_RESIZE_MIN_WIDTH } from '@/ui/layout/dropdown/constants/DropdownResizeMinWidth'; -import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext'; +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { dropdownMaxHeightComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState'; import { dropdownMaxWidthComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState'; diff --git a/packages/twenty-front/src/modules/dropdown/constants/DropdownOffsetY.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/constants/DropdownOffsetY.ts similarity index 100% rename from packages/twenty-front/src/modules/dropdown/constants/DropdownOffsetY.tsx rename to packages/twenty-front/src/modules/ui/layout/dropdown/constants/DropdownOffsetY.ts diff --git a/packages/twenty-front/src/modules/dropdown/constants/DropdownWidth.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/constants/DropdownWidth.ts similarity index 100% rename from packages/twenty-front/src/modules/dropdown/constants/DropdownWidth.tsx rename to packages/twenty-front/src/modules/ui/layout/dropdown/constants/DropdownWidth.ts diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/contexts/DropdownComponeInstanceContext.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/contexts/DropdownComponentInstanceContext.ts similarity index 100% rename from packages/twenty-front/src/modules/ui/layout/dropdown/contexts/DropdownComponeInstanceContext.ts rename to packages/twenty-front/src/modules/ui/layout/dropdown/contexts/DropdownComponentInstanceContext.ts diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseAnyOpenDropdown.test.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseAnyOpenDropdown.test.tsx index f51add78e..819a3fd51 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseAnyOpenDropdown.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseAnyOpenDropdown.test.tsx @@ -3,20 +3,36 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { RecoilRoot } from 'recoil'; +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; -import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; +import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; +import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; const dropdownId = 'test-dropdown-id'; const Wrapper = ({ children }: { children: React.ReactNode }) => { - return {children}; + return ( + + + {children} + + + ); }; describe('useCloseAnyOpenDropdown', () => { it('should open dropdown and then close it with closeAnyOpenDropdown', async () => { const { result } = renderHook( () => { - const { openDropdown, isDropdownOpen } = useDropdown(dropdownId); + const isDropdownOpen = useRecoilComponentValueV2( + isDropdownOpenComponentStateV2, + dropdownId, + ); + + const { openDropdown } = useOpenDropdown(); const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown(); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdownFromOutside.test.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdownFromOutside.test.tsx deleted file mode 100644 index 01c5c5eb4..000000000 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdownFromOutside.test.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { expect } from '@storybook/test'; -import { renderHook } from '@testing-library/react'; -import { act } from 'react'; -import { RecoilRoot } from 'recoil'; - -import { useCloseDropdownFromOutside } from '@/ui/layout/dropdown/hooks/useCloseDropdownFromOutside'; -import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; - -const dropdownId = 'test-dropdown-id'; - -const Wrapper = ({ children }: { children: React.ReactNode }) => { - return {children}; -}; - -describe('useCloseDropdownFromOutside', () => { - it('should close open dropdown', async () => { - const { result } = renderHook( - () => { - const { isDropdownOpen, openDropdown } = useDropdown(dropdownId); - const { closeDropdownFromOutside } = useCloseDropdownFromOutside(); - - return { closeDropdownFromOutside, isDropdownOpen, openDropdown }; - }, - { - wrapper: Wrapper, - }, - ); - - expect(result.current.isDropdownOpen).toBe(false); - - act(() => { - result.current.openDropdown(); - }); - - expect(result.current.isDropdownOpen).toBe(true); - - act(() => { - result.current.closeDropdownFromOutside(dropdownId); - }); - - expect(result.current.isDropdownOpen).toBe(false); - }); -}); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown.ts index 11b417aa3..724d0b70f 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown.ts @@ -1,4 +1,4 @@ -import { useCloseDropdownFromOutside } from '@/ui/layout/dropdown/hooks/useCloseDropdownFromOutside'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState'; import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; @@ -6,7 +6,7 @@ import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const useCloseAnyOpenDropdown = () => { - const { closeDropdownFromOutside } = useCloseDropdownFromOutside(); + const { closeDropdown } = useCloseDropdown(); const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); @@ -33,14 +33,14 @@ export const useCloseAnyOpenDropdown = () => { const thereIsOneNestedDropdownOpen = isDefined(previousDropdownFocusId); if (isDefined(activeDropdownFocusId)) { - closeDropdownFromOutside(activeDropdownFocusId); + closeDropdown(activeDropdownFocusId); removeFocusItemFromFocusStackById({ focusId: activeDropdownFocusId, }); } if (thereIsOneNestedDropdownOpen) { - closeDropdownFromOutside(previousDropdownFocusId); + closeDropdown(previousDropdownFocusId); removeFocusItemFromFocusStackById({ focusId: previousDropdownFocusId, }); @@ -49,7 +49,7 @@ export const useCloseAnyOpenDropdown = () => { set(previousDropdownFocusIdState, null); set(activeDropdownFocusIdState, null); }, - [closeDropdownFromOutside, removeFocusItemFromFocusStackById], + [closeDropdown, removeFocusItemFromFocusStackById], ); return { closeAnyOpenDropdown }; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdown.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdown.ts new file mode 100644 index 000000000..f031f6406 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdown.ts @@ -0,0 +1,79 @@ +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; +import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; +import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; +import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2'; +import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; +import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; + +export const useCloseDropdown = () => { + const { goBackToPreviousDropdownFocusId } = + useGoBackToPreviousDropdownFocusId(); + + const { removeFocusItemFromFocusStackById } = + useRemoveFocusItemFromFocusStackById(); + + const dropdownComponentInstanceIdFromContext = + useAvailableComponentInstanceId(DropdownComponentInstanceContext); + + const closeDropdown = useRecoilCallback( + ({ set, snapshot }) => + (dropdownComponentInstanceIdFromProps?: string) => { + const dropdownComponentInstanceId = + dropdownComponentInstanceIdFromProps ?? + dropdownComponentInstanceIdFromContext; + + if (!isDefined(dropdownComponentInstanceId)) { + throw new Error('Dropdown component instance ID is not defined'); + } + + const isDropdownOpen = snapshot + .getLoadable( + isDropdownOpenComponentStateV2.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + ) + .getValue(); + + const isDropdownOpenLegacy = snapshot + .getLoadable( + isDropdownOpenComponentState({ + scopeId: dropdownComponentInstanceId, + }), + ) + .getValue(); + + if (isDropdownOpen || isDropdownOpenLegacy) { + removeFocusItemFromFocusStackById({ + focusId: dropdownComponentInstanceId, + }); + + goBackToPreviousDropdownFocusId(); + + set( + isDropdownOpenComponentStateV2.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + false, + ); + + set( + isDropdownOpenComponentState({ + scopeId: dropdownComponentInstanceId, + }), + false, + ); + } + }, + [ + removeFocusItemFromFocusStackById, + goBackToPreviousDropdownFocusId, + dropdownComponentInstanceIdFromContext, + ], + ); + + return { + closeDropdown, + }; +}; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdownFromOutside.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdownFromOutside.ts deleted file mode 100644 index 9deb63ee6..000000000 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdownFromOutside.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilCallback } from 'recoil'; - -export const useCloseDropdownFromOutside = () => { - const closeDropdownFromOutside = useRecoilCallback( - ({ set }) => - (dropdownId: string) => { - set(isDropdownOpenComponentState({ scopeId: dropdownId }), false); - }, - [], - ); - - return { closeDropdownFromOutside }; -}; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts index d04afd915..ddf3ad8ce 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts @@ -10,6 +10,13 @@ import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysCo import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { useCallback } from 'react'; +/** + * + * @deprecated This hook is deprecated, use a specific hook instead : + * - `useOpenDropdown` + * - `useCloseDropdown` + * - `useToggleDropdown` + */ export const useDropdown = (dropdownId?: string) => { const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); const { removeFocusItemFromFocusStackById } = diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdownV2.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdownV2.ts deleted file mode 100644 index 8ba1fdd34..000000000 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useDropdownV2.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { useRecoilCallback } from 'recoil'; - -import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; -import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; -import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; -import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; -import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; -import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; - -export const useDropdownV2 = () => { - const { goBackToPreviousDropdownFocusId } = - useGoBackToPreviousDropdownFocusId(); - - const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); - - const { removeFocusItemFromFocusStackById } = - useRemoveFocusItemFromFocusStackById(); - - const { setActiveDropdownFocusIdAndMemorizePrevious } = - useSetActiveDropdownFocusIdAndMemorizePrevious(); - - const closeDropdown = useRecoilCallback( - ({ set, snapshot }) => - (specificComponentId: string) => { - const scopeId = specificComponentId; - - const isDropdownOpen = snapshot - .getLoadable(isDropdownOpenComponentState({ scopeId })) - .getValue(); - - if (isDropdownOpen) { - removeFocusItemFromFocusStackById({ - focusId: scopeId, - }); - goBackToPreviousDropdownFocusId(); - set( - isDropdownOpenComponentState({ - scopeId, - }), - false, - ); - } - }, - [removeFocusItemFromFocusStackById, goBackToPreviousDropdownFocusId], - ); - - const openDropdown = useRecoilCallback( - ({ set }) => - ( - specificComponentId: string, - globalHotkeysConfig?: Partial, - ) => { - const scopeId = specificComponentId; - - set( - isDropdownOpenComponentState({ - scopeId, - }), - true, - ); - - setActiveDropdownFocusIdAndMemorizePrevious(specificComponentId); - - pushFocusItemToFocusStack({ - focusId: scopeId, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: scopeId, - }, - globalHotkeysConfig, - // TODO: Remove this once we've fully migrated away from hotkey scopes - hotkeyScope: { scope: 'dropdown' } as HotkeyScope, - memoizeKey: 'global', - }); - }, - [pushFocusItemToFocusStack, setActiveDropdownFocusIdAndMemorizePrevious], - ); - - const toggleDropdown = useRecoilCallback( - ({ snapshot }) => - ( - specificComponentId: string, - globalHotkeysConfig?: Partial, - ) => { - const scopeId = specificComponentId; - const isDropdownOpen = snapshot - .getLoadable(isDropdownOpenComponentState({ scopeId })) - .getValue(); - - if (isDropdownOpen) { - closeDropdown(specificComponentId); - } else { - openDropdown(specificComponentId, globalHotkeysConfig); - } - }, - [closeDropdown, openDropdown], - ); - - return { - closeDropdown, - openDropdown, - toggleDropdown, - }; -}; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useOpenDropdown.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useOpenDropdown.ts new file mode 100644 index 000000000..c38b495d9 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useOpenDropdown.ts @@ -0,0 +1,77 @@ +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; +import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; +import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; +import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2'; +import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; +import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; +import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; +import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; + +type OpenDropdownArgs = { + dropdownComponentInstanceIdFromProps?: string; + globalHotkeysConfig?: Partial; +}; + +export const useOpenDropdown = () => { + const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); + + const { setActiveDropdownFocusIdAndMemorizePrevious } = + useSetActiveDropdownFocusIdAndMemorizePrevious(); + const dropdownComponentInstanceIdFromContext = + useAvailableComponentInstanceId(DropdownComponentInstanceContext); + + const openDropdown = useRecoilCallback( + ({ set }) => + (args?: OpenDropdownArgs | null | undefined) => { + const dropdownComponentInstanceId = + args?.dropdownComponentInstanceIdFromProps ?? + dropdownComponentInstanceIdFromContext; + + if (!isDefined(dropdownComponentInstanceId)) { + throw new Error('Dropdown component instance ID is not defined'); + } + + set( + isDropdownOpenComponentState({ + scopeId: dropdownComponentInstanceId, + }), + true, + ); + + set( + isDropdownOpenComponentStateV2.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + true, + ); + + setActiveDropdownFocusIdAndMemorizePrevious( + dropdownComponentInstanceId, + ); + + pushFocusItemToFocusStack({ + focusId: dropdownComponentInstanceId, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: dropdownComponentInstanceId, + }, + globalHotkeysConfig: args?.globalHotkeysConfig ?? undefined, + // TODO: Remove this once we've fully migrated away from hotkey scopes + hotkeyScope: { scope: 'dropdown' } as HotkeyScope, + memoizeKey: 'global', + }); + }, + [ + pushFocusItemToFocusStack, + setActiveDropdownFocusIdAndMemorizePrevious, + dropdownComponentInstanceIdFromContext, + ], + ); + + return { + openDropdown, + }; +}; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useToggleDropdown.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useToggleDropdown.ts new file mode 100644 index 000000000..279b418a1 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useToggleDropdown.ts @@ -0,0 +1,66 @@ +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; +import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; +import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; +import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2'; +import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; +import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; + +export const useToggleDropdown = () => { + const dropdownComponentInstanceIdFromContext = + useAvailableComponentInstanceId(DropdownComponentInstanceContext); + + const { openDropdown } = useOpenDropdown(); + const { closeDropdown } = useCloseDropdown(); + + const toggleDropdown = useRecoilCallback( + ({ snapshot }) => + ({ + dropdownComponentInstanceIdFromProps, + globalHotkeysConfig, + }: { + dropdownComponentInstanceIdFromProps?: string; + globalHotkeysConfig?: Partial; + }) => { + const dropdownComponentInstanceId = + dropdownComponentInstanceIdFromProps ?? + dropdownComponentInstanceIdFromContext; + + if (!isDefined(dropdownComponentInstanceId)) { + throw new Error('Dropdown component instance ID is not defined'); + } + + const isDropdownOpen = snapshot + .getLoadable( + isDropdownOpenComponentStateV2.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + ) + .getValue(); + + const isDropdownOpenLegacy = snapshot + .getLoadable( + isDropdownOpenComponentState({ + scopeId: dropdownComponentInstanceId, + }), + ) + .getValue(); + + if (isDropdownOpen || isDropdownOpenLegacy) { + closeDropdown(dropdownComponentInstanceId); + } else { + openDropdown({ + dropdownComponentInstanceIdFromProps: dropdownComponentInstanceId, + globalHotkeysConfig, + }); + } + }, + [closeDropdown, openDropdown, dropdownComponentInstanceIdFromContext], + ); + + return { + toggleDropdown, + }; +}; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/activeDropdownFocusIdState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/activeDropdownFocusIdState.ts index d775eb156..0e264992e 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/activeDropdownFocusIdState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/activeDropdownFocusIdState.ts @@ -1,4 +1,5 @@ import { createState } from 'twenty-ui/utilities'; + export const activeDropdownFocusIdState = createState({ key: 'activeDropdownFocusIdState', defaultValue: null, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState.ts index f375c8b87..c1d5181f8 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState.ts @@ -1,4 +1,4 @@ -import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext'; +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; export const dropdownMaxHeightComponentState = createComponentStateV2< diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState.ts index 4b7345b84..6461f6e6e 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState.ts @@ -1,4 +1,4 @@ -import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext'; +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; export const dropdownMaxWidthComponentState = createComponentStateV2< diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentState.ts index 22aa5bc66..44722fde6 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentState.ts @@ -1,5 +1,8 @@ import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +/** + * @deprecated Use `isDropdownOpenComponentStateV2` instead. + */ export const isDropdownOpenComponentState = createComponentState({ key: 'isDropdownOpenComponentState', defaultValue: false, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentStateV2.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentStateV2.ts new file mode 100644 index 000000000..717b00333 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/isDropdownOpenComponentStateV2.ts @@ -0,0 +1,8 @@ +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const isDropdownOpenComponentStateV2 = createComponentStateV2({ + key: 'isDropdownOpenComponentStateV2', + defaultValue: false, + componentInstanceContext: DropdownComponentInstanceContext, +}); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/previousDropdownFocusIdState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/previousDropdownFocusIdState.ts index ff4161a14..e5548122b 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/previousDropdownFocusIdState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/previousDropdownFocusIdState.ts @@ -1,4 +1,5 @@ import { createState } from 'twenty-ui/utilities'; + export const previousDropdownFocusIdState = createState({ key: 'previousDropdownFocusIdState', defaultValue: null, diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId.ts new file mode 100644 index 000000000..6f138c2b7 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId.ts @@ -0,0 +1,19 @@ +import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; +import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { isNonEmptyString } from '@sniptt/guards'; + +export const useAvailableComponentInstanceId = < + T extends { instanceId: string }, +>( + Context: ComponentInstanceStateContext, +): string | null => { + const instanceStateContext = useComponentInstanceStateContext(Context); + + const instanceIdFromContext = instanceStateContext?.instanceId; + + if (isNonEmptyString(instanceIdFromContext)) { + return instanceIdFromContext; + } else { + return null; + } +}; diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts index d6dbe903a..1f9d4d8d0 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts @@ -1,6 +1,6 @@ import { useCallback } from 'react'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId'; @@ -17,7 +17,7 @@ export const useCloseAndResetViewPicker = () => { viewPickerIsPersistingComponentState, ); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const closeAndResetViewPicker = useCallback(() => { setViewPickerIsPersisting(false); diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdown.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdown.tsx index 35082df8c..80792b075 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdown.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdown.tsx @@ -1,6 +1,6 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; import { WorkflowVariablesDropdownFieldItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems'; @@ -51,7 +51,7 @@ export const WorkflowVariablesDropdown = ({ const isDropdownOpen = useRecoilValue( extractComponentState(isDropdownOpenComponentState, dropdownId), ); - const { closeDropdown } = useDropdownV2(); + const { closeDropdown } = useCloseDropdown(); const availableVariablesInWorkflowStep = useAvailableVariablesInWorkflowStep({ objectNameSingularToSelect, });