From 530f74e28c70a2bb675851880e626b0b819ee7ea Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Thu, 19 Feb 2026 13:50:21 +0100 Subject: [PATCH] Migrate more to Jotai (#18087) Continue jotai migration --- .../GotoHotkeysEffectsProvider.tsx | 14 ++-- ...CurrentWorkspaceMemberFavoritesFolders.tsx | 14 ++-- .../components/FavoriteFolderPickerFooter.tsx | 4 +- ...rkspaceMemberNavigationMenuItemFolders.tsx | 14 ++-- .../MainNavigationDrawerFixedItems.tsx | 6 +- .../components/MobileNavigationBar.tsx | 3 +- .../components/SettingsNavigationDrawer.tsx | 4 +- .../AppNavigationDrawer.stories.tsx | 5 +- .../navigation/hooks/useOpenSettings.ts | 3 +- ...ionDrawerSectionForObjectMetadataItems.tsx | 12 ++- ...vigationDrawerSectionForWorkspaceItems.tsx | 3 +- ...jectOptionsDropdownHiddenFieldsContent.tsx | 4 +- ...tionsDropdownHiddenRecordGroupsContent.tsx | 4 +- ...ptionsDropdownRecordGroupFieldsContent.tsx | 4 +- .../ui/meta-types/hooks/useAddSelectOption.ts | 6 +- .../hooks/useRecordGroupActions.ts | 4 +- .../RecordTableHeaderPlusButtonContent.tsx | 4 +- .../components/AdvancedSettingsWrapper.tsx | 4 +- ...ingsDataModelFieldRelationJunctionForm.tsx | 4 +- .../SettingsDataModelFieldSelectForm.tsx | 4 +- .../SettingsObjectRelationsTable.tsx | 4 +- ...SettingsUpdateDataModelObjectAboutForm.tsx | 3 +- .../components/DialogManager.tsx | 6 +- .../components/DialogManagerEffect.tsx | 6 +- .../hooks/__tests__/useDialogManager.test.tsx | 25 ++++-- .../dialog-manager/hooks/useDialogManager.ts | 71 ++++++++-------- .../states/dialogInternalComponentState.ts | 18 ++-- .../components/SnackBarProvider.tsx | 4 +- .../snack-bar-manager/hooks/useSnackBar.ts | 84 +++++++++---------- .../states/snackBarInternalComponentState.ts | 4 +- .../field/display/states/filePreviewState.ts | 4 +- .../ui/input/components/IconPicker.tsx | 26 ++++-- .../ui/input/hooks/IconPickerScrollEffect.tsx | 9 +- .../states/iconPickerVisibleCountState.ts | 8 +- .../ui/layout/page/components/PageHeader.tsx | 4 +- .../NavigationDrawerWidthEffect.tsx | 4 +- ...ltiWorkspaceDropdownClickableComponent.tsx | 3 +- .../components/NavigationDrawer.tsx | 7 +- ...avigationDrawerAnimatedCollapseWrapper.tsx | 4 +- .../components/NavigationDrawerBackButton.tsx | 6 +- .../NavigationDrawerCollapseButton.tsx | 4 +- .../components/NavigationDrawerHeader.tsx | 4 +- .../components/NavigationDrawerItem.tsx | 4 +- ...igationDrawerItemsCollapsableContainer.tsx | 4 +- .../NavigationDrawerSectionTitle.tsx | 3 +- .../hooks/useNavigationSection.ts | 59 ++++++------- .../states/isAdvancedModeEnabledState.ts | 9 +- .../isNavigationSectionOpenFamilyState.ts | 7 +- .../states/isNavigationDrawerExpanded.ts | 9 +- .../states/navigationDrawerWidthState.ts | 10 +-- .../states/navigationMemorizedUrlState.ts | 4 +- ...ldNavigateBackToMemorizedUrlOnSaveState.ts | 9 +- .../ui/theme/components/BaseThemeProvider.tsx | 4 +- .../modules/ui/theme/hooks/useColorScheme.ts | 7 +- .../theme/states/persistedColorSchemeState.ts | 10 +-- .../state/jotai/utils/createFamilyStateV2.ts | 10 ++- .../state/jotai/utils/createStateV2.ts | 7 +- .../hooks/useGetAvailableFieldsForCalendar.ts | 5 +- .../useGetAvailableFieldsToGroupRecordsBy.ts | 5 +- .../data-model/SettingsObjectDetailPage.tsx | 5 +- .../data-model/SettingsObjectFieldEdit.tsx | 6 +- .../data-model/SettingsObjectFieldTable.tsx | 5 +- .../data-model/SettingsObjectTable.tsx | 3 +- 63 files changed, 330 insertions(+), 283 deletions(-) diff --git a/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx b/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx index d30cb5fb76..afbf47a829 100644 --- a/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx +++ b/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx @@ -4,7 +4,7 @@ import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNaviga import { navigationDrawerExpandedMemorizedStateV2 } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedStateV2'; import { useGoToHotkeys } from '@/ui/utilities/hotkey/hooks/useGoToHotkeys'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { getAppPath, getSettingsPath } from 'twenty-shared/utils'; @@ -17,14 +17,10 @@ export const GotoHotkeysEffectsProvider = () => { useGoToHotkeys({ key: 's', location: getSettingsPath(SettingsPath.ProfilePage), - preNavigateFunction: useRecoilCallback( - ({ set }) => - () => { - set(isNavigationDrawerExpandedState, true); - store.set(navigationDrawerExpandedMemorizedStateV2.atom, true); - }, - [store], - ), + preNavigateFunction: useCallback(() => { + store.set(isNavigationDrawerExpandedState.atom, true); + store.set(navigationDrawerExpandedMemorizedStateV2.atom, true); + }, [store]), }); return activeNonSystemObjectMetadataItems.map((objectMetadataItem) => { diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx index 29f1aa21a2..7a5d12617e 100644 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx +++ b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx @@ -11,6 +11,8 @@ import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigat import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; +import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; @@ -29,12 +31,12 @@ export const CurrentWorkspaceMemberFavoritesFolders = () => { const { t } = useLingui(); - const { - toggleNavigationSection, - isNavigationSectionOpenState, - openNavigationSection, - } = useNavigationSection('Favorites'); - const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); + const { toggleNavigationSection, openNavigationSection } = + useNavigationSection('Favorites'); + const isNavigationSectionOpen = useFamilyRecoilValueV2( + isNavigationSectionOpenFamilyState, + 'Favorites', + ); const toggleNewFolder = () => { openNavigationSection(); diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerFooter.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerFooter.tsx index 56a74bacd4..d47124118d 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerFooter.tsx +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerFooter.tsx @@ -4,9 +4,9 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; -import { useSetRecoilState } from 'recoil'; import { IconPlus } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; @@ -19,7 +19,7 @@ export const FavoriteFolderPickerFooter = ({ const [, setIsFavoriteFolderCreating] = useRecoilStateV2( isFavoriteFolderCreatingStateV2, ); - const setIsNavigationDrawerExpanded = useSetRecoilState( + const setIsNavigationDrawerExpanded = useSetRecoilStateV2( isNavigationDrawerExpandedState, ); const { openNavigationSection } = useNavigationSection('Favorites'); diff --git a/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItemFolders.tsx b/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItemFolders.tsx index c19093ccab..fc02bab9a0 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItemFolders.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItemFolders.tsx @@ -17,6 +17,8 @@ import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigat import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; +import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; export const CurrentWorkspaceMemberNavigationMenuItemFolders = () => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); @@ -32,12 +34,12 @@ export const CurrentWorkspaceMemberNavigationMenuItemFolders = () => { const { t } = useLingui(); - const { - toggleNavigationSection, - isNavigationSectionOpenState, - openNavigationSection, - } = useNavigationSection('Favorites'); - const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); + const { toggleNavigationSection, openNavigationSection } = + useNavigationSection('Favorites'); + const isNavigationSectionOpen = useFamilyRecoilValueV2( + isNavigationSectionOpenFamilyState, + 'Favorites', + ); const toggleNewFolder = () => { openNavigationSection(); diff --git a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerFixedItems.tsx b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerFixedItems.tsx index b6d650da4f..9e0fb294e8 100644 --- a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerFixedItems.tsx +++ b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerFixedItems.tsx @@ -4,11 +4,11 @@ import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/componen import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { navigationDrawerExpandedMemorizedStateV2 } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedStateV2'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useLingui } from '@lingui/react/macro'; import { useLocation, useNavigate } from 'react-router-dom'; -import { useRecoilState, useSetRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { IconSearch, IconSettings, IconSparkles } from 'twenty-ui/display'; @@ -18,12 +18,12 @@ import { FeatureFlagKey } from '~/generated-metadata/graphql'; export const MainNavigationDrawerFixedItems = () => { const isMobile = useIsMobile(); const location = useLocation(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] = - useRecoilState(isNavigationDrawerExpandedState); + useRecoilStateV2(isNavigationDrawerExpandedState); const setNavigationDrawerExpandedMemorized = useSetRecoilStateV2( navigationDrawerExpandedMemorizedStateV2, ); diff --git a/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx b/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx index efda877cd9..b6b854ce97 100644 --- a/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx +++ b/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx @@ -7,6 +7,7 @@ import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePat import { useOpenSettingsMenu } from '@/navigation/hooks/useOpenSettings'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; import { useNavigate } from 'react-router-dom'; @@ -31,7 +32,7 @@ export const MobileNavigationBar = () => { const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu(); const isSettingsPage = useIsSettingsPage(); const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] = - useRecoilState(isNavigationDrawerExpandedState); + useRecoilStateV2(isNavigationDrawerExpandedState); const [currentMobileNavigationDrawer, setCurrentMobileNavigationDrawer] = useRecoilState(currentMobileNavigationDrawerState); const { openSettingsMenu } = useOpenSettingsMenu(); diff --git a/packages/twenty-front/src/modules/navigation/components/SettingsNavigationDrawer.tsx b/packages/twenty-front/src/modules/navigation/components/SettingsNavigationDrawer.tsx index 1292939902..6998be37bd 100644 --- a/packages/twenty-front/src/modules/navigation/components/SettingsNavigationDrawer.tsx +++ b/packages/twenty-front/src/modules/navigation/components/SettingsNavigationDrawer.tsx @@ -3,8 +3,8 @@ import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/N import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent'; import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilState } from 'recoil'; import { AdvancedSettingsToggle } from 'twenty-ui/navigation'; export const SettingsNavigationDrawer = ({ @@ -13,7 +13,7 @@ export const SettingsNavigationDrawer = ({ className?: string; }) => { const { t } = useLingui(); - const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useRecoilState( + const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useRecoilStateV2( isAdvancedModeEnabledState, ); diff --git a/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx b/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx index 72d7821a44..f2439b5eca 100644 --- a/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx +++ b/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx @@ -4,6 +4,8 @@ import { MemoryRouter } from 'react-router-dom'; import { useSetRecoilState } from 'recoil'; import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState'; +import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; @@ -13,7 +15,6 @@ import { AppNavigationDrawer, type AppNavigationDrawerProps, } from '@/navigation/components/AppNavigationDrawer'; -import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { AppPath } from 'twenty-shared/types'; const MobileNavigationDrawerStateSetterEffect = ({ @@ -22,7 +23,7 @@ const MobileNavigationDrawerStateSetterEffect = ({ mobileNavigationDrawer?: 'main' | 'settings'; }) => { const isMobile = useIsMobile(); - const setIsNavigationDrawerExpanded = useSetRecoilState( + const setIsNavigationDrawerExpanded = useSetRecoilStateV2( isNavigationDrawerExpandedState, ); const setCurrentMobileNavigationDrawer = useSetRecoilState( diff --git a/packages/twenty-front/src/modules/navigation/hooks/useOpenSettings.ts b/packages/twenty-front/src/modules/navigation/hooks/useOpenSettings.ts index 92f85c1e09..b50843c66b 100644 --- a/packages/twenty-front/src/modules/navigation/hooks/useOpenSettings.ts +++ b/packages/twenty-front/src/modules/navigation/hooks/useOpenSettings.ts @@ -1,9 +1,10 @@ import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useSetRecoilState } from 'recoil'; export const useOpenSettingsMenu = () => { - const setIsNavigationDrawerExpanded = useSetRecoilState( + const setIsNavigationDrawerExpanded = useSetRecoilStateV2( isNavigationDrawerExpandedState, ); const setCurrentMobileNavigationDrawer = useSetRecoilState( diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx index 0b921654fe..c65dd7cbd8 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems.tsx @@ -7,7 +7,8 @@ import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigat import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; -import { useRecoilValue } from 'recoil'; +import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; const ORDERED_FIRST_STANDARD_OBJECTS: string[] = [ @@ -45,9 +46,12 @@ export const NavigationDrawerSectionForObjectMetadataItems = ({ onObjectMetadataItemClick, onActiveObjectMetadataItemClick, }: NavigationDrawerSectionForObjectMetadataItemsProps) => { - const { toggleNavigationSection, isNavigationSectionOpenState } = - useNavigationSection('Objects' + (isRemote ? 'Remote' : 'Workspace')); - const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); + const navigationSectionId = 'Objects' + (isRemote ? 'Remote' : 'Workspace'); + const { toggleNavigationSection } = useNavigationSection(navigationSectionId); + const isNavigationSectionOpen = useFamilyRecoilValueV2( + isNavigationSectionOpenFamilyState, + navigationSectionId, + ); const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForWorkspaceItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForWorkspaceItems.tsx index d14ff0fd41..496a8d40e2 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForWorkspaceItems.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForWorkspaceItems.tsx @@ -69,9 +69,8 @@ export const NavigationDrawerSectionForWorkspaceItems = ({ const { t } = useLingui(); const theme = useTheme(); const workspaceDropDisabled = useIsDropDisabledForSection(true); - const { toggleNavigationSection, isNavigationSectionOpenState } = + const { toggleNavigationSection, isNavigationSectionOpen } = useNavigationSection('Workspace'); - const isNavigationSectionOpen = useRecoilValue(isNavigationSectionOpenState); const coreViews = useRecoilValue(coreViewsState); const views = coreViews.map(convertCoreViewToView); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx index 0f19078b04..bdc93b7b0a 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenFieldsContent.tsx @@ -1,5 +1,4 @@ import { useLocation } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; @@ -10,6 +9,7 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { ViewFieldsHiddenDropdownSection } from '@/views/components/ViewFieldsHiddenDropdownSection'; import { useLingui } from '@lingui/react/macro'; import { SettingsPath } from 'twenty-shared/types'; @@ -31,7 +31,7 @@ export const ObjectOptionsDropdownHiddenFieldsContent = () => { }); const location = useLocation(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx index 493b90064e..1905dcafd9 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownHiddenRecordGroupsContent.tsx @@ -15,10 +15,10 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useLingui } from '@lingui/react/macro'; import { useLocation } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { VIEW_GROUP_VISIBLE_OPTIONS_MAX } from 'twenty-shared/constants'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; @@ -64,7 +64,7 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => { }); const location = useLocation(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx index 95b67ca757..505e145659 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx @@ -16,10 +16,10 @@ import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/Dropdow import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { ViewType } from '@/views/types/ViewType'; import { useLingui } from '@lingui/react/macro'; import { useLocation } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { IconChevronLeft, IconSettings, useIcons } from 'twenty-ui/display'; @@ -77,7 +77,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => { ); const location = useLocation(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddSelectOption.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddSelectOption.ts index 4412eabaa2..74b7f7a683 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddSelectOption.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddSelectOption.ts @@ -1,19 +1,19 @@ import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { shouldNavigateBackToMemorizedUrlOnSaveState } from '@/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useCallback } from 'react'; import { useParams } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; export const useAddSelectOption = (fieldName: string) => { const { objectNamePlural } = useParams(); const navigateSettings = useNavigateSettings(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); - const setShouldNavigateBackToMemorizedUrlOnSave = useSetRecoilState( + const setShouldNavigateBackToMemorizedUrlOnSave = useSetRecoilStateV2( shouldNavigateBackToMemorizedUrlOnSaveState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupActions.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupActions.ts index 436c371546..c6b764ac4c 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupActions.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupActions.ts @@ -11,12 +11,12 @@ import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFla import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type ViewType } from '@/views/types/ViewType'; import { t } from '@lingui/core/macro'; import { isUndefined } from '@sniptt/guards'; import { useCallback, useContext } from 'react'; import { useLocation } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { @@ -56,7 +56,7 @@ export const useRecordGroupActions = ({ const { handleVisibilityChange: handleRecordGroupVisibilityChange } = useRecordGroupVisibility(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx index 35bd6f4eed..b462721e40 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent.tsx @@ -1,6 +1,5 @@ import { useCallback } from 'react'; import { useLocation } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { useActiveFieldMetadataItems } from '@/object-metadata/hooks/useActiveFieldMetadataItems'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; @@ -13,6 +12,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useLingui } from '@lingui/react/macro'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; @@ -42,7 +42,7 @@ export const RecordTableHeaderPlusButtonContent = () => { ); const location = useLocation(); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); diff --git a/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx b/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx index fdda6ac8c3..b763da7146 100644 --- a/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx +++ b/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx @@ -1,8 +1,8 @@ import { AdvancedSettingsContentWrapperWithDot } from '@/settings/components/AdvancedSettingsContentWrapperWithDot'; import { ADVANCED_SETTINGS_ANIMATION_DURATION } from '@/settings/constants/AdvancedSettingsAnimationDurations'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; const StyledContent = styled.div` @@ -24,7 +24,7 @@ export const AdvancedSettingsWrapper = ({ dotPosition = 'centered', animationDimension = 'height', }: AdvancedSettingsWrapperProps) => { - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); return ( (); - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); const { objectMetadataItem: sourceObjectMetadataItem } = useObjectMetadataItem({ objectNameSingular }); diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx index df56e1f153..938522ad26 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx @@ -28,11 +28,11 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { IconDotsVertical, @@ -166,7 +166,7 @@ export const SettingsDataModelFieldSelectForm = ({ ); const isNullable = fieldMetadataItem?.isNullable; - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); const [searchParams] = useSearchParams(); diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationsTable.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationsTable.tsx index dc0b4a421f..e3485475cf 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationsTable.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationsTable.tsx @@ -11,11 +11,11 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; import { type TableMetadata } from '@/ui/layout/table/types/TableMetadata'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { useMemo, useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { FieldMetadataType } from 'twenty-shared/types'; import { IconArchive, @@ -83,7 +83,7 @@ export const SettingsObjectRelationsTable = ({ const [showInactive, setShowInactive] = useState(true); const [showSystemRelations, setShowSystemRelations] = useState(false); - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); const tableMetadata = SETTINGS_OBJECT_RELATION_TABLE_METADATA; diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx index b8e1b07cca..321daf2b3f 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx @@ -8,6 +8,7 @@ import { settingsDataModelObjectAboutFormSchema, } from '@/settings/data-model/validation-schemas/settingsDataModelObjectAboutFormSchema'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { zodResolver } from '@hookform/resolvers/zod'; import { FormProvider, useForm } from 'react-hook-form'; import { useSetRecoilState } from 'recoil'; @@ -30,7 +31,7 @@ export const SettingsUpdateDataModelObjectAboutForm = ({ const setUpdatedObjectNamePlural = useSetRecoilState( updatedObjectNamePluralState, ); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManager.tsx b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManager.tsx index 7670effe0b..cabd454088 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManager.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManager.tsx @@ -1,12 +1,14 @@ import { dialogInternalComponentState } from '@/ui/feedback/dialog-manager/states/dialogInternalComponentState'; import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { Dialog } from './Dialog'; import { DialogManagerEffect } from './DialogManagerEffect'; export const DialogManager = ({ children }: React.PropsWithChildren) => { - const dialogInternal = useRecoilComponentValue(dialogInternalComponentState); + const dialogInternal = useRecoilComponentValueV2( + dialogInternalComponentState, + ); const { closeDialog } = useDialogManager(); return ( diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManagerEffect.tsx b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManagerEffect.tsx index 7e3516f80b..6a474d7dba 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManagerEffect.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/DialogManagerEffect.tsx @@ -5,10 +5,12 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { dialogInternalComponentState } from '@/ui/feedback/dialog-manager/states/dialogInternalComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const DialogManagerEffect = () => { - const dialogInternal = useRecoilComponentValue(dialogInternalComponentState); + const dialogInternal = useRecoilComponentValueV2( + dialogInternalComponentState, + ); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/__tests__/useDialogManager.test.tsx b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/__tests__/useDialogManager.test.tsx index c310ac5c0a..a719482150 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/__tests__/useDialogManager.test.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/__tests__/useDialogManager.test.tsx @@ -1,4 +1,5 @@ import { act, renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { RecoilRoot } from 'recoil'; import { v4 as uuidv4 } from 'uuid'; @@ -6,7 +7,11 @@ import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/con import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager'; import { dialogInternalComponentState } from '@/ui/feedback/dialog-manager/states/dialogInternalComponentState'; import { type DialogOptions } from '@/ui/feedback/dialog-manager/types/DialogOptions'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { + jotaiStore, + resetJotaiStore, +} from '@/ui/utilities/state/jotai/jotaiStore'; const mockedUuid = 'mocked-uuid'; jest.mock('uuid'); @@ -15,11 +20,13 @@ jest.mock('uuid'); const Wrapper = ({ children }: { children: React.ReactNode }) => ( - - {children} - + + + {children} + + ); @@ -77,7 +84,7 @@ const renderHooks = () => { const { result } = renderHook( () => ({ dialogManager: useDialogManager(), - dialogInternal: useRecoilComponentValue(dialogInternalComponentState), + dialogInternal: useRecoilComponentValueV2(dialogInternalComponentState), }), renderHookConfig, ); @@ -95,6 +102,10 @@ const expectedReturnFromEnqueue = ( }; describe('useDialogManager', () => { + beforeEach(() => { + resetJotaiStore(); + }); + describe('tests for useDialogManager - enqueueDialog', () => { it('Should enqueueDialog', () => { const result = renderHooks(); diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/useDialogManager.ts b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/useDialogManager.ts index 07fea851f0..c3117e2aa5 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/useDialogManager.ts +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/hooks/useDialogManager.ts @@ -1,4 +1,4 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { v4 } from 'uuid'; import { DIALOG_FOCUS_ID } from '@/ui/feedback/dialog-manager/constants/DialogFocusId'; @@ -8,55 +8,56 @@ import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/con import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { dialogInternalComponentState } from '@/ui/feedback/dialog-manager/states/dialogInternalComponentState'; import { type DialogOptions } from '@/ui/feedback/dialog-manager/types/DialogOptions'; +import { useStore } from 'jotai'; export const useDialogManager = () => { const componentInstanceId = useAvailableComponentInstanceIdOrThrow( DialogComponentInstanceContext, ); + const store = useStore(); + const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const closeDialog = useRecoilCallback( - ({ set }) => - (id: string) => { - set( - dialogInternalComponentState.atomFamily({ - instanceId: componentInstanceId, - }), - (prevState) => ({ - ...prevState, - queue: prevState.queue.filter((dialog) => dialog.id !== id), - }), - ); + const closeDialog = useCallback( + (id: string) => { + store.set( + dialogInternalComponentState.atomFamily({ + instanceId: componentInstanceId, + }), + (prevState) => ({ + ...prevState, + queue: prevState.queue.filter((dialog) => dialog.id !== id), + }), + ); - removeFocusItemFromFocusStackById({ focusId: DIALOG_FOCUS_ID }); - }, - [componentInstanceId, removeFocusItemFromFocusStackById], + removeFocusItemFromFocusStackById({ focusId: DIALOG_FOCUS_ID }); + }, + [componentInstanceId, removeFocusItemFromFocusStackById, store], ); - const setDialogQueue = useRecoilCallback( - ({ set }) => - (newValue) => - set( - dialogInternalComponentState.atomFamily({ - instanceId: componentInstanceId, - }), - (prev) => { - if (prev.queue.length >= prev.maxQueue) { - return { - ...prev, - queue: [...prev.queue.slice(1), newValue] as DialogOptions[], - }; - } - + const setDialogQueue = useCallback( + (newValue: DialogOptions) => + store.set( + dialogInternalComponentState.atomFamily({ + instanceId: componentInstanceId, + }), + (prev) => { + if (prev.queue.length >= prev.maxQueue) { return { ...prev, - queue: [...prev.queue, newValue] as DialogOptions[], + queue: [...prev.queue.slice(1), newValue], }; - }, - ), - [componentInstanceId], + } + + return { + ...prev, + queue: [...prev.queue, newValue], + }; + }, + ), + [componentInstanceId, store], ); const enqueueDialog = (options?: Omit) => { diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/states/dialogInternalComponentState.ts b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/states/dialogInternalComponentState.ts index dee5e28b3c..d84f46874c 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/states/dialogInternalComponentState.ts +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/states/dialogInternalComponentState.ts @@ -1,5 +1,5 @@ import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type DialogOptions } from '@/ui/feedback/dialog-manager/types/DialogOptions'; type DialogState = { @@ -7,11 +7,13 @@ type DialogState = { queue: DialogOptions[]; }; -export const dialogInternalComponentState = createComponentState({ - key: 'dialogInternalComponentState', - defaultValue: { - maxQueue: 2, - queue: [], +export const dialogInternalComponentState = createComponentStateV2( + { + key: 'dialogInternalComponentState', + defaultValue: { + maxQueue: 2, + queue: [], + }, + componentInstanceContext: DialogComponentInstanceContext, }, - componentInstanceContext: DialogComponentInstanceContext, -}); +); diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx index 5876705b96..b834e7809c 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx @@ -6,7 +6,7 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { snackBarInternalComponentState } from '@/ui/feedback/snack-bar-manager/states/snackBarInternalComponentState'; import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; import { SnackBar } from './SnackBar'; @@ -27,7 +27,7 @@ const StyledSnackBarContainer = styled.div` `; export const SnackBarProvider = ({ children }: React.PropsWithChildren) => { - const snackBarInternal = useRecoilComponentValue( + const snackBarInternal = useRecoilComponentValueV2( snackBarInternalComponentState, ); diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts index 96291fc8eb..6ff29bdadc 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/hooks/useSnackBar.ts @@ -1,5 +1,4 @@ import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; import { v4 as uuidv4 } from 'uuid'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; @@ -12,6 +11,7 @@ import { buildErrorAction } from '@/ui/feedback/snack-bar-manager/utils/build-er import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { type ApolloError } from '@apollo/client'; import { t } from '@lingui/core/macro'; +import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; import { getErrorMessageFromApolloError } from '~/utils/get-error-message-from-apollo-error.util'; @@ -20,53 +20,53 @@ export const useSnackBar = () => { SnackBarComponentInstanceContext, ); - const handleSnackBarClose = useRecoilCallback( - ({ set }) => - (id: string) => { - set( - snackBarInternalComponentState.atomFamily({ - instanceId: componentInstanceId, - }), - (prevState) => ({ - ...prevState, - queue: prevState.queue.filter((snackBar) => snackBar.id !== id), - }), - ); - }, - [componentInstanceId], + const store = useStore(); + + const handleSnackBarClose = useCallback( + (id: string) => { + store.set( + snackBarInternalComponentState.atomFamily({ + instanceId: componentInstanceId, + }), + (prevState) => ({ + ...prevState, + queue: prevState.queue.filter((snackBar) => snackBar.id !== id), + }), + ); + }, + [componentInstanceId, store], ); - const setSnackBarQueue = useRecoilCallback( - ({ set }) => - (newValue: SnackBarOptions) => - set( - snackBarInternalComponentState.atomFamily({ - instanceId: componentInstanceId, - }), - (prev) => { - if ( - isDefined(newValue.dedupeKey) && - prev.queue.some( - (snackBar) => snackBar.dedupeKey === newValue.dedupeKey, - ) - ) { - return prev; - } - - if (prev.queue.length >= prev.maxQueue) { - return { - ...prev, - queue: [...prev.queue.slice(1), newValue] as SnackBarOptions[], - }; - } + const setSnackBarQueue = useCallback( + (newValue: SnackBarOptions) => + store.set( + snackBarInternalComponentState.atomFamily({ + instanceId: componentInstanceId, + }), + (prev) => { + if ( + isDefined(newValue.dedupeKey) && + prev.queue.some( + (snackBar) => snackBar.dedupeKey === newValue.dedupeKey, + ) + ) { + return prev; + } + if (prev.queue.length >= prev.maxQueue) { return { ...prev, - queue: [...prev.queue, newValue] as SnackBarOptions[], + queue: [...prev.queue.slice(1), newValue] as SnackBarOptions[], }; - }, - ), - [componentInstanceId], + } + + return { + ...prev, + queue: [...prev.queue, newValue] as SnackBarOptions[], + }; + }, + ), + [componentInstanceId, store], ); const enqueueSuccessSnackBar = useCallback( diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/states/snackBarInternalComponentState.ts b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/states/snackBarInternalComponentState.ts index 7d03782f28..ce3cd3ed64 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/states/snackBarInternalComponentState.ts +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/states/snackBarInternalComponentState.ts @@ -1,5 +1,5 @@ import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type SnackBarProps } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; export type SnackBarOptions = SnackBarProps & { @@ -12,7 +12,7 @@ export type SnackBarState = { }; export const snackBarInternalComponentState = - createComponentState({ + createComponentStateV2({ key: 'snackBarState', defaultValue: { maxQueue: 3, diff --git a/packages/twenty-front/src/modules/ui/field/display/states/filePreviewState.ts b/packages/twenty-front/src/modules/ui/field/display/states/filePreviewState.ts index 6f0ac0e51a..272c2cc016 100644 --- a/packages/twenty-front/src/modules/ui/field/display/states/filePreviewState.ts +++ b/packages/twenty-front/src/modules/ui/field/display/states/filePreviewState.ts @@ -1,7 +1,7 @@ import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const filePreviewState = createState({ +export const filePreviewState = createStateV2({ key: 'filePreviewState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx b/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx index 8eeb74bd6f..8a303bb1f4 100644 --- a/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import { type ReactNode, useMemo, useState } from 'react'; +import { type ReactNode, useCallback, useMemo, useState } from 'react'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -10,16 +10,20 @@ import { arrayToChunks } from '~/utils/array/arrayToChunks'; import { ICON_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/ui/input/components/constants/IconPickerDropdownContentWidth'; import { IconPickerScrollEffect } from '@/ui/input/hooks/IconPickerScrollEffect'; -import { iconPickerVisibleCountState } from '@/ui/input/states/iconPickerVisibleCountState'; +import { + ICON_PICKER_DEFAULT_VISIBLE_COUNT, + iconPickerVisibleCountState, +} from '@/ui/input/states/iconPickerVisibleCountState'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; -import { useRecoilValue, useResetRecoilState } from 'recoil'; +import { useStore } from 'jotai'; import { IconApps, type IconComponent, useIcons } from 'twenty-ui/display'; import { IconButton, @@ -156,12 +160,18 @@ export const IconPicker = ({ const { closeDropdown } = useCloseDropdown(); - const iconPickerVisibleCount = - useRecoilValue(iconPickerVisibleCountState(dropdownId)) ?? maxIconsVisible; + const store = useStore(); - const resetIconPickerVisibleCount = useResetRecoilState( - iconPickerVisibleCountState(dropdownId), - ); + const iconPickerVisibleCount = + useFamilyRecoilValueV2(iconPickerVisibleCountState, dropdownId) ?? + maxIconsVisible; + + const resetIconPickerVisibleCount = useCallback(() => { + store.set( + iconPickerVisibleCountState.atomFamily(dropdownId), + ICON_PICKER_DEFAULT_VISIBLE_COUNT, + ); + }, [store, dropdownId]); const { getIcons, getIcon } = useIcons(); const icons = getIcons(); diff --git a/packages/twenty-front/src/modules/ui/input/hooks/IconPickerScrollEffect.tsx b/packages/twenty-front/src/modules/ui/input/hooks/IconPickerScrollEffect.tsx index aa2fa66558..b200a24b2e 100644 --- a/packages/twenty-front/src/modules/ui/input/hooks/IconPickerScrollEffect.tsx +++ b/packages/twenty-front/src/modules/ui/input/hooks/IconPickerScrollEffect.tsx @@ -1,7 +1,7 @@ +import { iconPickerVisibleCountState } from '@/ui/input/states/iconPickerVisibleCountState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; -import { iconPickerVisibleCountState } from '@/ui/input/states/iconPickerVisibleCountState'; type IconPickerScrollEffectProps = { sentinelId: string; @@ -14,8 +14,9 @@ export const IconPickerScrollEffect = ({ }: IconPickerScrollEffectProps) => { const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement(); - const setIconPickerVisibleCount = useSetRecoilState( - iconPickerVisibleCountState(dropdownId), + const setIconPickerVisibleCount = useSetFamilyRecoilStateV2( + iconPickerVisibleCountState, + dropdownId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/ui/input/states/iconPickerVisibleCountState.ts b/packages/twenty-front/src/modules/ui/input/states/iconPickerVisibleCountState.ts index 130df01d2b..3a4401eb6d 100644 --- a/packages/twenty-front/src/modules/ui/input/states/iconPickerVisibleCountState.ts +++ b/packages/twenty-front/src/modules/ui/input/states/iconPickerVisibleCountState.ts @@ -1,6 +1,8 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const iconPickerVisibleCountState = createFamilyState({ +export const ICON_PICKER_DEFAULT_VISIBLE_COUNT = 25; + +export const iconPickerVisibleCountState = createFamilyStateV2({ key: 'iconPickerVisibleCountState', - defaultValue: 25, + defaultValue: ICON_PICKER_DEFAULT_VISIBLE_COUNT, }); diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx index 0b95df4336..44ec9b2213 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx @@ -1,13 +1,13 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { type ReactNode } from 'react'; -import { useRecoilValue } from 'recoil'; import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton'; import { PAGE_ACTION_CONTAINER_CLICK_OUTSIDE_ID } from '@/ui/layout/page/constants/PageActionContainerClickOutsideId'; import { PAGE_BAR_MIN_HEIGHT } from '@/ui/layout/page/constants/PageBarMinHeight'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { AnimatePresence } from 'framer-motion'; import { @@ -96,7 +96,7 @@ export const PageHeader = ({ }: PageHeaderProps) => { const isMobile = useIsMobile(); const theme = useTheme(); - const isNavigationDrawerExpanded = useRecoilValue( + const isNavigationDrawerExpanded = useRecoilValueV2( isNavigationDrawerExpandedState, ); diff --git a/packages/twenty-front/src/modules/ui/navigation/components/NavigationDrawerWidthEffect.tsx b/packages/twenty-front/src/modules/ui/navigation/components/NavigationDrawerWidthEffect.tsx index b36aecd6ba..3d81da0a1c 100644 --- a/packages/twenty-front/src/modules/ui/navigation/components/NavigationDrawerWidthEffect.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/components/NavigationDrawerWidthEffect.tsx @@ -1,13 +1,13 @@ import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { NAVIGATION_DRAWER_WIDTH_VAR, navigationDrawerWidthState, } from '@/ui/navigation/states/navigationDrawerWidthState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; export const NavigationDrawerWidthEffect = () => { - const navigationDrawerWidth = useRecoilValue(navigationDrawerWidthState); + const navigationDrawerWidth = useRecoilValueV2(navigationDrawerWidthState); useEffect(() => { document.documentElement.style.setProperty( diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownClickableComponent.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownClickableComponent.tsx index eb7122cfb3..155451b10b 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownClickableComponent.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownClickableComponent.tsx @@ -9,13 +9,14 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useRecoilValue } from 'recoil'; import { useTheme } from '@emotion/react'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { Avatar } from 'twenty-ui/display'; export const MultiWorkspaceDropdownClickableComponent = () => { const currentWorkspace = useRecoilValue(currentWorkspaceState); const theme = useTheme(); - const isNavigationDrawerExpanded = useRecoilValue( + const isNavigationDrawerExpanded = useRecoilValueV2( isNavigationDrawerExpandedState, ); return ( diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx index a158a6df0f..65d27ee54f 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx @@ -1,9 +1,10 @@ import styled from '@emotion/styled'; import { type ReactNode, useState } from 'react'; -import { useRecoilState, useSetRecoilState } from 'recoil'; +import { useSetRecoilState } from 'recoil'; import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer'; import { tableWidthResizeIsActiveState } from '@/object-record/record-table/states/tableWidthResizeIsActivedState'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { ResizablePanelEdge } from '@/ui/layout/resizable-panel/components/ResizablePanelEdge'; import { NAVIGATION_DRAWER_COLLAPSED_WIDTH } from '@/ui/layout/resizable-panel/constants/NavigationDrawerCollapsedWidth'; import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints'; @@ -77,8 +78,8 @@ export const NavigationDrawer = ({ const isSettingsDrawer = useIsSettingsDrawer(); const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] = - useRecoilState(isNavigationDrawerExpandedState); - const [navigationDrawerWidth, setNavigationDrawerWidth] = useRecoilState( + useRecoilStateV2(isNavigationDrawerExpandedState); + const [navigationDrawerWidth, setNavigationDrawerWidth] = useRecoilStateV2( navigationDrawerWidthState, ); const setTableWidthResizeIsActive = useSetRecoilState( diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx index 6cd8efed70..6f3137f43c 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper.tsx @@ -1,5 +1,6 @@ import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { @@ -7,7 +8,6 @@ import { motion, type TargetAndTransition, } from 'framer-motion'; -import { useRecoilValue } from 'recoil'; const StyledAnimatedContainer = styled(motion.span)` display: block; @@ -20,7 +20,7 @@ export const NavigationDrawerAnimatedCollapseWrapper = ({ }) => { const theme = useTheme(); const isSettingsPage = useIsSettingsPage(); - const isNavigationDrawerExpanded = useRecoilValue( + const isNavigationDrawerExpanded = useRecoilValueV2( isNavigationDrawerExpandedState, ); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx index 836d4d6cf8..963992d26c 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx @@ -1,11 +1,11 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { navigationDrawerExpandedMemorizedStateV2 } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedStateV2'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo'; import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; import { IconX } from 'twenty-ui/display'; @@ -47,9 +47,9 @@ export const NavigationDrawerBackButton = ({ title, }: NavigationDrawerBackButtonProps) => { const theme = useTheme(); - const navigationMemorizedUrl = useRecoilValue(navigationMemorizedUrlState); + const navigationMemorizedUrl = useRecoilValueV2(navigationMemorizedUrlState); - const setIsNavigationDrawerExpanded = useSetRecoilState( + const setIsNavigationDrawerExpanded = useSetRecoilStateV2( isNavigationDrawerExpandedState, ); const navigationDrawerExpandedMemorized = useRecoilValueV2( diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx index d7576bb151..976b5168c0 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton.tsx @@ -1,6 +1,6 @@ import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import styled from '@emotion/styled'; -import { useSetRecoilState } from 'recoil'; import { IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightCollapse, @@ -26,7 +26,7 @@ export const NavigationDrawerCollapseButton = ({ className, direction = 'left', }: NavigationDrawerCollapseButtonProps) => { - const setIsNavigationDrawerExpanded = useSetRecoilState( + const setIsNavigationDrawerExpanded = useSetRecoilStateV2( isNavigationDrawerExpandedState, ); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx index fd514e4595..9af4d64941 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerHeader.tsx @@ -1,11 +1,11 @@ import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { MultiWorkspaceDropdownButton } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/MultiWorkspaceDropdownButton'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { PAGE_BAR_MIN_HEIGHT } from '@/ui/layout/page/constants/PageBarMinHeight'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { NavigationDrawerCollapseButton } from './NavigationDrawerCollapseButton'; const StyledContainer = styled.div` @@ -36,7 +36,7 @@ export const NavigationDrawerHeader = ({ }: NavigationDrawerHeaderProps) => { const isMobile = useIsMobile(); - const isNavigationDrawerExpanded = useRecoilValue( + const isNavigationDrawerExpanded = useRecoilValueV2( isNavigationDrawerExpandedState, ); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx index 7f8cbc0b46..c70a5de372 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItem.tsx @@ -6,13 +6,13 @@ import { useNavigationDrawerTooltip } from '@/ui/navigation/navigation-drawer/ho import { type NavigationDrawerSubItemState } from '@/ui/navigation/navigation-drawer/types/NavigationDrawerSubItemState'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import isPropValid from '@emotion/is-prop-valid'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { type ReactNode } from 'react'; import { Link } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { Pill } from 'twenty-ui/components'; import { @@ -305,7 +305,7 @@ export const NavigationDrawerItem = ({ const isMobile = useIsMobile(); const isSettingsPage = useIsSettingsPage(); const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] = - useRecoilState(isNavigationDrawerExpandedState); + useRecoilStateV2(isNavigationDrawerExpandedState); const { navigationItemId } = useNavigationDrawerTooltip(label, to); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer.tsx index ba271c9820..ba987e9547 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer.tsx @@ -1,5 +1,6 @@ import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { @@ -8,7 +9,6 @@ import { type TargetAndTransition, } from 'framer-motion'; import { type ReactNode } from 'react'; -import { useRecoilValue } from 'recoil'; const StyledAnimationGroupContainer = styled(motion.div)``; @@ -23,7 +23,7 @@ export const NavigationDrawerItemsCollapsableContainer = ({ }: NavigationDrawerItemsCollapsableContainerProps) => { const theme = useTheme(); const isSettingsPage = useIsSettingsPage(); - const isNavigationDrawerExpanded = useRecoilValue( + const isNavigationDrawerExpanded = useRecoilValueV2( isNavigationDrawerExpandedState, ); const isExpanded = isNavigationDrawerExpanded || isSettingsPage; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx index 92f9d25dc4..c055178273 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle.tsx @@ -4,6 +4,7 @@ import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; import { NavigationDrawerSectionTitleSkeletonLoader } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import React from 'react'; import { useRecoilValue } from 'recoil'; @@ -60,7 +61,7 @@ export const NavigationDrawerSectionTitle = ({ alwaysShowRightIcon = false, }: NavigationDrawerSectionTitleProps) => { const isMobile = useIsMobile(); - const isNavigationDrawerExpanded = useRecoilValue( + const isNavigationDrawerExpanded = useRecoilValueV2( isNavigationDrawerExpandedState, ); const isSettingsPage = useIsSettingsPage(); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts index 33c3255a3b..68d072c369 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useNavigationSection.ts @@ -1,45 +1,40 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; export const useNavigationSection = (navigationSectionId: string) => { - const closeNavigationSection = useRecoilCallback( - ({ set }) => - () => { - set(isNavigationSectionOpenFamilyState(navigationSectionId), false); - }, - [navigationSectionId], + const store = useStore(); + const isNavigationSectionOpen = useFamilyRecoilValueV2( + isNavigationSectionOpenFamilyState, + navigationSectionId, ); - const openNavigationSection = useRecoilCallback( - ({ set }) => - () => { - set(isNavigationSectionOpenFamilyState(navigationSectionId), true); - }, - [navigationSectionId], - ); + const closeNavigationSection = useCallback(() => { + store.set( + isNavigationSectionOpenFamilyState.atomFamily(navigationSectionId), + false, + ); + }, [store, navigationSectionId]); - const toggleNavigationSection = useRecoilCallback( - ({ snapshot }) => - () => { - const isNavigationSectionOpen = snapshot - .getLoadable(isNavigationSectionOpenFamilyState(navigationSectionId)) - .getValue(); + const openNavigationSection = useCallback(() => { + store.set( + isNavigationSectionOpenFamilyState.atomFamily(navigationSectionId), + true, + ); + }, [store, navigationSectionId]); - if (isNavigationSectionOpen) { - closeNavigationSection(); - } else { - openNavigationSection(); - } - }, - [closeNavigationSection, openNavigationSection, navigationSectionId], - ); - - const isNavigationSectionOpenState = - isNavigationSectionOpenFamilyState(navigationSectionId); + const toggleNavigationSection = useCallback(() => { + if (isNavigationSectionOpen) { + closeNavigationSection(); + } else { + openNavigationSection(); + } + }, [isNavigationSectionOpen, closeNavigationSection, openNavigationSection]); return { - isNavigationSectionOpenState, + isNavigationSectionOpen, closeNavigationSection, openNavigationSection, toggleNavigationSection, diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts index d4f8429483..dbe1928ac5 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts @@ -1,8 +1,7 @@ -import { atom } from 'recoil'; -import { localStorageEffect } from '~/utils/recoil/localStorageEffect'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const isAdvancedModeEnabledState = atom({ +export const isAdvancedModeEnabledState = createStateV2({ key: 'isAdvancedModeEnabledAtom', - default: false, - effects: [localStorageEffect()], + defaultValue: false, + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState.ts index 8044e652ee..c8c7a647b6 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState.ts +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState.ts @@ -1,11 +1,10 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; -import { localStorageEffect } from '~/utils/recoil/localStorageEffect'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const isNavigationSectionOpenFamilyState = createFamilyState< +export const isNavigationSectionOpenFamilyState = createFamilyStateV2< boolean, string >({ key: 'isNavigationSectionOpenFamilyState', defaultValue: true, - effects: [localStorageEffect()], + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/ui/navigation/states/isNavigationDrawerExpanded.ts b/packages/twenty-front/src/modules/ui/navigation/states/isNavigationDrawerExpanded.ts index e81b079b64..93be66aa8f 100644 --- a/packages/twenty-front/src/modules/ui/navigation/states/isNavigationDrawerExpanded.ts +++ b/packages/twenty-front/src/modules/ui/navigation/states/isNavigationDrawerExpanded.ts @@ -1,11 +1,10 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; -import { localStorageEffect } from '~/utils/recoil/localStorageEffect'; const isMobile = window.innerWidth <= MOBILE_VIEWPORT; -export const isNavigationDrawerExpandedState = atom({ +export const isNavigationDrawerExpandedState = createStateV2({ key: 'isNavigationDrawerExpanded', - default: !isMobile, - effects: [localStorageEffect()], + defaultValue: !isMobile, + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/ui/navigation/states/navigationDrawerWidthState.ts b/packages/twenty-front/src/modules/ui/navigation/states/navigationDrawerWidthState.ts index 9cb0ee89d0..d32d6500b2 100644 --- a/packages/twenty-front/src/modules/ui/navigation/states/navigationDrawerWidthState.ts +++ b/packages/twenty-front/src/modules/ui/navigation/states/navigationDrawerWidthState.ts @@ -1,12 +1,10 @@ -import { atom } from 'recoil'; - import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints'; -import { localStorageEffect } from '~/utils/recoil/localStorageEffect'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; export const NAVIGATION_DRAWER_WIDTH_VAR = '--navigation-drawer-width'; -export const navigationDrawerWidthState = atom({ +export const navigationDrawerWidthState = createStateV2({ key: 'navigationDrawerWidth', - default: NAVIGATION_DRAWER_CONSTRAINTS.default, - effects: [localStorageEffect()], + defaultValue: NAVIGATION_DRAWER_CONSTRAINTS.default, + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/ui/navigation/states/navigationMemorizedUrlState.ts b/packages/twenty-front/src/modules/ui/navigation/states/navigationMemorizedUrlState.ts index 186c362773..dd71c9aa62 100644 --- a/packages/twenty-front/src/modules/ui/navigation/states/navigationMemorizedUrlState.ts +++ b/packages/twenty-front/src/modules/ui/navigation/states/navigationMemorizedUrlState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const navigationMemorizedUrlState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const navigationMemorizedUrlState = createStateV2({ key: 'navigationMemorizedUrlState', defaultValue: '/', }); diff --git a/packages/twenty-front/src/modules/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState.ts b/packages/twenty-front/src/modules/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState.ts index 31b2cf267f..583ab10552 100644 --- a/packages/twenty-front/src/modules/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState.ts +++ b/packages/twenty-front/src/modules/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState.ts @@ -1,8 +1,7 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const shouldNavigateBackToMemorizedUrlOnSaveState = createState( - { +export const shouldNavigateBackToMemorizedUrlOnSaveState = + createStateV2({ key: 'shouldNavigateBackToMemorizedUrlOnSaveState', defaultValue: false, - }, -); + }); diff --git a/packages/twenty-front/src/modules/ui/theme/components/BaseThemeProvider.tsx b/packages/twenty-front/src/modules/ui/theme/components/BaseThemeProvider.tsx index 9710a638eb..5919a5c684 100644 --- a/packages/twenty-front/src/modules/ui/theme/components/BaseThemeProvider.tsx +++ b/packages/twenty-front/src/modules/ui/theme/components/BaseThemeProvider.tsx @@ -3,7 +3,7 @@ import { createContext } from 'react'; import { useSystemColorScheme } from '@/ui/theme/hooks/useSystemColorScheme'; import { persistedColorSchemeState } from '@/ui/theme/states/persistedColorSchemeState'; -import { useRecoilState } from 'recoil'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { type ColorScheme } from 'twenty-ui/input'; import { THEME_DARK, THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme'; @@ -16,7 +16,7 @@ export const ThemeSchemeContext = createContext<(theme: ColorScheme) => void>( ); export const BaseThemeProvider = ({ children }: BaseThemeProviderProps) => { - const [persistedColorScheme, setPersistedColorScheme] = useRecoilState( + const [persistedColorScheme, setPersistedColorScheme] = useRecoilStateV2( persistedColorSchemeState, ); const systemColorScheme = useSystemColorScheme(); diff --git a/packages/twenty-front/src/modules/ui/theme/hooks/useColorScheme.ts b/packages/twenty-front/src/modules/ui/theme/hooks/useColorScheme.ts index c443ce9a1a..5785c02172 100644 --- a/packages/twenty-front/src/modules/ui/theme/hooks/useColorScheme.ts +++ b/packages/twenty-front/src/modules/ui/theme/hooks/useColorScheme.ts @@ -1,10 +1,11 @@ import { useCallback } from 'react'; -import { useRecoilState, useSetRecoilState } from 'recoil'; +import { useRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { persistedColorSchemeState } from '@/ui/theme/states/persistedColorSchemeState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { type IconComponent, @@ -19,7 +20,9 @@ export const useColorScheme = () => { ); const { updateOneRecord } = useUpdateOneRecord(); - const setPersistedColorScheme = useSetRecoilState(persistedColorSchemeState); + const setPersistedColorScheme = useSetRecoilStateV2( + persistedColorSchemeState, + ); const colorScheme = currentWorkspaceMember?.colorScheme ?? 'System'; diff --git a/packages/twenty-front/src/modules/ui/theme/states/persistedColorSchemeState.ts b/packages/twenty-front/src/modules/ui/theme/states/persistedColorSchemeState.ts index 0c17a620af..8c6152a542 100644 --- a/packages/twenty-front/src/modules/ui/theme/states/persistedColorSchemeState.ts +++ b/packages/twenty-front/src/modules/ui/theme/states/persistedColorSchemeState.ts @@ -1,10 +1,8 @@ -import { atom } from 'recoil'; - import { type ColorScheme } from '@/workspace-member/types/WorkspaceMember'; -import { localStorageEffect } from '~/utils/recoil/localStorageEffect'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const persistedColorSchemeState = atom({ +export const persistedColorSchemeState = createStateV2({ key: 'persistedColorSchemeState', - default: 'System', - effects: [localStorageEffect()], + defaultValue: 'System', + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createFamilyStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createFamilyStateV2.ts index c6bd259707..7e43e91a8d 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createFamilyStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createFamilyStateV2.ts @@ -1,13 +1,16 @@ import { atom } from 'jotai'; +import { atomWithStorage } from 'jotai/utils'; import { type FamilyStateV2 } from '@/ui/utilities/state/jotai/types/FamilyStateV2'; export const createFamilyStateV2 = ({ key, defaultValue, + useLocalStorage = false, }: { key: string; defaultValue: ValueType; + useLocalStorage?: boolean; }): FamilyStateV2 => { const atomCache = new Map< string, @@ -26,8 +29,11 @@ export const createFamilyStateV2 = ({ return existing; } - const baseAtom = atom(defaultValue); - baseAtom.debugLabel = `${key}__${cacheKey}`; + const atomKey = `${key}__${cacheKey}`; + const baseAtom = useLocalStorage + ? atomWithStorage(atomKey, defaultValue) + : atom(defaultValue); + baseAtom.debugLabel = atomKey; atomCache.set(cacheKey, baseAtom); return baseAtom; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createStateV2.ts index 65e72cedfa..1052a14c55 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createStateV2.ts @@ -1,15 +1,20 @@ import { atom } from 'jotai'; +import { atomWithStorage } from 'jotai/utils'; import { type StateV2 } from '@/ui/utilities/state/jotai/types/StateV2'; export const createStateV2 = ({ key, defaultValue, + useLocalStorage = false, }: { key: string; defaultValue: ValueType; + useLocalStorage?: boolean; }): StateV2 => { - const baseAtom = atom(defaultValue); + const baseAtom = useLocalStorage + ? atomWithStorage(key, defaultValue) + : atom(defaultValue); baseAtom.debugLabel = key; return { diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts index 992b45589b..6490667f88 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts @@ -1,9 +1,10 @@ import { useCallback } from 'react'; import { useLocation } from 'react-router-dom'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; import { FieldMetadataType, SettingsPath } from 'twenty-shared/types'; @@ -15,7 +16,7 @@ export const useGetAvailableFieldsForCalendar = () => { viewObjectMetadataIdComponentState, ); const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); const location = useLocation(); diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy.ts index 726e7e7ef2..93a6f99332 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy.ts @@ -1,9 +1,10 @@ import { useCallback } from 'react'; import { useLocation } from 'react-router-dom'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; import { SettingsPath } from 'twenty-shared/types'; @@ -16,7 +17,7 @@ export const useGetAvailableFieldsToGroupRecordsBy = () => { viewObjectMetadataIdComponentState, ); const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const setNavigationMemorizedUrl = useSetRecoilState( + const setNavigationMemorizedUrl = useSetRecoilStateV2( navigationMemorizedUrlState, ); const location = useLocation(); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx index 86ed035e5f..07fdd67456 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx @@ -9,9 +9,10 @@ import { ObjectSettings } from '@/settings/data-model/object-details/components/ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { TabList } from '@/ui/layout/tab-list/components/TabList'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import styled from '@emotion/styled'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilState } from 'recoil'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; @@ -66,7 +67,7 @@ export const SettingsObjectDetailPage = () => { SETTINGS_OBJECT_DETAIL_TABS.COMPONENT_INSTANCE_ID, ); - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); const isUniqueIndexesEnabled = useIsFeatureEnabled( FeatureFlagKey.IS_UNIQUE_INDEXES_ENABLED, ); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx index 576ed4b36a..10d91318fb 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx @@ -27,9 +27,9 @@ import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { shouldNavigateBackToMemorizedUrlOnSaveState } from '@/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilState } from 'recoil'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { @@ -67,14 +67,14 @@ export const SettingsObjectFieldEdit = () => { const navigate = useNavigate(); - const [navigationMemorizedUrl, setNavigationMemorizedUrl] = useRecoilState( + const [navigationMemorizedUrl, setNavigationMemorizedUrl] = useRecoilStateV2( navigationMemorizedUrlState, ); const [ shouldNavigateBackToMemorizedUrlOnSave, setShouldNavigateBackToMemorizedUrlOnSave, - ] = useRecoilState(shouldNavigateBackToMemorizedUrlOnSaveState); + ] = useRecoilStateV2(shouldNavigateBackToMemorizedUrlOnSaveState); const { objectNamePlural = '', fieldName = '' } = useParams(); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx index 5f3bde0fee..f1afd0f6b5 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx @@ -15,11 +15,12 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; import { type TableMetadata } from '@/ui/layout/table/types/TableMetadata'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { useEffect, useMemo, useState } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilState } from 'recoil'; import { FieldMetadataType } from 'twenty-shared/types'; import { IconArchive, @@ -90,7 +91,7 @@ export const SettingsObjectFieldTable = ({ const [showInactive, setShowInactive] = useState(true); const [showSystemFields, setShowSystemFields] = useState(false); - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); const tableMetadata = SETTINGS_OBJECT_FIELD_TABLE_METADATA; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx index 07d6df9cf8..2489fa117f 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx @@ -16,6 +16,7 @@ import { Table } from '@/ui/layout/table/components/Table'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; @@ -49,7 +50,7 @@ export const SettingsObjectTable = ({ const theme = useTheme(); - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const isAdvancedModeEnabled = useRecoilValueV2(isAdvancedModeEnabledState); const [searchTerm, setSearchTerm] = useState(''); const [showDeactivated, setShowDeactivated] = useState(true);