From 36c2b0e23b636131f8afceeaff3d4b0e103a1aca Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Thu, 19 Feb 2026 00:58:26 +0100 Subject: [PATCH] Migrate dropdown to jotai (#18063) Here we go again --- packages/twenty-front/.storybook/preview.tsx | 6 ++ .../RecordIndexActionMenuDropdown.stories.tsx | 76 ++++++++++--------- .../components/CommandMenuItemDropdown.tsx | 4 +- .../CurrentWorkspaceMemberFavorites.tsx | 3 +- ...rentWorkspaceMemberNavigationMenuItems.tsx | 3 +- .../components/ObjectOptionsDropdown.tsx | 4 +- .../components/ObjectSortDropdownButton.tsx | 3 +- ...ardColumnHeaderAggregateDropdownButton.tsx | 4 +- .../RecordDetailMorphRelationSection.tsx | 4 +- ...lMorphRelationSectionDropdownManyToOne.tsx | 4 +- ...lMorphRelationSectionDropdownOneToMany.tsx | 4 +- .../RecordDetailRelationRecordsListItem.tsx | 4 +- .../RecordDetailRelationSection.tsx | 4 +- ...ordDetailRelationSectionDropdownToMany.tsx | 4 +- ...cordDetailRelationSectionDropdownToOne.tsx | 4 +- .../components/FormArrayFieldInput.tsx | 4 +- .../components/MultiItemFieldMenuItem.tsx | 4 +- .../components/RecordInlineCell.tsx | 53 +++++++------ ...ordTableColumnAggregateFooterValueCell.tsx | 3 +- .../components/FieldWidgetInlineCell.tsx | 53 +++++++------ .../FieldWidgetRelationEditAction.tsx | 4 +- .../field/input/components/AddressInput.tsx | 4 +- .../PhoneCountryPickerDropdownButton.tsx | 4 +- .../layout/dropdown/components/Dropdown.tsx | 19 +++-- .../components/DropdownOnToggleEffect.tsx | 6 +- .../internal/DropdownInternalContainer.tsx | 18 +++-- .../useCloseAnyOpenDropdown.test.tsx | 29 ++++--- .../hooks/__tests__/useCloseDropdown.test.tsx | 47 ++++++++---- .../hooks/__tests__/useOpenDropdown.test.tsx | 47 ++++++++---- .../__tests__/useToggleDropdown.test.tsx | 47 ++++++++---- .../dropdown/hooks/useCloseAnyOpenDropdown.ts | 65 ++++++++-------- .../layout/dropdown/hooks/useCloseDropdown.ts | 59 +++++++------- .../useGoBackToPreviousDropdownFocusId.ts | 24 +++--- .../layout/dropdown/hooks/useOpenDropdown.ts | 69 +++++++++-------- ...SetFocusedDropdownIdAndMemorizePrevious.ts | 26 +++---- .../dropdown/hooks/useToggleDropdown.ts | 51 ++++++------- .../states/activeDropdownFocusIdState.ts | 4 +- .../states/dropdownPlacementComponentState.ts | 4 +- .../dropdownMaxHeightComponentState.ts | 4 +- .../dropdownMaxWidthComponentState.ts | 4 +- .../dropdownYPositionComponentState.ts | 4 +- .../states/isDropdownOpenComponentState.ts | 4 +- .../states/previousDropdownFocusIdState.ts | 4 +- .../jotai/hooks/useRecoilComponentStateV2.ts | 30 ++++++++ .../jotai/hooks/useRecoilComponentValueV2.ts | 27 +++++++ .../hooks/useSetRecoilComponentStateV2.ts | 27 +++++++ .../ui/utilities/state/jotai/jotaiStore.ts | 7 +- .../state/jotai/types/ComponentStateV2.ts | 15 ++++ .../jotai/utils/createComponentStateV2.ts | 50 ++++++++++++ .../views/components/ViewBarDetails.tsx | 3 +- .../views/components/ViewBarFilterButton.tsx | 4 +- .../ViewFieldsVisibleDropdownSection.tsx | 3 +- .../components/ViewPickerDropdown.tsx | 4 +- .../components/WorkflowVariablesDropdown.tsx | 4 +- 54 files changed, 599 insertions(+), 370 deletions(-) create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentStateV2.ts diff --git a/packages/twenty-front/.storybook/preview.tsx b/packages/twenty-front/.storybook/preview.tsx index 5d7257fc7a..6175fbda54 100644 --- a/packages/twenty-front/.storybook/preview.tsx +++ b/packages/twenty-front/.storybook/preview.tsx @@ -9,6 +9,8 @@ import { SOURCE_LOCALE } from 'twenty-shared/translations'; // eslint-disable-next-line no-restricted-imports import { RootDecorator } from '../src/testing/decorators/RootDecorator'; +// eslint-disable-next-line no-restricted-imports +import { resetJotaiStore } from '../src/modules/ui/utilities/state/jotai/jotaiStore'; import 'react-loading-skeleton/dist/skeleton.css'; import 'twenty-ui/style.css'; @@ -84,6 +86,10 @@ const preview: Preview = { RootDecorator, ], + beforeEach: () => { + resetJotaiStore(); + }, + loaders: [mswLoader], parameters: { diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx index a9ef722b7f..06071a46fc 100644 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx @@ -1,4 +1,5 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; +import { Provider as JotaiProvider } from 'jotai'; import { RecoilRoot } from 'recoil'; import * as test from 'storybook/test'; import { expect, userEvent, waitFor, within } from 'storybook/test'; @@ -10,6 +11,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { RouterDecorator } from 'twenty-ui/testing'; import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; @@ -21,44 +23,48 @@ const meta: Meta = { title: 'Modules/ActionMenu/RecordIndexActionMenuDropdown', component: RecordIndexActionMenuDropdown, decorators: [ - (Story) => ( - { - set( - recordIndexActionMenuDropdownPositionComponentState.atomFamily({ - instanceId: 'action-menu-dropdown-story', - }), - { x: 10, y: 10 }, - ); + (Story) => { + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ + instanceId: 'action-menu-dropdown-story-action-menu', + }), + true, + ); - set( - isDropdownOpenComponentState.atomFamily({ - instanceId: 'action-menu-dropdown-story-action-menu', - }), - true, - ); - }} - > - - + { + set( + recordIndexActionMenuDropdownPositionComponentState.atomFamily({ + instanceId: 'action-menu-dropdown-story', + }), + { x: 10, y: 10 }, + ); }} > - - - - - ), + + + + + + + + ); + }, ContextStoreDecorator, RouterDecorator, ], diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuItemDropdown.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuItemDropdown.tsx index 5d59652e6c..32737107f7 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuItemDropdown.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuItemDropdown.tsx @@ -9,7 +9,7 @@ import { } from '@/ui/layout/dropdown/components/Dropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export type CommandMenuItemDropdownProps = CommandMenuItemProps & Pick< @@ -31,7 +31,7 @@ export const CommandMenuItemDropdown = ({ dropdownId, disabled = false, }: CommandMenuItemDropdownProps) => { - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx index 34d515cf65..1f0a8dee96 100644 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx +++ b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx @@ -26,6 +26,7 @@ import { currentFavoriteFolderIdStateV2 } from '@/ui/navigation/navigation-drawe import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { Droppable } from '@hello-pangea/dnd'; import { useLingui } from '@lingui/react/macro'; import { useContext, useState } from 'react'; @@ -95,7 +96,7 @@ export const CurrentWorkspaceMemberFavorites = ({ const dropdownId = `favorite-folder-edit-${folder.folderId}`; - const isDropdownOpenComponent = useRecoilComponentValue( + const isDropdownOpenComponent = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItems.tsx b/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItems.tsx index 5e9d300b48..4f6883d433 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItems.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItems.tsx @@ -45,6 +45,7 @@ import { currentNavigationMenuItemFolderIdStateV2 } from '@/ui/navigation/naviga import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isNonEmptyString } from '@sniptt/guards'; import { isDefined } from 'twenty-shared/utils'; @@ -123,7 +124,7 @@ export const CurrentWorkspaceMemberNavigationMenuItems = ({ const dropdownId = `navigation-menu-item-folder-edit-${folder.id}`; - const isDropdownOpenComponent = useRecoilComponentValue( + const isDropdownOpenComponent = useRecoilComponentValueV2( isDropdownOpenComponentState, 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 ffab19c832..1dc4b667af 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 @@ -10,7 +10,7 @@ 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 { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type ViewType } from '@/views/types/ViewType'; import { Trans } from '@lingui/react/macro'; @@ -28,7 +28,7 @@ export const ObjectOptionsDropdown = ({ const { currentContentId, handleContentChange, handleResetContent } = useDropdownContextCurrentContentId(); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, OBJECT_OPTIONS_DROPDOWN_ID, ); diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx index 78f85c980e..0267823512 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx @@ -27,6 +27,7 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { Trans, useLingui } from '@lingui/react/macro'; import { useRecoilValue } from 'recoil'; @@ -138,7 +139,7 @@ export const ObjectSortDropdownButton = () => { setIsRecordSortDirectionMenuUnfolded(false); }; - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, OBJECT_SORT_DROPDOWN_ID, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownButton.tsx index 11468e7e1a..8f0b17343f 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownButton.tsx @@ -1,6 +1,6 @@ import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { type Nullable } from 'twenty-shared/types'; import { Tag } from 'twenty-ui/components'; @@ -23,7 +23,7 @@ export const RecordBoardColumnHeaderAggregateDropdownButton = ({ value?: Nullable; tooltip?: Nullable; }) => { - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSection.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSection.tsx index 7b1fa15390..54c49925e5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSection.tsx @@ -12,7 +12,7 @@ import { type FieldMorphRelationMetadata } from '@/object-record/record-field/ui import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { RecordDetailMorphRelationSectionDropdown } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdown'; import { RecordDetailRelationRecordsList } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsList'; @@ -49,7 +49,7 @@ export const RecordDetailMorphRelationSection = ({ instanceId: scopeInstanceId, }); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx index 68778c7f0f..81f24fd403 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx @@ -16,7 +16,7 @@ import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/reco import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -65,7 +65,7 @@ export const RecordDetailMorphRelationSectionDropdownManyToOne = ({ const { closeDropdown } = useCloseDropdown(); - const dropdownPlacement = useRecoilComponentValue( + const dropdownPlacement = useRecoilComponentValueV2( dropdownPlacementComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx index e0b2413058..29e408ed5b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx @@ -18,7 +18,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { FieldMetadataType } from 'twenty-shared/types'; import { CustomError, isDefined } from 'twenty-shared/utils'; @@ -68,7 +68,7 @@ export const RecordDetailMorphRelationSectionDropdownOneToMany = ({ const { closeDropdown } = useCloseDropdown(); - const dropdownPlacement = useRecoilComponentValue( + const dropdownPlacement = useRecoilComponentValueV2( dropdownPlacementComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx index 3f092cb56c..a9247ed34b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx @@ -28,7 +28,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { t } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; @@ -152,7 +152,7 @@ export const RecordDetailRelationRecordsListItem = ({ const dropdownInstanceId = `record-field-card-menu:${scopeInstanceId}:${relationFieldMetadataId}:${relationRecord.id}`; const { closeDropdown } = useCloseDropdown(); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx index e6069f2498..09e2a8f4f4 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx @@ -21,7 +21,7 @@ import { AggregateOperations } from '@/object-record/record-table/constants/Aggr import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; import { useLingui } from '@lingui/react/macro'; import { @@ -100,7 +100,7 @@ export const RecordDetailRelationSection = ({ instanceId: scopeInstanceId, }); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx index 1056af8c8a..a233f8dc2d 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx @@ -21,7 +21,7 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { CustomError, isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; @@ -85,7 +85,7 @@ export const RecordDetailRelationSectionDropdownToMany = ({ const { closeDropdown } = useCloseDropdown(); - const dropdownPlacement = useRecoilComponentValue( + const dropdownPlacement = useRecoilComponentValueV2( dropdownPlacementComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx index 1d071e0095..a24cbc614a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx @@ -18,7 +18,7 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; @@ -96,7 +96,7 @@ export const RecordDetailRelationSectionDropdownToOne = ({ const { closeDropdown } = useCloseDropdown(); - const dropdownPlacement = useRecoilComponentValue( + const dropdownPlacement = useRecoilComponentValueV2( dropdownPlacementComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormArrayFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormArrayFieldInput.tsx index 724577eb5e..e4c2d963ca 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormArrayFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormArrayFieldInput.tsx @@ -20,7 +20,7 @@ import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDrop 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 { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; @@ -128,7 +128,7 @@ export const FormArrayFieldInput = ({ const containerRef = useRef(null); const dropdownId = `dropdown-${instanceId}`; - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldMenuItem.tsx index 92de2a5eed..9467f95ace 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldMenuItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldMenuItem.tsx @@ -4,7 +4,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { MenuItemWithOptionDropdown } from '@/ui/navigation/menu-item/components/MenuItemWithOptionDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import React, { useState } from 'react'; import { IconBookmark, @@ -44,7 +44,7 @@ export const MultiItemFieldMenuItem = ({ }: MultiItemFieldMenuItemProps) => { const [isHovered, setIsHovered] = useState(false); const { closeDropdown } = useCloseDropdown(); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx index 0854003248..79f0583c66 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx @@ -19,7 +19,7 @@ import { usePersistFieldFromFieldInputContext } from '@/object-record/record-fie import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField'; import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { useIcons } from 'twenty-ui/display'; import { RecordInlineCellContainer } from './RecordInlineCellContainer'; import { @@ -133,37 +133,36 @@ export const RecordInlineCell = ({ closeInlineCell(); }; - const handleClickOutside = useRecoilCallback( - ({ snapshot }) => - ({ - event, - newValue, - skipPersist, - }: Parameters[0]) => { - const currentDropdownFocusId = snapshot - .getLoadable(activeDropdownFocusIdState) - .getValue(); + const handleClickOutside = useCallback( + ({ + event, + newValue, + skipPersist, + }: Parameters[0]) => { + const currentDropdownFocusId = jotaiStore.get( + activeDropdownFocusIdState.atom, + ); - const expectedDropdownFocusId = getDropdownFocusIdForRecordField({ - recordId, - fieldMetadataId: fieldDefinition.fieldMetadataId, - componentType: 'inline-cell', - instanceId: scopeInstanceId, - }); + const expectedDropdownFocusId = getDropdownFocusIdForRecordField({ + recordId, + fieldMetadataId: fieldDefinition.fieldMetadataId, + componentType: 'inline-cell', + instanceId: scopeInstanceId, + }); - if (currentDropdownFocusId !== expectedDropdownFocusId) { - return; - } + if (currentDropdownFocusId !== expectedDropdownFocusId) { + return; + } - event?.preventDefault(); - event?.stopImmediatePropagation(); + event?.preventDefault(); + event?.stopImmediatePropagation(); - if (skipPersist !== true) { - persistFieldFromFieldInputContext(newValue); - } + if (skipPersist !== true) { + persistFieldFromFieldInputContext(newValue); + } - closeInlineCell(); - }, + closeInlineCell(); + }, [ recordId, fieldDefinition.fieldMetadataId, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx index d2d8b5ef73..86db833b3f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx @@ -6,6 +6,7 @@ import { RecordTableColumnAggregateFooterValue } from '@/object-record/record-ta import { hasAggregateOperationForViewFieldFamilySelector } from '@/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useContext, useState } from 'react'; @@ -57,7 +58,7 @@ export const RecordTableColumnAggregateFooterValueCell = ({ }) => { const [isHovered, setIsHovered] = useState(false); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCell.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCell.tsx index b516055772..7175c0e1b1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCell.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCell.tsx @@ -24,7 +24,7 @@ import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropd import { FieldWidgetInlineCellContainer } from '@/page-layout/widgets/field/components/FieldWidgetInlineCellContainer'; import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; type FieldWidgetInlineCellProps = { loading?: boolean; @@ -132,37 +132,36 @@ export const FieldWidgetInlineCell = ({ closeInlineCell(); }; - const handleClickOutside = useRecoilCallback( - ({ snapshot }) => - ({ - event, - newValue, - skipPersist, - }: Parameters[0]) => { - const currentDropdownFocusId = snapshot - .getLoadable(activeDropdownFocusIdState) - .getValue(); + const handleClickOutside = useCallback( + ({ + event, + newValue, + skipPersist, + }: Parameters[0]) => { + const currentDropdownFocusId = jotaiStore.get( + activeDropdownFocusIdState.atom, + ); - const expectedDropdownFocusId = getDropdownFocusIdForRecordField({ - recordId, - fieldMetadataId: fieldDefinition.fieldMetadataId, - componentType: 'inline-cell', - instanceId: scopeInstanceId, - }); + const expectedDropdownFocusId = getDropdownFocusIdForRecordField({ + recordId, + fieldMetadataId: fieldDefinition.fieldMetadataId, + componentType: 'inline-cell', + instanceId: scopeInstanceId, + }); - if (currentDropdownFocusId !== expectedDropdownFocusId) { - return; - } + if (currentDropdownFocusId !== expectedDropdownFocusId) { + return; + } - event?.preventDefault(); - event?.stopImmediatePropagation(); + event?.preventDefault(); + event?.stopImmediatePropagation(); - if (skipPersist !== true) { - persistFieldFromFieldInputContext(newValue); - } + if (skipPersist !== true) { + persistFieldFromFieldInputContext(newValue); + } - closeInlineCell(); - }, + closeInlineCell(); + }, [ closeInlineCell, recordId, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx index ec50335a86..cedc1c56fe 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx @@ -20,7 +20,7 @@ import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guar import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { CustomError } from 'twenty-shared/utils'; @@ -99,7 +99,7 @@ export const FieldWidgetRelationEditAction = ({ instanceId: scopeInstanceId, }); - const isRelationSelectionDropdownOpen = useRecoilComponentValue( + const isRelationSelectionDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, relationSelectionDropdownId, ); diff --git a/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx index 5250d2f673..b788bf5292 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx @@ -13,7 +13,7 @@ import { SELECT_COUNTRY_DROPDOWN_ID } from '@/ui/input/components/internal/count import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; import { v4 } from 'uuid'; @@ -236,7 +236,7 @@ export const AddressInput = ({ onShiftTab: handleShiftTab, }); - const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState); + const activeDropdownFocusId = useRecoilValueV2(activeDropdownFocusIdState); useListenClickOutside({ refs: [wrapperRef], diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx index abe4ed272a..7d71264bee 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx @@ -10,7 +10,7 @@ import { PhoneCountryPickerDropdownSelect } from './PhoneCountryPickerDropdownSe import { PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID } from '@/ui/input/components/internal/phone/constants/PhoneCountryCodePickerDropdownId'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import 'react-phone-number-input/style.css'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronDown, IconWorld } from 'twenty-ui/display'; @@ -78,7 +78,7 @@ export const PhoneCountryPickerDropdownButton = ({ const [selectedCountry, setSelectedCountry] = useState(); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID, ); 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 a64aed1ab7..1e2cbd4011 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 @@ -13,8 +13,8 @@ import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/int import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset'; import { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { type Placement, @@ -24,10 +24,9 @@ import { size, useFloating, } from '@floating-ui/react'; -import { type MouseEvent, type ReactNode } from 'react'; +import { type MouseEvent, type ReactNode, useCallback } from 'react'; import { flushSync } from 'react-dom'; import { type Keys } from 'react-hotkeys-hook'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { useIsMobile } from 'twenty-ui/utilities'; @@ -89,7 +88,7 @@ export const Dropdown = ({ disableClickForClickableComponent = false, middlewareBoundaryPadding = {}, }: DropdownProps) => { - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); @@ -108,17 +107,17 @@ export const Dropdown = ({ ] : []; - const setDropdownMaxHeight = useSetRecoilComponentState( + const setDropdownMaxHeight = useSetRecoilComponentStateV2( dropdownMaxHeightComponentState, dropdownId, ); - const setDropdownMaxWidth = useSetRecoilComponentState( + const setDropdownMaxWidth = useSetRecoilComponentStateV2( dropdownMaxWidthComponentState, dropdownId, ); - const setDropdownYPosition = useSetRecoilComponentState( + const setDropdownYPosition = useSetRecoilComponentStateV2( dropdownYPositionComponentState, dropdownId, ); @@ -173,8 +172,8 @@ export const Dropdown = ({ strategy: dropdownStrategy, }); - const handleClickableComponentClick = useRecoilCallback( - () => async (event: MouseEvent) => { + const handleClickableComponentClick = useCallback( + async (event: MouseEvent) => { if (disableClickForClickableComponent) return; event.stopPropagation(); event.preventDefault(); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownOnToggleEffect.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownOnToggleEffect.tsx index 1cd362c791..6a451e3a77 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownOnToggleEffect.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownOnToggleEffect.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const DropdownOnToggleEffect = ({ onDropdownClose, @@ -10,7 +10,9 @@ export const DropdownOnToggleEffect = ({ onDropdownClose?: () => void; onDropdownOpen?: () => void; }) => { - const isDropdownOpen = useRecoilComponentValue(isDropdownOpenComponentState); + const isDropdownOpen = useRecoilComponentValueV2( + isDropdownOpenComponentState, + ); const [currentIsDropdownOpen, setCurrentIsDropdownOpen] = useState(isDropdownOpen); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx index 581f988344..8f1a160e0d 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx @@ -11,8 +11,9 @@ import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { FloatingPortal, @@ -21,7 +22,6 @@ import { } from '@floating-ui/react'; import { useContext, useEffect } from 'react'; import { type Keys } from 'react-hotkeys-hook'; -import { useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; export const StyledDropdownContentContainer = styled.div<{ @@ -70,23 +70,25 @@ export const DropdownInternalContainer = ({ excludedClickOutsideIds, isDropdownInModal = false, }: DropdownInternalContainerProps) => { - const isDropdownOpen = useRecoilComponentValue(isDropdownOpenComponentState); + const isDropdownOpen = useRecoilComponentValueV2( + isDropdownOpenComponentState, + ); const { closeDropdown } = useCloseDropdown(); - const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState); + const activeDropdownFocusId = useRecoilValueV2(activeDropdownFocusIdState); - const dropdownMaxHeight = useRecoilComponentValue( + const dropdownMaxHeight = useRecoilComponentValueV2( dropdownMaxHeightComponentState, dropdownId, ); - const dropdownMaxWidth = useRecoilComponentValue( + const dropdownMaxWidth = useRecoilComponentValueV2( dropdownMaxWidthComponentState, dropdownId, ); - const setDropdownPlacement = useSetRecoilComponentState( + const setDropdownPlacement = useSetRecoilComponentStateV2( dropdownPlacementComponentState, dropdownId, ); 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 2c4587bf26..08f45a9e15 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 @@ -1,4 +1,5 @@ import { renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { act } from 'react'; import { RecoilRoot } from 'recoil'; @@ -6,27 +7,37 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/ import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; const dropdownId = 'test-dropdown-id'; const Wrapper = ({ children }: { children: React.ReactNode }) => { return ( - - - {children} - - + + + + {children} + + + ); }; describe('useCloseAnyOpenDropdown', () => { + beforeEach(() => { + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }), + false, + ); + }); + it('should open dropdown and then close it with closeAnyOpenDropdown', async () => { const { result } = renderHook( () => { - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdown.test.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdown.test.tsx index 1e0b62a47d..fc0480e23f 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdown.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useCloseDropdown.test.tsx @@ -1,4 +1,5 @@ import { renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { act } from 'react'; import { RecoilRoot } from 'recoil'; @@ -6,36 +7,52 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/ 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 { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; const dropdownId = 'test-dropdown-id'; const outsideDropdownId = 'test-dropdown-id-outside'; const Wrapper = ({ children }: { children: React.ReactNode }) => { return ( - - - {children} - - - + + + + {children} + + + + ); }; describe('useCloseDropdown', () => { + beforeEach(() => { + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }), + false, + ); + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ + instanceId: outsideDropdownId, + }), + false, + ); + }); + it('should close dropdown from inside component instance context', async () => { const { result } = renderHook( () => { - const isOutsideDropdownOpen = useRecoilComponentValue( + const isOutsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, outsideDropdownId, ); - const isInsideDropdownOpen = useRecoilComponentValue( + const isInsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ); @@ -72,12 +89,12 @@ describe('useCloseDropdown', () => { it('should close dropdown from outside component instance context', async () => { const { result } = renderHook( () => { - const isOutsideDropdownOpen = useRecoilComponentValue( + const isOutsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, outsideDropdownId, ); - const isInsideDropdownOpen = useRecoilComponentValue( + const isInsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useOpenDropdown.test.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useOpenDropdown.test.tsx index 847e5e9fd1..29c043dae5 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useOpenDropdown.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useOpenDropdown.test.tsx @@ -1,40 +1,57 @@ import { renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { act } from 'react'; import { RecoilRoot } from 'recoil'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; const dropdownId = 'test-dropdown-id'; const outsideDropdownId = 'test-dropdown-id-outside'; const Wrapper = ({ children }: { children: React.ReactNode }) => { return ( - - - {children} - - - + + + + {children} + + + + ); }; describe('useOpenDropdown', () => { + beforeEach(() => { + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }), + false, + ); + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ + instanceId: outsideDropdownId, + }), + false, + ); + }); + it('should open dropdown from inside component instance context', async () => { const { result } = renderHook( () => { - const isOutsideDropdownOpen = useRecoilComponentValue( + const isOutsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, outsideDropdownId, ); - const isInsideDropdownOpen = useRecoilComponentValue( + const isInsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ); @@ -61,12 +78,12 @@ describe('useOpenDropdown', () => { it('should open dropdown from outside component instance context', async () => { const { result } = renderHook( () => { - const isOutsideDropdownOpen = useRecoilComponentValue( + const isOutsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, outsideDropdownId, ); - const isInsideDropdownOpen = useRecoilComponentValue( + const isInsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useToggleDropdown.test.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useToggleDropdown.test.tsx index e25a98fa41..3042ae7d21 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useToggleDropdown.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/__tests__/useToggleDropdown.test.tsx @@ -1,40 +1,57 @@ import { renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { act } from 'react'; import { RecoilRoot } from 'recoil'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; const dropdownId = 'test-dropdown-id'; const outsideDropdownId = 'test-dropdown-id-outside'; const Wrapper = ({ children }: { children: React.ReactNode }) => { return ( - - - {children} - - - + + + + {children} + + + + ); }; describe('useToggleDropdown', () => { + beforeEach(() => { + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }), + false, + ); + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ + instanceId: outsideDropdownId, + }), + false, + ); + }); + it('should toggle dropdown from inside component instance context', async () => { const { result } = renderHook( () => { - const isOutsideDropdownOpen = useRecoilComponentValue( + const isOutsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, outsideDropdownId, ); - const isInsideDropdownOpen = useRecoilComponentValue( + const isInsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ); const { toggleDropdown } = useToggleDropdown(); @@ -74,12 +91,12 @@ describe('useToggleDropdown', () => { it('should toggle dropdown from outside component instance context', async () => { const { result } = renderHook( () => { - const isOutsideDropdownOpen = useRecoilComponentValue( + const isOutsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, outsideDropdownId, ); - const isInsideDropdownOpen = useRecoilComponentValue( + const isInsideDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ); const { toggleDropdown } = useToggleDropdown(); 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 724d0b70f1..f0e020db1e 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,8 +1,10 @@ +import { useCallback } from 'react'; + 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'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isDefined } from 'twenty-shared/utils'; export const useCloseAnyOpenDropdown = () => { @@ -11,46 +13,41 @@ export const useCloseAnyOpenDropdown = () => { const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const closeAnyOpenDropdown = useRecoilCallback( - ({ snapshot, set }) => - () => { - const previousDropdownFocusId = snapshot - .getLoadable(previousDropdownFocusIdState) - .getValue(); + const closeAnyOpenDropdown = useCallback(() => { + const previousDropdownFocusId = jotaiStore.get( + previousDropdownFocusIdState.atom, + ); - const activeDropdownFocusId = snapshot - .getLoadable(activeDropdownFocusIdState) - .getValue(); + const activeDropdownFocusId = jotaiStore.get( + activeDropdownFocusIdState.atom, + ); - const thereIsNoDropdownOpen = - !isDefined(activeDropdownFocusId) && - !isDefined(previousDropdownFocusId); + const thereIsNoDropdownOpen = + !isDefined(activeDropdownFocusId) && !isDefined(previousDropdownFocusId); - if (thereIsNoDropdownOpen) { - return; - } + if (thereIsNoDropdownOpen) { + return; + } - const thereIsOneNestedDropdownOpen = isDefined(previousDropdownFocusId); + const thereIsOneNestedDropdownOpen = isDefined(previousDropdownFocusId); - if (isDefined(activeDropdownFocusId)) { - closeDropdown(activeDropdownFocusId); - removeFocusItemFromFocusStackById({ - focusId: activeDropdownFocusId, - }); - } + if (isDefined(activeDropdownFocusId)) { + closeDropdown(activeDropdownFocusId); + removeFocusItemFromFocusStackById({ + focusId: activeDropdownFocusId, + }); + } - if (thereIsOneNestedDropdownOpen) { - closeDropdown(previousDropdownFocusId); - removeFocusItemFromFocusStackById({ - focusId: previousDropdownFocusId, - }); - } + if (thereIsOneNestedDropdownOpen) { + closeDropdown(previousDropdownFocusId); + removeFocusItemFromFocusStackById({ + focusId: previousDropdownFocusId, + }); + } - set(previousDropdownFocusIdState, null); - set(activeDropdownFocusIdState, null); - }, - [closeDropdown, removeFocusItemFromFocusStackById], - ); + jotaiStore.set(previousDropdownFocusIdState.atom, null); + jotaiStore.set(activeDropdownFocusIdState.atom, null); + }, [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 index a1b55c1456..d002b6b394 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdown.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useCloseDropdown.ts @@ -1,10 +1,12 @@ +import { useCallback } from 'react'; + 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 { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isDefined } from 'twenty-shared/utils'; export const useCloseDropdown = () => { @@ -17,40 +19,37 @@ export const useCloseDropdown = () => { const dropdownComponentInstanceIdFromContext = useAvailableComponentInstanceId(DropdownComponentInstanceContext); - const closeDropdown = useRecoilCallback( - ({ set, snapshot }) => - (dropdownComponentInstanceIdFromProps?: string) => { - const dropdownComponentInstanceId = - dropdownComponentInstanceIdFromProps ?? - dropdownComponentInstanceIdFromContext; + const closeDropdown = useCallback( + (dropdownComponentInstanceIdFromProps?: string) => { + const dropdownComponentInstanceId = + dropdownComponentInstanceIdFromProps ?? + dropdownComponentInstanceIdFromContext; - if (!isDefined(dropdownComponentInstanceId)) { - throw new Error('Dropdown component instance ID is not defined'); - } + if (!isDefined(dropdownComponentInstanceId)) { + throw new Error('Dropdown component instance ID is not defined'); + } - const isDropdownOpen = snapshot - .getLoadable( - isDropdownOpenComponentState.atomFamily({ - instanceId: dropdownComponentInstanceId, - }), - ) - .getValue(); + const isDropdownOpen = jotaiStore.get( + isDropdownOpenComponentState.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + ); - if (isDropdownOpen) { - removeFocusItemFromFocusStackById({ - focusId: dropdownComponentInstanceId, - }); + if (isDropdownOpen) { + removeFocusItemFromFocusStackById({ + focusId: dropdownComponentInstanceId, + }); - goBackToPreviousDropdownFocusId(); + goBackToPreviousDropdownFocusId(); - set( - isDropdownOpenComponentState.atomFamily({ - instanceId: dropdownComponentInstanceId, - }), - false, - ); - } - }, + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + false, + ); + } + }, [ removeFocusItemFromFocusStackById, goBackToPreviousDropdownFocusId, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId.ts index 157aaf5add..bb82d2689b 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId.ts @@ -1,22 +1,22 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState'; import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; // TODO: this won't work for more than 1 nested dropdown export const useGoBackToPreviousDropdownFocusId = () => { - const goBackToPreviousDropdownFocusId = useRecoilCallback( - ({ snapshot, set }) => - () => { - const previouslyFocusedDropdownId = snapshot - .getLoadable(previousDropdownFocusIdState) - .getValue(); + const goBackToPreviousDropdownFocusId = useCallback(() => { + const previouslyFocusedDropdownId = jotaiStore.get( + previousDropdownFocusIdState.atom, + ); - set(activeDropdownFocusIdState, previouslyFocusedDropdownId); - set(previousDropdownFocusIdState, null); - }, - [], - ); + jotaiStore.set( + activeDropdownFocusIdState.atom, + previouslyFocusedDropdownId, + ); + jotaiStore.set(previousDropdownFocusIdState.atom, null); + }, []); return { goBackToPreviousDropdownFocusId, 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 index f60ccbb973..2631c4ce86 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useOpenDropdown.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useOpenDropdown.ts @@ -1,3 +1,5 @@ +import { useCallback } from 'react'; + import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; @@ -6,7 +8,7 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isDefined } from 'twenty-shared/utils'; type OpenDropdownArgs = { @@ -22,44 +24,41 @@ export const useOpenDropdown = () => { const dropdownComponentInstanceIdFromContext = useAvailableComponentInstanceId(DropdownComponentInstanceContext); - const openDropdown = useRecoilCallback( - ({ set }) => - (args?: OpenDropdownArgs | null | undefined) => { - const dropdownComponentInstanceId = - args?.dropdownComponentInstanceIdFromProps ?? - dropdownComponentInstanceIdFromContext; + const openDropdown = useCallback( + (args?: OpenDropdownArgs | null | undefined) => { + const dropdownComponentInstanceId = + args?.dropdownComponentInstanceIdFromProps ?? + dropdownComponentInstanceIdFromContext; - if (!isDefined(dropdownComponentInstanceId)) { - throw new Error('Dropdown component instance ID is not defined'); - } + if (!isDefined(dropdownComponentInstanceId)) { + throw new Error('Dropdown component instance ID is not defined'); + } - set( - isDropdownOpenComponentState.atomFamily({ - instanceId: dropdownComponentInstanceId, - }), - true, - ); + jotaiStore.set( + isDropdownOpenComponentState.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + true, + ); - setActiveDropdownFocusIdAndMemorizePrevious( - dropdownComponentInstanceId, - ); + setActiveDropdownFocusIdAndMemorizePrevious(dropdownComponentInstanceId); - pushFocusItemToFocusStack({ - focusId: dropdownComponentInstanceId, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: dropdownComponentInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: - args?.globalHotkeysConfig - ?.enableGlobalHotkeysConflictingWithKeyboard ?? false, - enableGlobalHotkeysWithModifiers: - args?.globalHotkeysConfig?.enableGlobalHotkeysWithModifiers ?? - false, - }, - }); - }, + pushFocusItemToFocusStack({ + focusId: dropdownComponentInstanceId, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: dropdownComponentInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: + args?.globalHotkeysConfig + ?.enableGlobalHotkeysConflictingWithKeyboard ?? false, + enableGlobalHotkeysWithModifiers: + args?.globalHotkeysConfig?.enableGlobalHotkeysWithModifiers ?? + false, + }, + }); + }, [ pushFocusItemToFocusStack, setActiveDropdownFocusIdAndMemorizePrevious, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious.ts index 2a3bf9dc88..53b000deff 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious.ts @@ -1,23 +1,23 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState'; import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; export const useSetActiveDropdownFocusIdAndMemorizePrevious = () => { - const setActiveDropdownFocusIdAndMemorizePrevious = useRecoilCallback( - ({ snapshot, set }) => - (dropdownId: string | null) => { - const activeDropdownFocusId = snapshot - .getLoadable(activeDropdownFocusIdState) - .getValue(); + const setActiveDropdownFocusIdAndMemorizePrevious = useCallback( + (dropdownId: string | null) => { + const activeDropdownFocusId = jotaiStore.get( + activeDropdownFocusIdState.atom, + ); - if (activeDropdownFocusId === dropdownId) { - return; - } + if (activeDropdownFocusId === dropdownId) { + return; + } - set(previousDropdownFocusIdState, activeDropdownFocusId); - set(activeDropdownFocusIdState, dropdownId); - }, + jotaiStore.set(previousDropdownFocusIdState.atom, activeDropdownFocusId); + jotaiStore.set(activeDropdownFocusIdState.atom, dropdownId); + }, [], ); 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 index bb6e479ebf..d58b5cb58d 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useToggleDropdown.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/hooks/useToggleDropdown.ts @@ -1,10 +1,12 @@ +import { useCallback } from 'react'; + 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 { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isDefined } from 'twenty-shared/utils'; type ToggleDropdownArgs = { @@ -19,34 +21,31 @@ export const useToggleDropdown = () => { const { openDropdown } = useOpenDropdown(); const { closeDropdown } = useCloseDropdown(); - const toggleDropdown = useRecoilCallback( - ({ snapshot }) => - (args?: ToggleDropdownArgs | null | undefined) => { - const dropdownComponentInstanceId = - args?.dropdownComponentInstanceIdFromProps ?? - dropdownComponentInstanceIdFromContext; + const toggleDropdown = useCallback( + (args?: ToggleDropdownArgs | null | undefined) => { + const dropdownComponentInstanceId = + args?.dropdownComponentInstanceIdFromProps ?? + dropdownComponentInstanceIdFromContext; - if (!isDefined(dropdownComponentInstanceId)) { - throw new Error('Dropdown component instance ID is not defined'); - } + if (!isDefined(dropdownComponentInstanceId)) { + throw new Error('Dropdown component instance ID is not defined'); + } - const isDropdownOpen = snapshot - .getLoadable( - isDropdownOpenComponentState.atomFamily({ - instanceId: dropdownComponentInstanceId, - }), - ) - .getValue(); + const isDropdownOpen = jotaiStore.get( + isDropdownOpenComponentState.atomFamily({ + instanceId: dropdownComponentInstanceId, + }), + ); - if (isDropdownOpen) { - closeDropdown(dropdownComponentInstanceId); - } else { - openDropdown({ - dropdownComponentInstanceIdFromProps: dropdownComponentInstanceId, - globalHotkeysConfig: args?.globalHotkeysConfig, - }); - } - }, + if (isDropdownOpen) { + closeDropdown(dropdownComponentInstanceId); + } else { + openDropdown({ + dropdownComponentInstanceIdFromProps: dropdownComponentInstanceId, + globalHotkeysConfig: args?.globalHotkeysConfig, + }); + } + }, [closeDropdown, openDropdown, dropdownComponentInstanceIdFromContext], ); 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 b3462de685..23fbdfb283 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,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const activeDropdownFocusIdState = createState({ +export const activeDropdownFocusIdState = createStateV2({ key: 'activeDropdownFocusIdState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/dropdownPlacementComponentState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/dropdownPlacementComponentState.ts index 4fcc03fda2..06fb55bc28 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/dropdownPlacementComponentState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/dropdownPlacementComponentState.ts @@ -1,10 +1,10 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type Placement } from '@floating-ui/react'; export const dropdownPlacementComponentState = - createComponentState({ + createComponentStateV2({ key: 'dropdownPlacementComponentState', componentInstanceContext: DropdownComponentInstanceContext, 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 840c9d88b3..6edc2856f2 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,7 +1,7 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const dropdownMaxHeightComponentState = createComponentState< +export const dropdownMaxHeightComponentState = createComponentStateV2< number | undefined >({ key: 'dropdownMaxHeightComponentState', 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 e6276bc0d1..56c671e034 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,7 +1,7 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const dropdownMaxWidthComponentState = createComponentState< +export const dropdownMaxWidthComponentState = createComponentStateV2< number | undefined >({ key: 'dropdownMaxWidthComponentState', diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts index ef3a5626e1..49741a9ce6 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/states/internal/dropdownYPositionComponentState.ts @@ -1,7 +1,7 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const dropdownYPositionComponentState = createComponentState< +export const dropdownYPositionComponentState = createComponentStateV2< number | undefined >({ key: 'dropdownYPositionComponentState', 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 2e894b6640..abc068d920 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,7 +1,7 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const isDropdownOpenComponentState = createComponentState({ +export const isDropdownOpenComponentState = createComponentStateV2({ key: 'isDropdownOpenComponentState', 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 7570f193bd..9131957c46 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,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const previousDropdownFocusIdState = createState({ +export const previousDropdownFocusIdState = createStateV2({ key: 'previousDropdownFocusIdState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2.ts new file mode 100644 index 0000000000..2ef21b8283 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2.ts @@ -0,0 +1,30 @@ +import { useAtom } from 'jotai'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; + +export const useRecoilComponentStateV2 = ( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +): [ + StateType, + (value: StateType | ((prev: StateType) => StateType)) => void, +] => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useAtom(componentState.atomFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2.ts new file mode 100644 index 0000000000..cc9b345949 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2.ts @@ -0,0 +1,27 @@ +import { useAtomValue } from 'jotai'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; + +export const useRecoilComponentValueV2 = ( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +): StateType => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useAtomValue(componentState.atomFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2.ts new file mode 100644 index 0000000000..48ee152c8d --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2.ts @@ -0,0 +1,27 @@ +import { useSetAtom } from 'jotai'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; + +export const useSetRecoilComponentStateV2 = ( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +): ((value: ValueType | ((prev: ValueType) => ValueType)) => void) => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useSetAtom(componentState.atomFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/jotaiStore.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/jotaiStore.ts index cc3298ce1c..0e67b8747b 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/jotaiStore.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/jotaiStore.ts @@ -1,3 +1,8 @@ import { createStore } from 'jotai'; -export const jotaiStore = createStore(); +export let jotaiStore = createStore(); + +export const resetJotaiStore = () => { + jotaiStore = createStore(); + return jotaiStore; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentStateV2.ts new file mode 100644 index 0000000000..f1623843f3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentStateV2.ts @@ -0,0 +1,15 @@ +import { type WritableAtom } from 'jotai'; + +import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; + +type JotaiWritableAtom = WritableAtom< + ValueType, + [ValueType | ((prev: ValueType) => ValueType)], + void +>; + +export type ComponentStateV2 = { + type: 'ComponentStateV2'; + key: string; + atomFamily: (key: ComponentStateKey) => JotaiWritableAtom; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentStateV2.ts new file mode 100644 index 0000000000..dbc2ef2cfe --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentStateV2.ts @@ -0,0 +1,50 @@ +import { atom } from 'jotai'; + +import { type ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; +import { isDefined } from 'twenty-shared/utils'; + +export const createComponentStateV2 = ({ + key, + defaultValue, + componentInstanceContext, +}: { + key: string; + defaultValue: ValueType; + componentInstanceContext: ComponentInstanceStateContext | null; +}): ComponentStateV2 => { + if (isDefined(componentInstanceContext)) { + globalComponentInstanceContextMap.set(key, componentInstanceContext); + } + + const atomCache = new Map< + string, + ReturnType['atomFamily']> + >(); + + const familyFunction = ({ + instanceId, + }: ComponentStateKey): ReturnType< + ComponentStateV2['atomFamily'] + > => { + const existing = atomCache.get(instanceId); + + if (existing !== undefined) { + return existing; + } + + const baseAtom = atom(defaultValue); + baseAtom.debugLabel = `${key}__${instanceId}`; + atomCache.set(instanceId, baseAtom); + + return baseAtom; + }; + + return { + type: 'ComponentStateV2', + key, + atomFamily: familyFunction, + }; +}; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index 932d80a3e9..a626d07190 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -5,6 +5,7 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObje import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { AdvancedFilterDropdownButton } from '@/views/advanced-filter-chip/components/AdvancedFilterDropdownButton'; import { ViewBarDetailsAddFilterButton } from '@/views/components/ViewBarDetailsAddFilterButton'; import { EditableSortChip } from '@/views/editable-chip/components/EditableSortChip'; @@ -185,7 +186,7 @@ export const ViewBarDetails = ({ const shouldShowAdvancedFilterDropdownButton = currentRecordFilterGroups.length > 0; - const isAnyFieldSearchDropdownOpen = useRecoilComponentValue( + const isAnyFieldSearchDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ANY_FIELD_SEARCH_DROPDOWN_ID, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterButton.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterButton.tsx index f0e6eade2b..a56c031994 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterButton.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterButton.tsx @@ -1,11 +1,11 @@ import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { Trans } from '@lingui/react/macro'; export const ViewBarFilterButton = () => { - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, ViewBarFilterDropdownIds.MAIN, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx index c654011a6b..92b8f7695c 100644 --- a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx @@ -12,6 +12,7 @@ import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableLi import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/internal/dropdownYPositionComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -77,7 +78,7 @@ export const ViewFieldsVisibleDropdownSection = () => { ) .toSorted(sortByProperty('position')); - const dropdownYPosition = useRecoilComponentValue( + const dropdownYPosition = useRecoilComponentValueV2( dropdownYPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerDropdown.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerDropdown.tsx index b15cb54272..e3ab851f88 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerDropdown.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerDropdown.tsx @@ -5,7 +5,7 @@ import { t } from '@lingui/core/macro'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetRecordIndexTotalCount } from '@/views/hooks/internal/useGetRecordIndexTotalCount'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode'; @@ -61,7 +61,7 @@ export const ViewPickerDropdown = () => { const { totalCount } = useGetRecordIndexTotalCount(); - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, VIEW_PICKER_DROPDOWN_ID, ); 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 fc2d7aed38..842ffa521d 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 @@ -2,7 +2,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type InputSchemaPropertyType } from 'twenty-shared/workflow'; import { WorkflowVariablesDropdownStepItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownStepItems'; import { WorkflowVariablesDropdownSteps } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownSteps'; @@ -53,7 +53,7 @@ export const WorkflowVariablesDropdown = ({ const theme = useTheme(); const dropdownId = `${SEARCH_VARIABLES_DROPDOWN_ID}-${instanceId}`; - const isDropdownOpen = useRecoilComponentValue( + const isDropdownOpen = useRecoilComponentValueV2( isDropdownOpenComponentState, dropdownId, );