From 0f2af6a6cb1d44e2e901de864c8a5f5d7b97267e Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Tue, 24 Feb 2026 17:37:01 +0100 Subject: [PATCH] Jotai 13 (#18178) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Recoil to Jotai Migration — PR 13: Workflow, Page Layout, AI, Activities, Settings, SSE & Remaining Modules ### Summary This is the 13th PR in the [14-PR migration series](packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md) to replace Recoil with Jotai as the state management library in `twenty-front`. This PR migrates the remaining consumer code across all modules — updating ~1,076 files with ~10k insertions/deletions. ### What changed **New Jotai infrastructure (13 new files):** - `createComponentSelectorV2` and `createComponentFamilySelectorV2` — instance-scoped derived atoms, replacing Recoil's component selectors - 6 new hooks: `useRecoilComponentSelectorValueV2`, `useRecoilComponentFamilySelectorValueV2`, `useRecoilComponentSelectorCallbackStateV2`, `useRecoilComponentFamilySelectorCallbackStateV2`, `useRecoilComponentStateCallbackStateV2`, `useRecoilComponentFamilyStateCallbackStateV2` - New types: `ComponentSelectorV2`, `ComponentFamilySelectorV2`, `SelectorCallbacksV2` - Extended `buildGetHelper` to support the new selector patterns **State definition migrations:** - `createState()` → `createStateV2()` (Jotai `atom()`) - `createFamilyState()` → `createFamilyStateV2()` (Jotai `atom()` with family cache) - Recoil `selector`/`selectorFamily` → Jotai derived `atom()` via V2 utilities **Hook migrations (~2,400 removed, ~1,545 added V2 equivalents):** - `useRecoilValue` → `useRecoilValueV2` - `useRecoilState` → `useRecoilStateV2` - `useSetRecoilState` → `useSetRecoilStateV2` - `useRecoilCallback` → `useCallback` + `jotaiStore.get/set` - `useRecoilComponentValue` → `useRecoilComponentValueV2` - `useSetRecoilComponentState` → `useSetRecoilComponentStateV2` - `useRecoilComponentFamilyValue` → `useRecoilComponentFamilyValueV2` / `useFamilySelectorValueV2` - ~397 direct `import from 'recoil'` removed **Deleted files (9 files):** - `dateLocaleState.ts` — consolidated - `currentAIChatThreadTitleStateV2.ts` — renamed to replace the original - `isCommandMenuOpenedState.ts` — removed - `filesFieldUploadState.ts` — replaced by V2 - `recordStoreFamilySelector.ts`, `recordStoreFieldValueSelector.ts`, `recordStoreRecordsSelector.ts` — replaced by V2 equivalents - `settingsAllRolesSelector.ts` — replaced by `useSettingsAllRoles` hook - `settingsRoleIdsStateV2.ts` — consolidated **Modules migrated:** - Workflow (diagram, steps, variables, filters) - Page Layout (widgets, fields, graph, tabs) - AI (chat, agents, browsing context) - Activities (rich text editor, targets, timeline) - Action Menu (single/multiple record actions) - Command Menu (navigation, history, pages, workflow) - Context Store - Record Board, Record Table, Record Calendar, Record Index - Record Field, Record Filter, Record Sort, Record Group - Record Drag, Record Picker, Record Store - Views (view bar, view picker, filters, sorts) - Settings (roles, permissions, SSO, security, data model, developers, domains) - SSE (event streams, subscriptions) - Spreadsheet Import - Auth, Favorites, Front Components, Information Banner --- .../localization/states/dateLocaleState.ts | 17 - .../components/ActionOpenSidePanelPage.tsx | 4 +- .../HeadlessFrontComponentAction.tsx | 7 +- .../DeleteMultipleRecordsAction.tsx | 17 +- .../DestroyMultipleRecordsAction.tsx | 17 +- .../ExportMultipleRecordsAction.tsx | 4 +- .../components/MergeMultipleRecordsAction.tsx | 4 +- .../RestoreMultipleRecordsAction.tsx | 17 +- .../CreateNewViewNoSelectionRecord.tsx | 8 +- ...eDeletedRecordsNoSelectionRecordAction.tsx | 6 +- ...eDeletedRecordsNoSelectionRecordAction.tsx | 4 +- .../hooks/useRunWorkflowRecordActions.tsx | 121 +-- .../AddToFavoritesSingleRecordAction.tsx | 7 +- .../ExportNoteActionSingleRecordAction.tsx | 7 +- .../components/ExportSingleRecordAction.tsx | 4 +- .../CancelDashboardSingleRecordAction.tsx | 7 +- .../EditDashboardSingleRecordAction.tsx | 7 +- .../SaveDashboardSingleRecordAction.tsx | 7 +- .../hooks/useSelectedRecordIdOrThrow.tsx | 8 +- .../hooks/useSelectedRecordIds.tsx | 8 +- .../TidyUpWorkflowSingleRecordAction.tsx | 30 +- ...eeVersionWorkflowRunSingleRecordAction.tsx | 4 +- ...eWorkflowWorkflowRunSingleRecordAction.tsx | 4 +- .../StopWorkflowRunSingleRecordAction.tsx | 17 +- ...eRunsWorkflowVersionSingleRecordAction.tsx | 7 +- ...sionsWorkflowVersionSingleRecordAction.tsx | 7 +- ...kflowWorkflowVersionSingleRecordAction.tsx | 7 +- .../useRunWorkflowRecordAgnosticActions.tsx | 6 +- ...forceRegisteredActionsMapComponentState.ts | 4 +- .../components/RecordIndexActionMenu.tsx | 6 +- .../RecordIndexActionMenuDropdown.tsx | 3 +- .../components/RecordShowActionMenu.tsx | 9 +- .../RecordShowRightDrawerActionMenu.tsx | 6 +- .../RecordShowRightDrawerOpenRecordButton.tsx | 88 +- .../CommandMenuActionMenuDropdown.stories.tsx | 74 +- .../RecordIndexActionMenuDropdown.stories.tsx | 50 +- .../contexts/ActionMenuContextProvider.tsx | 6 +- .../ActionMenuContextProviderDefault.tsx | 6 +- ...tionMenuContextProviderWorkflowObjects.tsx | 10 +- .../action-menu/hooks/useRegisteredActions.ts | 15 +- .../useShouldActionBeRegisteredParams.ts | 31 +- ...ctionMenuDropdownPositionComponentState.ts | 4 +- .../components/CalendarEventsCard.tsx | 6 +- .../components/ActivityRichTextEditor.tsx | 154 ++- .../emails/components/EmailThreadHeader.tsx | 6 +- .../components/EmailThreadMessageSender.tsx | 6 +- .../states/lastViewableEmailThreadIdState.ts | 4 +- .../useActivityTargetObjectRecords.test.tsx | 8 +- .../useOpenCreateActivityDrawer.test.tsx | 4 +- .../modules/activities/hooks/useActivities.ts | 22 +- .../hooks/useActivityTargetObjectRecords.ts | 8 +- .../activities/hooks/useCreateActivityInDB.ts | 84 +- .../hooks/useOpenCreateActivityDrawer.ts | 11 +- .../useReplaceActivityBlockEditorContent.ts | 34 +- .../activities/hooks/useUpsertActivity.ts | 4 +- .../useOpenActivityTargetCellEditMode.ts | 133 ++- .../hooks/useUpdateActivityTargetFromCell.ts | 257 ++--- .../states/activityBodyFamilyState.ts | 4 +- .../activityTargetableEntityArrayState.ts | 4 +- .../states/canCreateActivityState.ts | 4 +- .../states/isCreatingActivityInDBState.ts | 4 +- .../components/EventRow.tsx | 11 +- .../components/EventFieldDiffValueEffect.tsx | 7 +- .../modules/ai/components/AIChatMessage.tsx | 6 +- .../ai/components/AIChatThreadGroup.tsx | 4 +- .../src/modules/ai/hooks/useAgentChat.ts | 4 +- .../src/modules/ai/hooks/useAgentChatData.ts | 4 +- .../modules/ai/hooks/useBrowsingContext.ts | 238 +++-- .../ai/hooks/useCreateNewAIChatThread.ts | 4 +- .../states/agentChatMessagesComponentState.ts | 4 +- .../states/currentAIChatThreadTitleState.ts | 6 +- .../states/currentAIChatThreadTitleStateV2.ts | 6 - .../effect-components/PageChangeEffect.tsx | 30 +- .../useExecuteTasksOnAnyLocationChange.ts | 133 ++- .../src/modules/auth/hooks/useAuth.ts | 127 +-- .../BlockEditorDropdownFocusEffect.tsx | 53 +- .../states/isSlashMenuOpenComponentState.ts | 4 +- ...seCommandMenuItemFrontComponentActions.tsx | 8 +- .../command-menu/components/CommandMenu.tsx | 10 +- .../components/CommandMenuAskAIInfo.tsx | 4 +- .../components/CommandMenuContainer.tsx | 6 +- .../CommandMenuDefaultSelectionEffect.tsx | 4 +- .../components/CommandMenuFolderInfo.tsx | 7 +- .../components/CommandMenuLinkInfo.tsx | 7 +- .../components/CommandMenuList.tsx | 4 +- .../components/CommandMenuPageLayoutInfo.tsx | 4 +- .../CommandMenuPageLayoutInfoContent.tsx | 18 +- .../components/CommandMenuRecordInfo.tsx | 34 +- .../components/CommandMenuRouter.tsx | 6 +- .../CommandMenuSidePanelForDesktop.tsx | 9 +- .../components/CommandMenuTopBar.tsx | 9 +- .../CommandMenuTopBarInputFocusEffect.tsx | 5 +- .../CommandMenuTopBarRightCornerIcon.tsx | 4 +- .../components/CommandMenuWidthEffect.tsx | 4 +- .../CommandMenuWorkflowStepInfo.tsx | 8 +- .../ResetContextToSelectionCommandButton.tsx | 6 +- .../__stories__/CommandMenu.stories.tsx | 62 +- .../CommandMenuContextRecordChip.stories.tsx | 8 +- .../hooks/__tests__/useCommandMenu.test.tsx | 53 +- ...MenuCloseAnimationCompleteCleanup.test.tsx | 107 +- .../__tests__/useCommandMenuHistory.test.tsx | 41 +- .../useCommandMenuOnItemClick.test.tsx | 6 +- ...uUpdateNavigationMorphItemsByPage.test.tsx | 64 +- .../__tests__/useNavigateCommandMenu.test.tsx | 19 +- ...useOpenCalendarEventInCommandMenu.test.tsx | 4 +- .../useOpenEmailThreadInCommandMenu.test.tsx | 4 +- .../useOpenRecordInCommandMenu.test.tsx | 33 +- .../useSetGlobalCommandMenuContext.test.tsx | 83 +- .../useUpdateCommandMenuPageInfo.test.tsx | 47 +- .../__tests__/useWorkflowCommandMenu.test.tsx | 28 +- .../command-menu/hooks/useCommandMenu.ts | 62 +- ...ommandMenuCloseAnimationCompleteCleanup.ts | 176 ++-- .../hooks/useCommandMenuContextChips.tsx | 15 +- .../hooks/useCommandMenuHistory.ts | 197 ++-- .../hooks/useCommandMenuHotKeys.ts | 10 +- .../hooks/useCommandMenuSearchRecords.tsx | 4 +- ...ndMenuUpdateNavigationMorphItemsByPage.tsx | 41 +- .../useCopyContextStoreAndActionMenuStates.ts | 238 ++--- .../hooks/useNavigateCommandMenu.ts | 200 ++-- .../useOpenCalendarEventInCommandMenu.ts | 81 +- .../hooks/useOpenEmailThreadInCommandMenu.ts | 81 +- .../useOpenFrontComponentInCommandMenu.ts | 58 +- .../useOpenMergeRecordsPageInCommandMenu.tsx | 66 +- .../hooks/useOpenRecordInCommandMenu.ts | 280 +++-- ...UpdateMultipleRecordsPageInCommandMenu.tsx | 18 +- .../hooks/useResetContextStoreStates.ts | 97 +- .../hooks/useSetGlobalCommandMenuContext.ts | 110 +- .../hooks/useUpdateCommandMenuPageInfo.ts | 77 +- .../hooks/useWorkflowCommandMenu.ts | 409 ++++---- .../CommandMenuCalendarEventPage.tsx | 4 +- .../CommandMenuFrontComponentPage.tsx | 4 +- .../viewableFrontComponentIdComponentState.ts | 4 +- .../CommandMenuMessageThreadPage.tsx | 4 +- .../useEmailThreadInCommandMenu.test.tsx | 4 +- .../hooks/useEmailThreadInCommandMenu.ts | 4 +- .../states/messageThreadComponentState.ts | 4 +- .../components/ChartFiltersSettings.tsx | 59 +- ...rtFiltersSettingsInitializeStateEffect.tsx | 10 +- .../page-layout/components/ChartSettings.tsx | 4 +- .../CommandMenuPageLayoutChartSettings.tsx | 6 +- .../CommandMenuPageLayoutGraphFilter.tsx | 6 +- .../CommandMenuPageLayoutTabSettings.tsx | 8 +- .../CommandMenuPageLayoutWidgetTypeSelect.tsx | 8 +- .../components/WidgetSettingsFooter.tsx | 3 +- .../hooks/useNavigatePageLayoutCommandMenu.ts | 11 +- ...ageLayoutFromContextStoreTargetedRecord.ts | 8 +- ...ageLayoutFromContextStoreTargetedRecord.ts | 6 +- .../useResetChartDraftFiltersSettings.ts | 67 +- .../hooks/useUpdateCurrentWidgetConfig.ts | 72 +- .../hooks/useUpdateGraphTypeConfig.ts | 221 ++-- .../page-layout/hooks/useWidgetInEditMode.ts | 6 +- ...asInitializedChartFiltersComponentState.ts | 4 +- .../components/CommandMenuRecordPage.tsx | 18 +- .../states/viewableRecordIdComponentState.ts | 4 +- ...iewableRecordNameSingularComponentState.ts | 4 +- .../CommandMenuWorkflowSelectAction.tsx | 4 +- .../hooks/useCommandMenuWorkflowIdOrThrow.ts | 4 +- .../commandMenuWorkflowIdComponentState.ts | 4 +- .../commandMenuWorkflowRunIdComponentState.ts | 4 +- ...commandMenuWorkflowStepIdComponentState.ts | 4 +- ...mandMenuWorkflowVersionIdComponentState.ts | 15 +- .../CommandMenuWorkflowCreateStepContent.tsx | 12 +- .../CommandMenuWorkflowEditStepContent.tsx | 4 +- ...CommandMenuWorkflowEditStepTypeContent.tsx | 10 +- .../CommandMenuWorkflowRunViewStepContent.tsx | 3 +- .../useCommandMenuWorkflowRunIdOrThrow.ts | 4 +- ...atorSubStepIterationIndexComponentState.ts | 4 +- .../CommandMenuWorkflowViewStepContent.tsx | 4 +- .../useCommandMenuWorkflowVersionIdOrThrow.ts | 4 +- ...ndMenuWorkflowSelectTriggerTypeContent.tsx | 4 +- ...mandMenuNavigationMorphItemsByPageState.ts | 4 +- .../states/commandMenuNavigationStackState.ts | 4 +- .../states/commandMenuPageInfoState.ts | 4 +- .../states/commandMenuPageState.ts | 4 +- .../states/commandMenuSearchState.ts | 4 +- ...MenuShouldFocusTitleInputComponentState.ts | 4 +- .../states/commandMenuWidthState.ts | 10 +- .../states/hasUserSelectedCommandState.ts | 4 +- .../states/isCommandMenuClosingState.ts | 4 +- .../states/isCommandMenuOpenedState.ts | 6 - .../MainContextStoreProviderEffect.tsx | 8 +- .../useContextStoreObjectMetadataItem.ts | 4 +- ...seContextStoreObjectMetadataItemOrThrow.ts | 4 +- ...seFindManyRecordsSelectedInContextStore.ts | 12 +- ...tStoreAnyFieldFilterValueComponentState.ts | 4 +- ...rrentObjectMetadataItemIdComponentState.ts | 4 +- ...contextStoreCurrentViewIdComponentState.ts | 4 +- ...ntextStoreCurrentViewTypeComponentState.ts | 4 +- .../contextStoreFilterGroupsComponentState.ts | 4 +- .../contextStoreFiltersComponentState.ts | 4 +- ...textStoreIsPageInEditModeComponentState.ts | 4 +- ...reNumberOfSelectedRecordsComponentState.ts | 4 +- ...StoreRecordShowParentViewComponentState.ts | 14 +- ...tStoreTargetedRecordsRuleComponentState.ts | 4 +- .../components/FavoriteFolderPicker.tsx | 5 +- .../components/FavoriteFolderPickerEffect.tsx | 45 +- .../components/FavoriteFolderPickerList.tsx | 6 +- .../FavoriteFolderPickerSearchInput.tsx | 4 +- .../hooks/useFavoriteFolderPicker.ts | 105 +- .../favoriteFolderIdPickerComponentState.ts | 4 +- ...voriteFolderPickerCheckedComponentState.ts | 4 +- ...avoriteFolderPickerComponentFamilyState.ts | 4 +- ...voriteFoldersSearchFilterComponentState.ts | 4 +- .../favoriteFoldersComponentSelector.ts | 21 +- .../HeadlessFrontComponentMountRoot.tsx | 5 +- .../useFrontComponentExecutionContext.ts | 4 +- .../hooks/useMountHeadlessFrontComponent.ts | 17 +- .../hooks/useUnmountHeadlessFrontComponent.ts | 17 +- ...lessFrontComponentMountedFamilySelector.ts | 25 +- .../mountedHeadlessFrontComponentIdsState.ts | 12 +- .../components/InformationBanner.tsx | 4 +- .../hooks/useDismissReconnectAccountBanner.ts | 4 +- .../informationBannerIsOpenComponentState.ts | 4 +- .../hooks/useExecuteLogicFunction.ts | 12 +- .../UserMetadataProviderInitialEffect.tsx | 32 +- .../components/NavigationMenuEditModeBar.tsx | 3 +- .../hooks/useHandleAddToNavigationDrop.ts | 14 +- .../components/MobileNavigationBar.tsx | 4 +- .../components/PageDragDropProvider.tsx | 66 +- ...igationDrawerItemForObjectMetadataItem.tsx | 4 +- .../hooks/useDeleteOneFieldMetadataItem.ts | 17 +- .../hooks/useGetFieldMetadataItemById.ts | 26 +- .../AdvancedFilterCommandMenuContainer.tsx | 4 +- ...ilterCommandMenuCreateRootFilterButton.tsx | 8 +- ...erCommandMenuRecordFilterOperandSelect.tsx | 4 +- ...ommandMenuValueFormCompositeFieldInput.tsx | 4 +- ...dvancedFilterCommandMenuValueFormInput.tsx | 15 +- .../AdvancedFilterDropdownFilterInput.tsx | 4 +- .../AdvancedFilterDropdownNumberInput.tsx | 7 +- ...vancedFilterFieldSelectDropdownContent.tsx | 4 +- .../AdvancedFilterFieldSelectMenu.tsx | 20 +- .../AdvancedFilterFieldSelectSearchInput.tsx | 4 +- ...dvancedFilterRecordFilterOperandSelect.tsx | 4 +- ...ancedFilterRecordFilterOptionsDropdown.tsx | 4 +- .../AdvancedFilterRootRecordFilterGroup.tsx | 4 +- .../AdvancedFilterSubFieldSelectMenu.tsx | 10 +- .../components/AdvancedFilterValueInput.tsx | 23 +- ...alueInputDropdownButtonClickableSelect.tsx | 4 +- ...ChildRecordFiltersAndRecordFilterGroups.ts | 6 +- .../hooks/useRecordFilterField.ts | 4 +- ...SelectFieldUsedInAdvancedFilterDropdown.ts | 21 +- ...eSetAdvancedFilterDropdownAllRowsStates.ts | 126 ++- ...rdFilterUsedInAdvancedFilterDropdownRow.ts | 57 +- ...LevelRecordFilterGroupComponentSelector.ts | 14 +- .../useFetchMoreRecordsWithPagination.ts | 213 ++-- .../useHandleFindManyRecordsCompleted.ts | 43 +- .../useLazyFetchMoreRecordsWithPagination.ts | 166 ++- .../hooks/useLazyFindManyRecords.ts | 114 +-- .../hooks/useLazyFindManyRecordsWithOffset.ts | 6 +- .../ObjectFilterDropdownActorSelect.tsx | 4 +- ...bjectFilterDropdownAnyFieldSearchInput.tsx | 4 +- .../ObjectFilterDropdownContentWrapper.tsx | 4 +- .../ObjectFilterDropdownCountrySelect.tsx | 12 +- .../ObjectFilterDropdownCurrencySelect.tsx | 12 +- .../ObjectFilterDropdownDateInput.tsx | 11 +- .../ObjectFilterDropdownDateTimeInput.tsx | 9 +- .../ObjectFilterDropdownFilterInput.tsx | 7 +- .../ObjectFilterDropdownFilterInputHeader.tsx | 4 +- ...lterDropdownInnerSelectOperandDropdown.tsx | 9 +- .../ObjectFilterDropdownNumberInput.tsx | 4 +- .../ObjectFilterDropdownOptionSelect.tsx | 8 +- .../ObjectFilterDropdownRecordSelect.tsx | 16 +- .../ObjectFilterDropdownSearchInput.tsx | 13 +- .../ObjectFilterDropdownSourceSelect.tsx | 14 +- .../ObjectFilterDropdownTextInput.tsx | 4 +- ...useApplyObjectFilterDropdownFilterValue.ts | 94 +- .../useApplyObjectFilterDropdownOperand.ts | 11 +- .../hooks/useEmptyRecordFilter.ts | 32 +- ...terDropdownSelectableFieldMetadataItems.ts | 7 +- .../useObjectFilterDropdownFilterValue.ts | 4 +- .../hooks/useResetFilterDropdown.ts | 77 +- ...UpsertObjectFilterDropdownCurrentFilter.ts | 29 +- ...adataItemIdUsedInDropdownComponentState.ts | 4 +- ...dataItemUsedInDropdownComponentSelector.ts | 18 +- ...downOperandSelectUnfoldedComponentState.ts | 4 +- ...ectFilterDropdownUnfoldedComponentState.ts | 4 +- ...nAnyFieldSearchIsSelectedComponentState.ts | 4 +- ...opdownCurrentRecordFilterComponentState.ts | 4 +- ...rDropdownFilterIsSelectedComponentState.ts | 4 +- ...IsSelectingCompositeFieldComponentState.ts | 4 +- ...FilterDropdownSearchInputComponentState.ts | 4 +- ...pdownSelectedOptionValuesComponentState.ts | 4 +- ...rDropdownSubMenuFieldTypeComponentState.ts | 4 +- ...selectedOperandInDropdownComponentState.ts | 4 +- ...ubFieldNameUsedInDropdownComponentState.ts | 4 +- ...ctOptionsDropdownCalendarFieldsContent.tsx | 4 +- ...jectOptionsDropdownCalendarViewContent.tsx | 7 +- .../ObjectOptionsDropdownCustomView.tsx | 12 +- .../ObjectOptionsDropdownDefaultView.tsx | 4 +- ...tionsDropdownHiddenRecordGroupsContent.tsx | 11 +- .../ObjectOptionsDropdownLayoutContent.tsx | 11 +- ...jectOptionsDropdownLayoutOpenInContent.tsx | 6 +- .../ObjectOptionsDropdownMenuViewName.tsx | 12 +- ...ptionsDropdownRecordGroupFieldsContent.tsx | 7 +- ...tOptionsDropdownRecordGroupSortContent.tsx | 8 +- ...jectOptionsDropdownRecordGroupsContent.tsx | 14 +- .../hooks/useObjectOptionsForBoard.ts | 8 +- .../hooks/useProcessOptionDropdownDragEnd.ts | 6 +- .../hooks/useSearchRecordGroupField.ts | 4 +- .../useSetViewTypeFromLayoutOptionsMenu.ts | 240 ++--- .../hooks/useUpdateObjectViewOptions.ts | 10 +- ...ptionsDropdownSearchInputComponentState.ts | 4 +- .../components/ObjectSortDropdownButton.tsx | 15 +- .../useResetRecordSortDropdownSearchInput.ts | 19 +- .../hooks/useResetSortDropdown.ts | 6 +- ...ctionDropdownMenuUnfoldedComponentState.ts | 4 +- ...ctSortDropdownSearchInputComponentState.ts | 4 +- ...lectedRecordSortDirectionComponentState.ts | 4 +- .../RecordBoardBodyEscapeHotkeyEffect.tsx | 4 +- .../RecordBoardClickOutsideEffect.tsx | 5 +- .../components/RecordBoardColumns.tsx | 4 +- .../components/RecordBoardContainer.tsx | 3 +- .../RecordBoardDataChangedEffect.tsx | 236 ++--- .../components/RecordBoardDragDropContext.tsx | 85 +- ...rdBoardFetchMoreInViewTriggerComponent.tsx | 14 +- .../components/RecordBoardHeader.tsx | 4 +- .../components/RecordBoardQueryEffect.tsx | 22 +- .../RecordBoardScrollToFocusedCardEffect.tsx | 13 +- .../RecordBoardSelectRecordsEffect.tsx | 12 +- .../hooks/useActiveRecordBoardCard.ts | 76 +- .../hooks/useFocusedRecordBoardCard.ts | 149 +-- ...uldInitializeRecordBoardForUpdateInputs.ts | 8 +- .../hooks/useRecordBoardCardHotkeys.ts | 8 +- .../hooks/useRecordBoardCardNavigation.ts | 265 +++-- .../hooks/useRecordBoardSelection.ts | 69 +- .../hooks/useRemoveRecordsFromBoard.ts | 135 +-- ...useRemoveSelectedRecordsFromRecordBoard.ts | 120 ++- .../hooks/useResetRecordBoardSelection.ts | 59 +- .../record-board/hooks/useSelectAllCards.ts | 70 +- .../hooks/useSetRecordIdsForColumn.ts | 100 +- .../hooks/useTriggerRecordBoardFetchMore.ts | 344 ++++--- .../useTriggerRecordBoardInitialQuery.ts | 198 ++-- .../RecordBoardCardCellEditModePortal.tsx | 4 +- ...ecordBoardCardCellHoveredPortalContent.tsx | 8 +- .../RecordBoardCardInputContextProvider.tsx | 4 +- .../components/RecordBoardCard.tsx | 22 +- .../components/RecordBoardCardBody.tsx | 8 +- .../RecordBoardCardDraggableContainer.tsx | 4 +- .../components/RecordBoardCardHeader.tsx | 17 +- .../RecordBoardCardMultiDragCounterChip.tsx | 4 +- .../RecordBoardCardMultiDragPreview.tsx | 4 +- .../RecordBoardCardMultiDragStack.tsx | 4 +- .../useRecordBoardCardMetadataFromPosition.ts | 9 +- ...BoardCardEditModePositionComponentState.ts | 4 +- ...ordBoardCardHoverPositionComponentState.ts | 15 +- ...recordBoardCardIsExpandedComponentState.ts | 4 +- .../components/RecordBoardColumn.tsx | 11 +- ...BoardColumnCardContainerSkeletonLoader.tsx | 4 +- .../RecordBoardColumnCardsContainer.tsx | 6 +- .../components/RecordBoardColumnHeader.tsx | 11 +- ...mnHeaderAggregateDropdownFieldsContent.tsx | 10 +- ...nHeaderAggregateDropdownOptionsContent.tsx | 10 +- .../RecordBoardColumnHeaderWrapper.tsx | 11 +- .../RecordBoardColumnNewRecordButton.tsx | 4 +- .../aggregateOperationComponentState.ts | 4 +- ...dIdsForAggregateOperationComponentState.ts | 4 +- ...iveRecordBoardCardIndexesComponentState.ts | 4 +- ...sedRecordBoardCardIndexesComponentState.ts | 4 +- ...cordBoardCardActiveComponentFamilyState.ts | 4 +- ...ecordBoardCardFocusActiveComponentState.ts | 4 +- ...ordBoardCardFocusedComponentFamilyState.ts | 4 +- ...rdBoardCardSelectedComponentFamilyState.ts | 4 +- ...BoardFetchingRecordsByColumnFamilyState.ts | 14 +- ...ecordBoardQueryIdentifierComponentState.ts | 4 +- .../lastRecordGroupIdsComponentState.ts | 6 +- ...CurrentGroupByQueryOffsetComponentState.ts | 4 +- ...recordBoardIsFetchingMoreComponentState.ts | 4 +- ...ecordBoardShouldFetchMoreComponentState.ts | 4 +- ...ldFetchMoreInColumnComponentFamilyState.ts | 4 +- ...allCardsSelectedStatusComponentSelector.ts | 14 +- ...BoardSelectedRecordIdsComponentSelector.ts | 24 +- .../components/RecordCalendarAddNew.tsx | 16 +- .../RecordCalendarSSESubscribeEffect.tsx | 4 +- .../components/RecordCalendarTopBar.tsx | 4 +- .../RecordIndexCalendarDataLoaderEffect.tsx | 19 +- ...ordIndexCalendarSelectedDateInitEffect.tsx | 6 +- .../hooks/useRecordCalendarGroupByRecords.ts | 4 +- .../month/components/RecordCalendarMonth.tsx | 4 +- .../components/RecordCalendarMonthBodyDay.tsx | 8 +- .../RecordCalendarMonth.stories.tsx | 52 +- .../hooks/useRecordCalendarMonthDaysRange.tsx | 5 +- .../useRecordCalendarQueryDateRangeFilter.tsx | 14 +- .../RecordCalendarCardCellEditModePortal.tsx | 4 +- .../RecordCalendarCardCellHoveredPortal.tsx | 4 +- ...rdCalendarCardCellHoveredPortalContent.tsx | 8 +- ...RecordCalendarCardInputContextProvider.tsx | 4 +- .../components/RecordCalendarCard.tsx | 8 +- .../components/RecordCalendarCardBody.tsx | 8 +- .../RecordCalendarCardDraggableContainer.tsx | 4 +- .../components/RecordCalendarCardHeader.tsx | 12 +- ...eRecordCalendarCardMetadataFromPosition.ts | 9 +- ...alendarCardSelectedComponentFamilyState.ts | 4 +- ...endarCardEditModePositionComponentState.ts | 4 +- ...CalendarCardHoverPositionComponentState.ts | 4 +- ...ecordCalendarSelectedDateComponentState.ts | 4 +- .../recordCalendarRecordIdsComponentState.ts | 4 +- ...ecordCalendarSelectedDateComponentState.ts | 4 +- ...lendarDayRecordsComponentFamilySelector.ts | 28 +- ...endarSelectedRecordIdsComponentSelector.ts | 26 +- .../selectors/useRecordCalendarSelection.ts | 46 +- .../hooks/__tests__/useEndRecordDrag.test.tsx | 13 +- .../__tests__/useStartRecordDrag.test.tsx | 50 +- .../record-drag/hooks/useEndRecordDrag.ts | 124 ++- .../hooks/useProcessBoardCardDrop.ts | 45 +- .../hooks/useProcessCalendarCardDrop.ts | 202 ++-- .../useProcessTableWithGroupRecordDrop.ts | 140 +-- .../useProcessTableWithoutGroupRecordDrop.ts | 220 ++-- .../record-drag/hooks/useStartRecordDrag.ts | 105 +- ...WithoutGroupDragAndDropOptimisticUpdate.ts | 139 ++- .../hooks/useUpdateDroppedRecordOnBoard.ts | 246 ++--- .../states/draggedRecordIdsComponentState.ts | 4 +- .../states/isDraggingRecordComponentState.ts | 4 +- .../states/isMultiDragActiveComponentState.ts | 4 +- ...PrimaryDragMultipleComponentFamilyState.ts | 4 +- ...condaryDragMultipleComponentFamilyState.ts | 4 +- .../originalDragSelectionComponentState.ts | 4 +- .../primaryDraggedRecordIdComponentState.ts | 4 +- .../__tests__/extractRecordPositions.test.ts | 92 +- .../utils/extractRecordPositions.ts | 14 +- .../record-drag/utils/processGroupDrop.ts | 20 +- .../RecordFieldListCellEditModePortal.tsx | 4 +- .../RecordFieldListCellHoveredPortal.tsx | 4 +- ...ecordFieldListCellHoveredPortalContent.tsx | 8 +- .../RecordFieldListInputContextProvider.tsx | 4 +- .../components/RecordFieldList.tsx | 4 +- .../useFieldListFieldMetadataFromPosition.ts | 6 +- ...lMorphRelationSectionDropdownManyToOne.tsx | 6 +- ...lMorphRelationSectionDropdownOneToMany.tsx | 15 +- .../RecordDetailRelationRecordsListItem.tsx | 4 +- .../RecordDetailRelationSection.tsx | 10 +- ...ordDetailRelationSectionDropdownToMany.tsx | 26 +- ...cordDetailRelationSectionDropdownToOne.tsx | 17 +- ...ionRelatedRecordsWithObjectNameSingular.ts | 12 +- ...dListCellEditModePositionComponentState.ts | 4 +- ...ordFieldListHoverPositionComponentState.ts | 15 +- .../hooks/useChangeRecordFieldVisibility.ts | 4 +- .../record-field/hooks/useMoveRecordField.ts | 120 ++- .../hooks/useRecordsFieldVisibleGqlFields.ts | 4 +- .../hooks/useReorderVisibleRecordFields.ts | 68 +- .../hooks/useUpdateRecordField.ts | 82 +- .../hooks/useUpsertRecordField.ts | 66 +- .../currentRecordFieldsComponentState.ts | 4 +- .../visibleRecordFieldsComponentSelector.ts | 125 +-- .../components/FormSingleRecordPicker.tsx | 6 +- .../hooks/__tests__/useIsFieldEmpty.test.tsx | 32 +- .../record-field/ui/hooks/useClearField.ts | 120 ++- .../ui/hooks/useInitDraftValue.ts | 99 +- .../ui/hooks/useIsRecordDeleted.ts | 14 +- .../ui/hooks/useOpenFieldInputEditMode.ts | 317 +++--- .../useOpenJunctionRelationFieldInput.ts | 201 ++-- .../record-field/ui/hooks/usePersistField.ts | 340 ++++--- .../ui/hooks/useRecordFieldInput.ts | 23 +- .../ui/hooks/useToggleEditOnlyInput.ts | 64 +- .../useUpdateJunctionRelationFromCell.ts | 219 ++-- ...ationFromManyFieldDisplay.perf.stories.tsx | 7 +- .../ui/meta-types/hooks/useAddressField.ts | 16 +- .../ui/meta-types/hooks/useArrayField.ts | 16 +- .../ui/meta-types/hooks/useBooleanField.ts | 16 +- .../ui/meta-types/hooks/useChipField.ts | 5 +- .../ui/meta-types/hooks/useCurrencyField.ts | 16 +- .../ui/meta-types/hooks/useDateField.ts | 16 +- .../ui/meta-types/hooks/useDateTimeField.ts | 12 +- .../ui/meta-types/hooks/useEmailsField.ts | 16 +- .../ui/meta-types/hooks/useFilesField.ts | 16 +- .../ui/meta-types/hooks/useFullNameField.ts | 16 +- .../ui/meta-types/hooks/useJsonField.ts | 16 +- .../ui/meta-types/hooks/useLinksField.ts | 16 +- .../meta-types/hooks/useMorphRelationField.ts | 15 +- .../meta-types/hooks/useMultiSelectField.ts | 16 +- .../ui/meta-types/hooks/useNumberField.ts | 16 +- .../ui/meta-types/hooks/usePhonesField.ts | 16 +- .../ui/meta-types/hooks/useRatingField.ts | 14 +- .../ui/meta-types/hooks/useRelationField.ts | 15 +- .../ui/meta-types/hooks/useSelectField.ts | 16 +- .../ui/meta-types/hooks/useTextField.ts | 16 +- .../input/components/BooleanFieldInput.tsx | 2 +- .../input/components/EmailsFieldInput.tsx | 4 +- .../input/components/FilesFieldInput.tsx | 4 +- .../input/components/LinksFieldInput.tsx | 4 +- .../MorphRelationManyToOneFieldInput.tsx | 6 +- .../MorphRelationOneToManyFieldInput.tsx | 4 +- .../input/components/PhonesFieldInput.tsx | 4 +- .../RelationManyToOneFieldInput.tsx | 11 +- .../RelationOneToManyFieldInput.tsx | 176 ++-- .../__stories__/ArrayFieldInput.stories.tsx | 2 +- .../__stories__/BooleanFieldInput.stories.tsx | 4 +- .../DateTimeFieldInput.stories.tsx | 2 +- .../__stories__/EmailsFieldInput.stories.tsx | 2 +- .../__stories__/LinksFieldInput.stories.tsx | 2 +- .../__stories__/PhonesFieldInput.stories.tsx | 2 +- .../RelationManyToOneFieldInput.stories.tsx | 11 +- .../RelationOneToManyFieldInput.stories.tsx | 8 +- .../useAddNewRecordAndOpenRightDrawer.ts | 6 +- .../input/hooks/useMorphPersistManyToOne.ts | 153 ++- .../input/hooks/useOpenFilesFieldInput.tsx | 281 +++-- ...seOpenMorphRelationManyToOneFieldInput.tsx | 127 ++- ...seOpenMorphRelationOneToManyFieldInput.tsx | 219 ++-- .../useOpenRelationFromManyFieldInput.tsx | 166 ++- .../hooks/useOpenRelationToOneFieldInput.tsx | 88 +- ...UpdateMorphRelationOneToManyFieldInput.tsx | 84 +- .../useUpdateRelationOneToManyFieldInput.tsx | 7 +- .../ui/states/filesFieldUploadState.ts | 16 - .../ui/states/lastShowPageRecordId.ts | 4 +- ...ecordFieldInputDraftValueComponentState.ts | 4 +- ...dFieldInputIsFieldInErrorComponentState.ts | 4 +- ...FieldInputLayoutDirectionComponentState.ts | 4 +- ...putLayoutDirectionLoadingComponentState.ts | 4 +- .../useRemoveRecordFilterGroup.test.tsx | 31 +- .../useUpsertRecordFilterGroup.test.tsx | 21 +- .../hooks/useRemoveRecordFilterGroup.ts | 78 +- .../useRemoveRootRecordFilterGroupIfEmpty.ts | 85 +- .../hooks/useUpsertRecordFilterGroup.ts | 85 +- ...currentRecordFilterGroupsComponentState.ts | 4 +- .../__tests__/useRemoveRecordFilter.test.tsx | 27 +- .../__tests__/useUpsertRecordFilter.test.tsx | 23 +- ...erFromObjectFilterDropdownCurrentStates.ts | 110 +- .../hooks/useRemoveRecordFilter.ts | 46 +- .../hooks/useUpsertRecordFilter.ts | 54 +- .../anyFieldFilterValueComponentState.ts | 14 +- .../currentRecordFiltersComponentState.ts | 4 +- .../states/hasAnySoftDeleteFilterOnView.ts | 17 +- .../RecordGroupMenuItemDraggable.tsx | 7 +- .../RecordGroupReorderConfirmationModal.tsx | 4 +- .../hooks/useCurrentRecordGroupDefinition.ts | 7 +- .../hooks/useRecordGroupActions.ts | 8 +- .../hooks/useRecordGroupFilter.ts | 4 +- .../useRecordGroupReorderConfirmationModal.ts | 9 +- .../hooks/useRecordGroupVisibility.ts | 55 +- .../hooks/useReorderRecordGroups.ts | 121 +-- .../record-group/hooks/useSetRecordGroups.ts | 166 ++- .../hooks/useShouldHideRecordGroup.ts | 8 +- ...mptyRecordGroupByIdComponentFamilyState.ts | 4 +- .../recordGroupDefinitionFamilyState.ts | 6 +- .../states/recordGroupIdsComponentState.ts | 4 +- ...vailableRecordGroupIdsComponentSelector.ts | 65 +- .../hasRecordGroupsComponentSelector.ts | 12 +- .../hiddenRecordGroupIdsComponentSelector.ts | 16 +- ...recordGroupDefinitionsComponentSelector.ts | 53 +- ...upFromGroupValueComponentFamilySelector.ts | 21 +- ...leRecordGroupIdsComponentFamilySelector.ts | 38 +- .../components/RecordIndexContainer.tsx | 4 +- ...textStoreNumberOfSelectedRecordsEffect.tsx | 14 +- .../components/RecordIndexContainerGater.tsx | 15 +- ...RecordIndexFiltersToContextStoreEffect.tsx | 29 +- .../RecordIndexGroupAggregateQueryEffect.tsx | 12 +- .../RecordIndexGroupAggregatesDataLoader.tsx | 8 +- ...ecordIndexLoadBaseOnContextStoreEffect.tsx | 4 +- .../components/RecordIndexPageHeader.tsx | 6 +- .../RecordIndexPageKanbanAddMenuItem.tsx | 7 +- .../RecordIndexRemoveSortingModal.tsx | 4 +- .../RecordIndexTableContainerEffect.tsx | 70 +- .../hooks/useRecordIndexLazyFetchRecords.ts | 19 +- .../useFindManyRecordIndexTableParams.ts | 10 +- .../hooks/useHandleIndexIdentifierClick.ts | 4 +- .../hooks/useHandleRecordGroupField.ts | 232 ++--- .../hooks/useHandleToggleColumnSort.ts | 68 +- .../hooks/useHandleToggleTrashColumnFilter.ts | 19 +- .../hooks/useLoadRecordIndexStates.ts | 210 ++-- .../hooks/useOpenRecordFromIndexView.ts | 98 +- ...seRecordIndexFieldMetadataDerivedStates.ts | 4 +- ...useRecordIndexGroupCommonQueryVariables.ts | 15 +- .../useRecordIndexGroupsAggregatesGroupBy.ts | 8 +- ...useRecordIndexIdFromCurrentContextStore.ts | 4 +- .../useSetRecordIndexAggregateDisplayLabel.ts | 35 +- ...ggregateDisplayValueForRecordGroupValue.ts | 84 +- ...ndexAggregateDisplayLabelComponentState.ts | 4 +- ...yValueForGroupValueComponentFamilyState.ts | 4 +- ...recordIndexCalendarFieldMetadataIdState.ts | 4 +- .../states/recordIndexCalendarLayoutState.ts | 12 +- ...xEntityCountByGroupComponentFamilyState.ts | 14 +- .../recordIndexFieldDefinitionsState.ts | 4 +- ...ggregateFieldMetadataItemComponentState.ts | 4 +- ...exGroupAggregateOperationComponentState.ts | 4 +- ...rdIndexGroupFieldMetadataComponentState.ts | 4 +- ...sFetchedAllRecordsByGroupComponentState.ts | 4 +- .../states/recordIndexOpenRecordInState.ts | 12 +- ...ecordIndexRecordGroupSortComponentState.ts | 4 +- ...GroupsAreInInitialLoadingComponentState.ts | 4 +- ...dexRecordIdsByGroupComponentFamilyState.ts | 4 +- ...ouldHideEmptyRecordGroupsComponentState.ts | 4 +- .../states/recordIndexViewTypeState.ts | 4 +- ...rdIdsOfAllRecordGroupsComponentSelector.ts | 24 +- ...RecordIdsWithoutGroupsComponentSelector.ts | 15 +- ...ecordIndexAllRecordIdsComponentSelector.ts | 71 +- .../recordIndexHasRecordsComponentSelector.ts | 12 +- ...rdGroupIsDraggableSortComponentSelector.ts | 11 +- ...ecordIndexLabelIdentifierComponentState.ts | 4 +- .../components/RecordInlineCellEditMode.tsx | 10 +- .../hooks/useMergeRecordsSelectedRecords.ts | 14 +- ...RecordAndObjectMetadataItemFromRecordId.ts | 11 +- .../components/MultipleRecordPicker.tsx | 57 +- .../MultipleRecordPickerFetchMoreLoader.tsx | 62 +- .../MultipleRecordPickerLoadingEffect.tsx | 12 +- .../MultipleRecordPickerMenuItemContent.tsx | 17 +- .../MultipleRecordPickerMenuItems.tsx | 57 +- .../MultipleRecordPickerSearchInput.tsx | 41 +- .../hooks/useMultipleRecordPickerOpen.ts | 56 +- .../useMultipleRecordPickerPerformSearch.ts | 588 ++++++----- ...ecordPickerIsFetchingMoreComponentState.ts | 4 +- ...ipleRecordPickerIsLoadingComponentState.ts | 4 +- .../multipleRecordPickerPaginationState.ts | 4 +- ...dPickerPickableMorphItemsComponentState.ts | 4 +- ...eRecordPickerSearchFilterComponentState.ts | 4 +- ...chableObjectMetadataItemsComponentState.ts | 4 +- ...rShouldShowInitialLoadingComponentState.ts | 4 +- ...dPickerShouldShowSkeletonComponentState.ts | 4 +- .../searchRecordStoreComponentFamilyState.ts | 4 +- ...PickerIsSelectedComponentFamilySelector.ts | 9 +- .../multipleRecordPickerPaginationSelector.ts | 26 +- ...ckableMorphItemsLengthComponentSelector.ts | 9 +- ...ecordIdsMatchingSearchComponentSelector.ts | 11 +- ...ickableMorphItemComponentFamilySelector.ts | 9 +- .../components/SingleRecordPicker.tsx | 4 +- .../SingleRecordPickerLoadingEffect.tsx | 4 +- .../components/SingleRecordPickerMenuItem.tsx | 11 +- .../SingleRecordPickerMenuItems.tsx | 10 +- .../SingleRecordPickerMenuItemsWithSearch.tsx | 4 +- .../useSingleRecordPickerRecords.test.tsx | 4 +- .../hooks/useSingleRecordPickerOpen.ts | 54 +- .../useSingleRecordPickerPerformSearch.ts | 48 +- .../hooks/useSingleRecordPickerRecords.ts | 6 +- .../hooks/useSingleRecordPickerSearch.ts | 6 +- ...eRecordPickerSearchFilterComponentState.ts | 4 +- ...leRecordPickerSearchQueryComponentState.ts | 4 +- ...chableObjectMetadataItemsComponentState.ts | 4 +- ...gleRecordPickerSelectedIdComponentState.ts | 15 +- ...rShouldShowInitialLoadingComponentState.ts | 4 +- ...dPickerShouldShowSkeletonComponentState.ts | 4 +- .../states/viewableRecordIdState.ts | 4 +- .../states/viewableRecordNameSingularState.ts | 4 +- .../PageLayoutRecordPageRenderer.tsx | 13 +- ...ainerContextStoreTargetedRecordsEffect.tsx | 6 +- .../components/RecordShowEffect.tsx | 24 +- .../record-show/components/SummaryCard.tsx | 23 +- .../hooks/useRecordShowContainerData.ts | 7 +- .../hooks/useRecordShowPagePagination.ts | 6 +- .../record-sort/hooks/useRemoveRecordSort.ts | 44 +- .../record-sort/hooks/useUpsertRecordSort.ts | 55 +- .../currentRecordSortsComponentState.ts | 4 +- .../useUpsertRecordsInStore.test.tsx | 12 +- .../hooks/useRecordFieldValue.tsx | 25 +- .../hooks/useUpsertRecordsInStore.ts | 100 +- .../states/recordLoadingFamilyState.ts | 4 +- .../states/recordStoreFamilyState.ts | 4 +- .../selectors/recordStoreFamilySelector.ts | 20 - .../selectors/recordStoreFamilySelectorV2.ts | 6 +- .../recordStoreFieldValueSelector.ts | 87 -- ... recordStoreIdentifierFamilySelectorV2.ts} | 28 +- .../recordStoreIdentifiersSelector.ts | 4 +- ...anyValueWithObjectNameFamilySelectorV2.ts} | 29 +- .../selectors/recordStoreRecordsSelector.ts | 16 - .../selectors/recordStoreRecordsSelectorV2.ts | 21 + .../record-table/components/RecordTable.tsx | 9 +- .../RecordTableColumnWidthEffect.tsx | 10 +- .../components/RecordTableContent.tsx | 55 +- .../components/RecordTableContextProvider.tsx | 10 +- .../components/RecordTableEmpty.tsx | 13 +- .../RecordTableNoRecordGroupAddNew.tsx | 48 +- ...dTableNoRecordGroupBodyContextProvider.tsx | 5 +- .../RecordTableNoRecordGroupRows.tsx | 4 +- .../components/RecordTableRecordGroupRows.tsx | 10 +- .../RecordTableScrollAndZIndexEffect.tsx | 19 +- .../RecordTableScrollToFocusedCellEffect.tsx | 6 +- .../RecordTableScrollToFocusedRowEffect.tsx | 9 +- .../components/RecordTableWidthEffect.tsx | 8 +- .../perf/RecordTableCell.perf.stories.tsx | 23 +- .../components/RecordTableEmptyHandler.tsx | 7 +- .../components/RecordTableEmptyState.tsx | 4 +- .../RecordTableEmptyStateDisplay.tsx | 4 +- .../RecordTableEmptyStateSoftDelete.tsx | 4 +- .../useCloseCurrentTableCellInEditMode.ts | 38 +- .../internal/useHandleContainerMouseEnter.ts | 37 +- .../hooks/internal/useLeaveTableFocus.ts | 6 +- .../internal/useResetTableRowSelection.ts | 68 +- .../hooks/internal/useSelectAllRows.ts | 68 +- .../internal/useSetAllRowSelectedState.ts | 19 +- .../hooks/internal/useSetRecordTableData.ts | 195 ++-- .../hooks/useActiveRecordTableRow.ts | 70 +- .../hooks/useBuildRecordInputFromFilters.ts | 4 +- .../hooks/useCreateNewIndexRecord.ts | 188 ++-- .../hooks/useFocusedRecordTableRow.ts | 201 ++-- .../useRecordTableLastColumnWidthToFill.ts | 6 +- .../hooks/useRecordTableMoveFocusedCell.ts | 239 ++--- .../hooks/useRecordTableMoveFocusedRow.ts | 96 +- .../RecordTableBodyEscapeHotkeyEffect.tsx | 4 +- ...dyNoRecordGroupDragDropContextProvider.tsx | 39 +- ...BodyRecordGroupDragDropContextProvider.tsx | 39 +- ...cordTableBodyVirtualizedDraggableClone.tsx | 4 +- .../RecordTableNoRecordGroupBody.tsx | 7 +- .../RecordTableRecordGroupBodyEffect.tsx | 12 +- .../RecordTableRecordGroupBodyEffects.tsx | 6 +- .../RecordTableRecordGroupsBody.tsx | 11 +- .../components/RecordTableCellEditMode.tsx | 10 +- .../RecordTableCellEditModePortal.tsx | 9 +- ...rdTableCellFieldContextLabelIdentifier.tsx | 4 +- .../RecordTableCellFirstRowFirstColumn.tsx | 10 +- .../RecordTableCellFocusedPortal.tsx | 13 +- .../RecordTableCellFocusedPortalContent.tsx | 10 +- .../RecordTableCellHoveredPortal.tsx | 11 +- .../RecordTableCellHoveredPortalContent.tsx | 8 +- .../RecordTableCellPortalContexts.tsx | 6 +- .../components/RecordTableCellPortals.tsx | 4 +- .../useMoveHoverToCurrentCell.test.tsx | 36 +- .../useSetIsRecordTableFocusActive.test.tsx | 47 +- .../useCloseRecordTableCellInGroup.test.tsx | 5 +- .../useCloseRecordTableCellNoGroup.test.tsx | 5 +- ...eCurrentlyFocusedRecordTableCellFocusId.ts | 4 +- .../hooks/useFocusRecordTableCell.ts | 72 +- .../hooks/useMoveHoverToCurrentCell.ts | 34 +- .../hooks/useOpenRecordTableCell.ts | 176 ++-- .../useSetIsRecordTableCellFocusActive.ts | 56 +- .../hooks/useTriggerActionMenuDropdown.ts | 50 +- .../hooks/useUnfocusRecordTableCell.ts | 63 +- ...ordTableColumnAggregateFooterValueCell.tsx | 13 +- ...egateRecordsForRecordTableColumnFooter.tsx | 17 +- .../hooks/useViewFieldAggregateOperation.tsx | 9 +- ...gateOperationForViewFieldFamilySelector.ts | 28 +- .../viewFieldAggregateOperationState.ts | 4 +- .../components/RecordTableColumnHead.tsx | 4 +- .../RecordTableHeaderAddColumnButton.tsx | 15 +- .../components/RecordTableHeaderCell.tsx | 17 +- .../RecordTableHeaderCheckboxColumn.tsx | 21 +- .../RecordTableHeaderDragDropColumn.tsx | 15 +- .../components/RecordTableHeaderFirstCell.tsx | 17 +- .../RecordTableHeaderFirstScrollableCell.tsx | 21 +- ...bleHeaderLabelIdentifierCellPlusButton.tsx | 4 +- .../RecordTableHeaderLastEmptyColumn.tsx | 15 +- .../RecordTableHeaderResizeHandler.tsx | 4 +- .../useOpenRecordFilterChipFromTableHeader.ts | 4 +- .../hooks/useResizeTableHeader.ts | 98 +- .../RecordTableDraggableTrFirstRowOfGroup.tsx | 4 +- .../components/RecordTableFieldsCells.tsx | 4 +- .../components/RecordTableFirstRowOfGroup.tsx | 4 +- .../components/RecordTableRow.tsx | 12 +- .../RecordTableRowMultiDragCounterChip.tsx | 4 +- .../RecordTableRowMultiDragPreview.tsx | 4 +- .../components/RecordTableTr.tsx | 23 +- .../hooks/useIsRecordSecondaryDragged.ts | 4 +- .../hooks/useRecordTableRowHotkeys.ts | 9 +- .../hooks/useSetCurrentRowSelected.ts | 89 +- .../hasUserSelectedAllRowsFamilyState.ts | 4 +- .../isAtLeastOneTableRowSelectedSelector.ts | 24 +- ...rdIdFirstOfGroupComponentFamilySelector.ts | 37 +- .../isRowSelectedComponentFamilyState.ts | 4 +- .../lastSelectedRowIndexComponentState.ts | 4 +- .../RecordTableRecordGroupSection.tsx | 22 +- .../RecordTableRecordGroupSectionAddNew.tsx | 11 +- .../RecordTableRecordGroupSectionLoadMore.tsx | 4 +- ...dGroupTableSectionToggledComponentState.ts | 4 +- ...activeRecordTableRowIndexComponentState.ts | 4 +- ...ocusedRecordTableRowIndexComponentState.ts | 4 +- ...ecordTableCellFocusActiveComponentState.ts | 4 +- ...RecordTableInitialLoadingComponentState.ts | 4 +- ...ecordTableRowActiveComponentFamilyState.ts | 4 +- ...RecordTableRowFocusActiveComponentState.ts | 4 +- ...cordTableRowFocusedComponentFamilyState.ts | 4 +- ...TableScrolledHorizontallyComponentState.ts | 4 +- ...rdTableScrolledVerticallyComponentState.ts | 4 +- .../isSoftDeleteFilterActiveComponentState.ts | 4 +- .../states/numberOfTableRowsComponentState.ts | 4 +- ...TableCellEditModePositionComponentState.ts | 4 +- .../recordTableFocusPositionComponentState.ts | 4 +- .../recordTableHoverPositionComponentState.ts | 4 +- .../states/recordTableWidthComponentState.ts | 4 +- .../states/resizeFieldOffsetComponentState.ts | 4 +- .../resizedFieldMetadataIdComponentState.ts | 4 +- .../allRowsSelectedStatusComponentSelector.ts | 24 +- .../isAtLeastOneTableRowSelectedSelector.ts | 26 + .../isSomeCellInEditModeComponentSelector.ts | 30 +- .../selectedRowIdsComponentSelector.ts | 23 +- .../unselectedRowIdsComponentSelector.ts | 23 +- ...actRecordTableFirstColumnComponentState.ts | 6 +- .../states/tableWidthResizeIsActivedState.ts | 4 +- ...ecordGroupScrollToPreviousRecordEffect.tsx | 8 +- .../RecordTableRowVirtualizedContainer.tsx | 8 +- ...ecordTableRowVirtualizedDebugRowHelper.tsx | 13 +- .../RecordTableRowVirtualizedFullData.tsx | 15 +- .../RecordTableRowVirtualizedRouterLevel1.tsx | 6 +- .../RecordTableRowVirtualizedRouterLevel2.tsx | 4 +- .../RecordTableVirtualizedBodyPlaceholder.tsx | 4 +- .../RecordTableVirtualizedDebugHelper.tsx | 4 +- ...leVirtualizedFieldMetadataUpdateEffect.tsx | 12 +- ...dTableVirtualizedInitialDataLoadEffect.tsx | 24 +- ...cordTableVirtualizedRowTreadmillEffect.tsx | 258 +++-- ...cordTableVirtualizedSSESubscribeEffect.tsx | 8 +- ...ResetTableVirtualizationForUpdateInputs.ts | 6 +- .../hooks/useLoadRecordsToVirtualRows.ts | 132 +-- .../hooks/useProcessTreadmillScrollTop.ts | 189 ++-- .../hooks/useReapplyRowSelection.ts | 4 +- .../hooks/useResetTableFocuses.ts | 4 +- ...seResetVirtualizationBecauseDataChanged.ts | 170 ++-- .../hooks/useResetVirtualizedRowTreadmill.ts | 47 +- .../hooks/useTriggerFetchPages.ts | 272 +++-- .../useTriggerInitialRecordTableDataLoad.ts | 222 ++-- ...tatusByRealIndexComponentFamilySelector.ts | 43 +- ...aLoadingStatusByRealIndexComponentState.ts | 15 +- .../states/dataPagesLoadedComponentState.ts | 4 +- ...ngVirtualTableDataLoadingComponentState.ts | 4 +- ...extStoreVirtualizedViewIdComponentState.ts | 4 +- ...alizedVisibleRecordFieldsComponentState.ts | 4 +- ...ssedFieldMetadataUpdateIdComponentState.ts | 4 +- .../states/lastRealIndexSetComponentState.ts | 4 +- ...ecordTableQueryIdentifierComponentState.ts | 4 +- .../lastScrollMeasurementsComponentState.ts | 4 +- .../lastScrollPositionComponentState.ts | 4 +- .../lowDetailsActivatedComponentState.ts | 13 +- ...IndexByVirtualIndexComponentFamilyState.ts | 4 +- ...ordIdByRealIndexComponentFamilySelector.ts | 40 +- .../recordIdByRealIndexComponentState.ts | 4 +- .../states/scrollAtRealIndexComponentState.ts | 4 +- ...ableHasAnyFilterOrSortComponentSelector.ts | 16 +- ...mberOfRecordsToVirtualizeComponentState.ts | 4 +- .../components/RecordTitleCell.tsx | 16 +- .../components/RecordTitleCellContainer.tsx | 4 +- .../RecordTitleCellTextFieldDisplay.tsx | 4 +- .../RecordTitleCellUuidFieldDisplay.tsx | 4 +- .../hooks/useOpenNewRecordTitleCell.ts | 57 +- .../hooks/useRecordTitleCell.tsx | 131 +-- .../isTitleCellInEditModeComponentState.ts | 4 +- .../useUpdateMultipleRecordsActions.test.ts | 8 +- .../hooks/useUpdateMultipleRecordsActions.ts | 10 +- ...jectRecordsSpreadsheetImportDialog.test.ts | 25 +- ...penObjectRecordsSpreadsheetImportDialog.ts | 4 +- .../object-record/states/cursorFamilyState.ts | 7 +- .../states/hasNextPageFamilyState.ts | 4 +- .../isFetchingMoreRecordsFamilyState.ts | 4 +- .../isRecordBoardColumnLoadingFamilyState.ts | 4 +- .../components/PageLayoutContent.tsx | 4 +- .../components/PageLayoutGridLayout.tsx | 18 +- .../components/PageLayoutGridOverlay.tsx | 7 +- .../PageLayoutInitializationQueryEffect.tsx | 63 +- .../PageLayoutRelationWidgetsSyncEffect.tsx | 63 +- .../components/PageLayoutRendererContent.tsx | 7 +- .../components/PageLayoutTabList.tsx | 28 +- ...youtTabListReorderableOverflowDropdown.tsx | 12 +- .../PageLayoutTabListReorderableTab.tsx | 4 +- .../components/PageLayoutTabRenderClone.tsx | 4 +- .../PageLayoutVerticalListEditor.tsx | 4 +- .../__stories__/PageLayoutTabList.stories.tsx | 13 +- .../hooks/__tests__/PageLayoutTestWrapper.tsx | 5 +- .../useChangePageLayoutDragSelection.test.tsx | 68 +- .../useCreatePageLayoutGraphWidget.test.tsx | 16 +- .../__tests__/useCreatePageLayoutTab.test.tsx | 17 +- .../useCreateWidgetFromClick.test.tsx | 6 +- .../useEndPageLayoutDragSelection.test.tsx | 98 +- .../usePageLayoutHandleLayoutChange.test.tsx | 8 +- .../useStartPageLayoutDragSelection.test.tsx | 45 +- .../page-layout/hooks/useBasePageLayout.ts | 7 +- .../hooks/useChangePageLayoutDragSelection.ts | 36 +- ...useCreatePageLayoutFrontComponentWidget.ts | 121 ++- .../hooks/useCreatePageLayoutGraphWidget.ts | 203 ++-- .../hooks/useCreatePageLayoutIframeWidget.ts | 121 ++- ...reatePageLayoutStandaloneRichTextWidget.ts | 127 ++- .../hooks/useCreatePageLayoutTab.ts | 77 +- .../hooks/useCreateWidgetFromClick.ts | 35 +- .../page-layout/hooks/useCurrentPageLayout.ts | 8 +- .../hooks/useDeletePageLayoutTab.ts | 55 +- .../hooks/useDeletePageLayoutWidget.ts | 67 +- .../hooks/useDuplicatePageLayoutTab.ts | 161 ++- .../hooks/useDuplicatePageLayoutWidget.ts | 185 ++-- .../hooks/useEditPageLayoutWidget.ts | 8 +- .../hooks/useEndPageLayoutDragSelection.ts | 64 +- .../page-layout/hooks/useMovePageLayoutTab.ts | 101 +- .../hooks/usePageLayoutDraftState.ts | 8 +- .../hooks/usePageLayoutHandleLayoutChange.ts | 107 +- .../hooks/usePageLayoutIdForRecord.ts | 10 +- ...ePageLayoutTabWithVisibleWidgetsOrThrow.ts | 4 +- ...ecordPageLayoutIdFromRecordStoreOrThrow.ts | 9 +- ...movePageLayoutWidgetAndPreservePosition.ts | 93 +- .../hooks/useReorderPageLayoutWidgets.ts | 46 +- ...setDraftPageLayoutToPersistedPageLayout.ts | 96 +- .../hooks/useSaveFieldsWidgetGroups.ts | 115 +-- .../page-layout/hooks/useSavePageLayout.ts | 110 +- .../hooks/useSetIsPageLayoutInEditMode.ts | 53 +- .../hooks/useStartPageLayoutDragSelection.ts | 19 +- .../hooks/useUpdatePageLayoutTab.ts | 30 +- .../hooks/useUpdatePageLayoutWidget.ts | 36 +- .../states/currentPageLayoutIdState.ts | 4 +- .../fieldsWidgetGroupsDraftComponentState.ts | 4 +- ...eldsWidgetGroupsPersistedComponentState.ts | 4 +- ...edFieldsWidgetGroupsDraftComponentState.ts | 4 +- .../isPageLayoutInEditModeComponentState.ts | 4 +- .../isPageLayoutTabDraggingComponentState.ts | 4 +- ...geLayoutCurrentBreakpointComponentState.ts | 4 +- .../pageLayoutCurrentLayoutsComponentState.ts | 4 +- .../states/pageLayoutDraftComponentState.ts | 4 +- .../pageLayoutDraggedAreaComponentState.ts | 4 +- ...ageLayoutDraggingWidgetIdComponentState.ts | 4 +- ...pageLayoutEditingWidgetIdComponentState.ts | 4 +- .../pageLayoutIsInitializedComponentState.ts | 4 +- .../pageLayoutPersistedComponentState.ts | 4 +- ...ageLayoutResizingWidgetIdComponentState.ts | 4 +- .../pageLayoutSelectedCellsComponentState.ts | 4 +- ...istCurrentDragDroppableIdComponentState.ts | 4 +- ...ayoutTabSettingsOpenTabIdComponentState.ts | 4 +- .../states/recordPageLayoutsState.ts | 4 +- .../states/savedPageLayoutsComponentState.ts | 4 +- ...eLayoutByObjectMetadataIdFamilySelector.ts | 28 +- .../recordPageLayoutFromIdFamilySelector.ts | 4 +- .../components/DashboardWidgetPlaceholder.tsx | 4 +- .../widgets/components/WidgetRenderer.tsx | 14 +- .../DashboardWidgetPlaceholder.stories.tsx | 27 +- .../__stories__/WidgetRenderer.stories.tsx | 920 ++++++++--------- .../widgets/field/components/FieldWidget.tsx | 14 +- .../FieldWidgetCellEditModePortal.tsx | 4 +- .../field/components/FieldWidgetDisplay.tsx | 4 +- .../__stories__/FieldWidget.stories.tsx | 960 ++++++++---------- .../useOpenFieldWidgetFieldInputEditMode.ts | 199 ++-- .../states/fieldWidgetHoverComponentState.ts | 4 +- .../fields/components/FieldsWidget.tsx | 4 +- .../FieldsWidgetCellEditModePortal.tsx | 4 +- .../FieldsWidgetCellHoveredPortal.tsx | 4 +- .../hooks/useCreateFieldsWidgetEditorGroup.ts | 65 +- .../hooks/useDeleteFieldsWidgetEditorGroup.ts | 30 +- .../hooks/useFieldsWidgetGroupsDraft.ts | 4 +- .../hooks/useFieldsWidgetGroupsForDisplay.ts | 6 +- .../useInitializeFieldsWidgetGroupsDraft.ts | 96 +- .../fields/hooks/useMoveFieldInDraft.ts | 181 ++-- .../useReorderFieldsWidgetEditorGroups.ts | 59 +- .../hooks/useToggleFieldVisibilityInDraft.ts | 57 +- .../hooks/useUpdateFieldsWidgetEditorGroup.ts | 52 +- .../FrontComponentWidgetRenderer.tsx | 4 +- .../__tests__/GraphWidgetTestWrapper.tsx | 19 +- ...GraphWidgetChartHasTooManyGroupsEffect.tsx | 4 +- .../graph/components/GraphWidgetLegend.tsx | 12 +- .../components/BarChart.tsx | 4 +- .../components/BarChartTooltip.tsx | 4 +- .../components/GraphWidgetBarChart.tsx | 14 +- .../GraphWidgetBarChartRenderer.tsx | 4 +- .../hooks/useBarChartData.ts | 4 +- .../graphWidgetBarTooltipComponentState.ts | 4 +- ...phWidgetHoveredSliceIndexComponentState.ts | 15 +- .../components/CustomCrosshairLayer.tsx | 4 +- .../components/CustomLinesLayer.tsx | 4 +- .../components/GraphLineChartTooltip.tsx | 4 +- .../components/GraphWidgetLineChart.tsx | 6 +- .../GraphWidgetLineChartRenderer.tsx | 4 +- .../components/LineAnimatedAreaPath.tsx | 4 +- .../hooks/useLineChartData.ts | 4 +- ...graphWidgetLineCrosshairXComponentState.ts | 4 +- .../graphWidgetLineTooltipComponentState.ts | 4 +- .../components/CustomArcsLayer.tsx | 4 +- .../components/GraphPieChartTooltip.tsx | 4 +- .../components/GraphWidgetPieChart.tsx | 4 +- .../GraphWidgetPieChartRenderer.tsx | 4 +- .../hooks/usePieChartCenterMetricData.ts | 6 +- .../hooks/usePieChartData.ts | 4 +- .../graphWidgetPieTooltipComponentState.ts | 4 +- .../hooks/useGraphWidgetAggregateQuery.ts | 6 +- .../graph/hooks/useLegendItemToggle.ts | 4 +- ...raphWidgetHiddenLegendIdsComponentState.ts | 4 +- ...WidgetHighlightedLegendIdComponentState.ts | 4 +- .../hasWidgetTooManyGroupsComponentState.ts | 13 +- .../hooks/useIsCurrentWidgetLastOfTab.ts | 4 +- .../widgets/hooks/useIsInPinnedTab.ts | 4 +- .../iframe/components/IframeWidget.tsx | 4 +- .../StandaloneRichTextEditorContent.tsx | 33 +- .../components/StandaloneRichTextWidget.tsx | 6 +- .../widgetCardHoveredComponentFamilyState.ts | 16 +- .../components/WidgetCardHeader.tsx | 4 +- .../SettingsDataModelSetFieldValueEffect.tsx | 8 +- ...ataModelSetLabelIdentifierRecordEffect.tsx | 4 +- .../SettingsObjectFieldItemTableRow.tsx | 9 +- ...SettingsUpdateDataModelObjectAboutForm.tsx | 3 +- .../states/settingsObjectFieldsFamilyState.ts | 4 +- .../settingsObjectIndexesFamilyState.ts | 4 +- .../states/apiKeyTokenFamilyState.ts | 7 +- .../components/SettingPublicDomain.tsx | 4 +- .../components/SettingsCustomDomain.tsx | 3 +- .../SettingsPublicDomainsListCard.tsx | 6 +- .../hooks/useCheckCustomDomainValidRecords.ts | 4 +- .../states/customDomainRecordsState.ts | 4 +- .../states/selectedPublicDomainState.ts | 6 +- .../tabs/SettingsLogicFunctionTestTab.tsx | 20 +- .../states/logicFunctionsState.ts | 4 +- .../members/hooks/useWorkspaceMemberRoles.ts | 5 +- .../components/GraphQLPlayground.tsx | 4 +- .../components/PlaygroundSetupForm.tsx | 4 +- .../playground/components/RestPlayground.tsx | 4 +- .../__stories__/GraphQLPlayground.stories.tsx | 4 +- .../__stories__/RestPlayground.stories.tsx | 4 +- .../playground/states/openAPIReference.ts | 4 +- .../states/playgroundApiKeyState.ts | 9 +- .../components/SettingsRolesContainer.tsx | 5 +- .../roles/components/SettingsRolesList.tsx | 5 +- .../components/SettingsRolesQueryEffect.tsx | 49 +- .../roles/hooks/useSettingsAllRoles.ts | 18 + .../roles/hooks/useUpdateAgentRole.ts | 12 +- .../roles/hooks/useUpdateApiKeyRole.ts | 12 +- .../hooks/useUpdateWorkspaceMemberRole.ts | 19 +- .../components/SettingsRoleAssignment.tsx | 11 +- .../SettingsRoleAssignmentTable.tsx | 7 +- .../SettingsRoleAssignmentTableRow.tsx | 5 +- .../SettingsRoleAssignment.stories.tsx | 7 +- .../SettingsRolePermissions.stories.tsx | 7 +- ...RolePermissionsObjectLevelOverrideCell.tsx | 7 +- ...tingsRolePermissionsObjectLevelSection.tsx | 7 +- ...ionsObjectLevelSeeFieldsValueForObject.tsx | 7 +- ...sObjectLevelUpdateFieldsValueForObject.tsx | 7 +- ...sObjectLevelObjectFieldPermissionTable.tsx | 6 +- ...ObjectFieldPermissionTableAllHeaderRow.tsx | 7 +- ...seGetObjectPermissionDerivedStates.test.ts | 4 + .../useGetObjectPermissionDerivedStates.ts | 7 +- .../useRemoveFieldPermissionInDraftRole.ts | 30 +- ...seRemoveReadOverrideOnAllFieldsOfObject.ts | 7 +- ...RemoveUpdateOverrideOnAllFieldsOfObject.ts | 7 +- .../useRestrictReadOnAllFieldsOfObject.ts | 7 +- .../useRestrictUpdateOnAllFieldsOfObject.ts | 7 +- .../useUpsertFieldPermissionInDraftRole.ts | 7 +- .../hooks/useResetObjectPermission.ts | 7 +- .../hooks/useUpsertObjectPermission.ts | 7 +- .../useUpsertObjectPermissionInDraftRole.ts | 7 +- ...gsRolePermissionsObjectLevelObjectForm.tsx | 7 +- ...ssionsObjectLevelObjectFormObjectLevel.tsx | 7 +- ...jectLevelObjectFormObjectLevelTableRow.tsx | 7 +- ...tLevelRecordLevelPermissionFieldSelect.tsx | 4 +- ...ordLevelPermissionFieldSelectFieldMenu.tsx | 17 +- ...LevelPermissionFieldSelectSubFieldMenu.tsx | 10 +- ...ordLevelPermissionFilterBuilderContent.tsx | 22 +- ...evelRecordLevelPermissionMeValueSelect.tsx | 7 +- ...ctLevelRecordLevelPermissionValueInput.tsx | 4 +- .../useRecordLevelPermissionFilterActions.ts | 4 +- ...useRecordLevelPermissionSyncToDraftRole.ts | 7 +- .../SettingsRolePermissionsObjectsSection.tsx | 12 +- ...tingsRolePermissionsObjectsTableHeader.tsx | 12 +- ...SettingsRolePermissionsSettingsSection.tsx | 12 +- ...ingsRolePermissionsSettingsTableHeader.tsx | 12 +- ...ettingsRolePermissionsSettingsTableRow.tsx | 12 +- .../SettingsRolePermissionsToolSection.tsx | 12 +- .../components/SettingsRoleSettings.tsx | 12 +- ...ngsDeleteRoleConfirmationModalSubtitle.tsx | 7 +- .../stories/SettingsRoleSettings.stories.tsx | 7 +- .../roles/role/components/SettingsRole.tsx | 17 +- .../components/SettingsRoleCreateEffect.tsx | 12 +- .../components/SettingsRoleEditEffect.tsx | 32 +- .../components/SettingsRoleLabelContainer.tsx | 13 +- .../roles/role/hooks/useSaveDraftRoleToDB.ts | 12 +- .../roles/states/settingsAllRolesSelector.ts | 14 - .../states/settingsDraftRoleFamilyState.ts | 4 +- .../settingsPersistedRoleFamilyState.ts | 4 +- .../roles/states/settingsRoleIdsState.ts | 6 +- .../roles/states/settingsRoleIdsStateV2.ts | 6 - .../states/settingsValidateRoleFamilyState.ts | 4 +- ...SettingsSSOIdentitiesProvidersListCard.tsx | 4 +- ...sSSOIdentitiesProvidersListCardWrapper.tsx | 4 +- ...gsSSOIdentityProviderRowRightContainer.tsx | 5 +- .../SettingsSecuritySSORowDropdownMenu.tsx | 5 +- ...ttingsSecurityAuthProvidersOptionsList.tsx | 3 +- .../SettingsApprovedAccessDomainsListCard.tsx | 9 +- ...ityApprovedAccessDomainRowDropdownMenu.tsx | 11 +- ...tyApprovedAccessDomainValidationEffect.tsx | 4 +- .../hooks/useCreateSSOIdentityProvider.ts | 4 +- .../hooks/useDeleteSSOIdentityProvider.ts | 4 +- .../hooks/useUpdateSSOIdentityProvider.ts | 4 +- .../states/ApprovedAccessDomainsState.ts | 4 +- .../states/SSOIdentitiesProvidersState.ts | 4 +- .../SignInBackgroundMockContainer.tsx | 4 +- .../SignInBackgroundMockContainerEffect.tsx | 8 +- .../__tests__/useSpreadsheetImport.test.tsx | 12 +- ...useComputeColumnSuggestionsAndAutoMatch.ts | 47 +- .../hooks/useHideStepBar.ts | 29 +- .../hooks/useOpenSpreadsheetImportDialog.ts | 8 +- .../components/SpreadsheetImportProvider.tsx | 10 +- ...dsheetImportCreatedRecordsProgressState.ts | 4 +- .../states/spreadsheetImportDialogState.ts | 4 +- .../steps/components/ImportDataStep.tsx | 5 +- .../MatchColumnsStep/MatchColumnsStep.tsx | 7 +- .../components/TemplateColumn.tsx | 4 +- .../states/initialComputedColumnsState.ts | 9 +- .../suggestedFieldsByColumnHeaderState.ts | 4 +- .../SpreadsheetImportStepperContainer.tsx | 6 +- .../components/SSEClientEffect.tsx | 29 +- .../components/SSEEventStreamEffect.tsx | 11 +- .../components/SSEQuerySubscribeEffect.tsx | 145 ++- .../useHandleSseClientConnectionRetry.ts | 87 +- .../hooks/useListenToEventsForQuery.ts | 80 +- .../hooks/useTriggerEventStreamCreation.ts | 275 +++-- .../hooks/useTriggerEventStreamDestroy.ts | 60 +- .../states/activeQueryListenersState.ts | 4 +- .../disposeFunctionByEventStreamMapState.ts | 4 +- .../states/isCreatingSseEventStreamState.ts | 4 +- .../states/isDestroyingEventStreamState.ts | 4 +- .../states/requiredQueryListenersState.ts | 4 +- .../states/shouldDestroyEventStreamState.ts | 4 +- .../sse-db-event/states/sseClientState.ts | 4 +- .../states/sseEventStreamIdState.ts | 4 +- .../states/sseEventStreamReadyState.ts | 4 +- .../components/FieldRichTextCard.tsx | 14 +- .../components/ShowPageSummaryCard.tsx | 6 +- .../components/NavigationDrawer.tsx | 4 +- .../utilities/state/jotai/MIGRATION_PLAN.md | 15 +- ...lComponentFamilySelectorCallbackStateV2.ts | 38 + ...useRecoilComponentFamilySelectorValueV2.ts | 30 + ...coilComponentFamilyStateCallbackStateV2.ts | 38 + ...eRecoilComponentSelectorCallbackStateV2.ts | 30 + .../useRecoilComponentSelectorValueV2.ts | 27 + .../useRecoilComponentStateCallbackStateV2.ts | 30 + .../jotai/types/ComponentFamilySelectorV2.ts | 9 + .../state/jotai/types/ComponentSelectorV2.ts | 9 + .../state/jotai/types/FamilyStateV2.ts | 2 +- .../state/jotai/types/SelectorCallbacksV2.ts | 24 + .../state/jotai/utils/buildGetHelper.ts | 55 +- .../utils/createComponentFamilySelectorV2.ts | 61 ++ .../jotai/utils/createComponentSelectorV2.ts | 54 + .../state/jotai/utils/createFamilyStateV2.ts | 6 +- .../components/LazyMetadataLoadEffect.tsx | 23 +- .../components/AdvancedFilterChip.tsx | 9 +- .../AdvancedFilterDropdownButton.tsx | 4 +- .../views/components/AnyFieldSearchChip.tsx | 7 +- .../components/QueryParamsFiltersEffect.tsx | 6 +- .../views/components/SoftDeleteFilterChip.tsx | 4 +- .../components/UpdateViewButtonGroup.tsx | 8 +- .../ViewBarAnyFieldFilterEffect.tsx | 15 +- .../views/components/ViewBarDetails.tsx | 15 +- .../components/ViewBarFilterDropdown.tsx | 4 +- ...wBarFilterDropdownAdvancedFilterButton.tsx | 4 +- ...erDropdownAnyFieldSearchButtonMenuItem.tsx | 4 +- .../ViewBarFilterDropdownContent.tsx | 13 +- .../ViewBarFilterDropdownFieldSelectMenu.tsx | 4 +- ...BarFilterDropdownFilterInputMenuHeader.tsx | 4 +- .../components/ViewBarRecordFieldEffect.tsx | 12 +- .../components/ViewBarRecordFilterEffect.tsx | 15 +- .../ViewBarRecordFilterGroupEffect.tsx | 15 +- .../components/ViewBarRecordSortEffect.tsx | 15 +- .../ViewFieldsHiddenDropdownSection.tsx | 4 +- .../ViewFieldsVisibleDropdownSection.tsx | 4 +- .../ViewBarFilterDropdown.stories.tsx | 52 +- .../EditableFilterChipDropdownMenuHeader.tsx | 4 +- ...GroupsToCurrentRecordFilterGroups.test.tsx | 28 +- ...ViewFiltersToCurrentRecordFilters.test.tsx | 28 +- ...rentViewSortsToCurrentRecordSorts.test.tsx | 19 +- ...ViewFiltersToCurrentRecordFilters.test.tsx | 6 +- ...pplyViewSortsToCurrentRecordSorts.test.tsx | 6 +- ...dataItemFromViewBarFilterDropdown.test.tsx | 89 +- .../internal/useGetRecordIndexTotalCount.ts | 8 +- ...rrentViewAnyFieldFilterToAnyFieldFilter.ts | 8 +- ...FilterGroupsToCurrentRecordFilterGroups.ts | 73 +- ...urrentViewFiltersToCurrentRecordFilters.ts | 8 +- ...plyCurrentViewSortsToCurrentRecordSorts.ts | 8 +- ...eApplyViewFiltersToCurrentRecordFilters.ts | 4 +- .../useApplyViewSortsToCurrentRecordSorts.ts | 4 +- ...erGroupsDifferentFromRecordFilterGroups.ts | 4 +- ...reViewFiltersDifferentFromRecordFilters.ts | 4 +- ...useAreViewSortsDifferentFromRecordSorts.ts | 4 +- .../hooks/useCreateViewFromCurrentView.ts | 333 +++--- .../views/hooks/useGetCurrentViewOnly.ts | 4 +- .../src/modules/views/hooks/useInitViewBar.ts | 6 +- ...ldMetadataItemFromViewBarFilterDropdown.ts | 164 +-- ...ilterDifferentFromCurrentAnyFieldFilter.ts | 4 +- .../useOpenAnyFieldSearchFilterFromViewBar.ts | 10 +- .../views/hooks/useOpenCreateViewDropown.ts | 4 +- .../hooks/useQueryVariablesFromParentView.ts | 4 +- .../useRefreshCoreViewsByObjectMetadataId.ts | 257 +++-- .../hooks/useSaveAnyFieldFilterToView.ts | 61 +- .../views/hooks/useSaveCurrentViewFields.ts | 189 ++-- .../views/hooks/useSaveCurrentViewGroups.ts | 241 +++-- ...aveRecordFilterGroupsToViewFilterGroups.ts | 114 +-- .../useSaveRecordFiltersToViewFilters.ts | 185 ++-- .../hooks/useSaveRecordSortsToViewSorts.ts | 85 +- .../useSetEditableFilterChipDropdownStates.ts | 77 +- .../views/hooks/useUpdateCurrentView.ts | 107 +- .../views/hooks/useUpdateViewAggregate.ts | 4 +- ...availableFieldDefinitionsComponentState.ts | 4 +- ...lizedAnyFieldFilterComponentFamilyState.ts | 4 +- ...CurrentRecordFieldsComponentFamilyState.ts | 4 +- ...tRecordFilterGroupsComponentFamilyState.ts | 4 +- ...urrentRecordFiltersComponentFamilyState.ts | 4 +- ...dCurrentRecordSortsComponentFamilyState.ts | 4 +- .../isCurrentViewIndexComponentState.ts | 4 +- .../states/isViewBarExpandedComponentState.ts | 4 +- .../viewObjectMetadataIdComponentState.ts | 4 +- .../ViewPickerContentCreateMode.tsx | 27 +- .../components/ViewPickerContentEditMode.tsx | 17 +- .../components/ViewPickerContentEffect.tsx | 26 +- .../components/ViewPickerCreateButton.tsx | 12 +- .../components/ViewPickerEditButton.tsx | 10 +- .../ViewPickerFavoriteFoldersDropdown.tsx | 4 +- .../components/ViewPickerListContent.tsx | 4 +- .../components/ViewPickerOptionDropdown.tsx | 4 +- .../useGetAvailableFieldsForCalendar.test.tsx | 32 +- ...etAvailableFieldsToGroupRecordsBy.test.tsx | 32 +- .../hooks/useCloseAndResetViewPicker.ts | 6 +- .../hooks/useCreateViewFromCurrentState.ts | 157 ++- .../hooks/useDestroyViewFromCurrentState.ts | 100 +- .../hooks/useGetAvailableFieldsForCalendar.ts | 4 +- .../useGetAvailableFieldsToGroupRecordsBy.ts | 4 +- .../hooks/useUpdateViewFromCurrentState.ts | 118 +-- .../view-picker/hooks/useViewPickerMode.ts | 4 +- ...erCalendarFieldMetadataIdComponentState.ts | 4 +- .../viewPickerInputNameComponentState.ts | 14 +- .../states/viewPickerIsDirtyComponentState.ts | 4 +- .../viewPickerIsPersistingComponentState.ts | 4 +- ...ainGroupByFieldMetadataIdComponentState.ts | 4 +- .../states/viewPickerModeComponentState.ts | 4 +- ...viewPickerReferenceViewIdComponentState.ts | 4 +- .../viewPickerSelectedIconComponentState.ts | 4 +- .../states/viewPickerTypeComponentState.ts | 4 +- .../viewPickerVisibilityComponentState.ts | 4 +- .../modules/workflow/hooks/useFlowOrThrow.ts | 4 +- .../useGetUpdatableWorkflowVersionOrThrow.ts | 4 +- ...kflowRunOpeningInCommandMenuSideEffects.ts | 169 ++- .../workflow/hooks/useRunWorkflowVersion.tsx | 16 +- .../workflow/hooks/useWorkflowRunIdOrThrow.ts | 4 +- .../hooks/useWorkflowVersionIdOrThrow.ts | 4 +- .../hooks/useWorkflowWithCurrentVersion.ts | 13 +- .../workflow/states/flowComponentState.ts | 4 +- .../workflow/states/selectors/stepSelector.ts | 8 +- .../stepsOutputSchemaFamilySelector.ts | 6 +- ...shouldWorkflowRefetchRequestFamilyState.ts | 4 +- ...workflowLastCreatedStepIdComponentState.ts | 4 +- ...kflowVisualizerWorkflowIdComponentState.ts | 15 +- ...owVisualizerWorkflowRunIdComponentState.ts | 4 +- ...sualizerWorkflowVersionIdComponentState.ts | 4 +- .../components/WorkflowDiagramCanvasBase.tsx | 232 ++--- .../WorkflowDiagramCanvasEditable.tsx | 10 +- .../components/WorkflowDiagramEffect.tsx | 92 +- .../WorkflowDiagramRightClickCommandMenu.tsx | 4 +- ...ightClickCommandMenuClickOutsideEffect.tsx | 4 +- .../components/WorkflowRunVisualizer.tsx | 4 +- .../WorkflowRunVisualizerEffect.tsx | 220 ++-- .../components/WorkflowSSESubscribeEffect.tsx | 7 +- .../WorkflowVersionVisualizerEffect.tsx | 10 +- .../components/WorkflowVisualizerEffect.tsx | 6 +- ...lowDiagramEmptyTriggerEditable.stories.tsx | 41 +- ...DiagramStepNodeEditableContent.stories.tsx | 45 +- .../hooks/useCloseRightClickMenu.ts | 4 +- .../hooks/useResetWorkflowInsertStepIds.ts | 21 +- .../useSetInitialWorkflowRunRightDrawerTab.ts | 91 +- .../hooks/useStartNodeCreation.ts | 16 +- .../states/workflowDiagramComponentState.ts | 4 +- .../workflowDiagramPanOnDragComponentState.ts | 4 +- ...kflowDiagramRightClickMenuPositionState.ts | 4 +- .../workflowDiagramStatusComponentState.ts | 4 +- ...ramWaitingNodesDimensionsComponentState.ts | 4 +- ...mAutomaticallyOpenedStepsComponentState.ts | 4 +- .../workflowSelectedNodeComponentState.ts | 4 +- .../workflow-edges/hooks/useEdgeState.ts | 9 +- .../workflowHoveredEdgeComponentState.ts | 4 +- .../workflowSelectedEdgeComponentState.ts | 4 +- .../WorkflowDiagramEmptyTriggerEditable.tsx | 12 +- .../WorkflowDiagramEmptyTriggerReadonly.tsx | 14 +- .../WorkflowDiagramStepNodeEditable.tsx | 12 +- ...WorkflowDiagramStepNodeEditableContent.tsx | 4 +- .../WorkflowDiagramStepNodeReadonly.tsx | 14 +- .../components/WorkflowRunDiagramStepNode.tsx | 12 +- .../WorkflowDropdownStepOutputItems.tsx | 119 +-- .../components/WorkflowRunStepInputDetail.tsx | 4 +- .../WorkflowEditActionFilterBodyEffect.tsx | 18 +- .../filters/hooks/useAddRootStepFilter.ts | 90 +- ...hildStepFiltersAndChildStepFilterGroups.ts | 8 +- .../filters/hooks/useFilterCounter.ts | 4 +- .../filters/hooks/useRemoveStepFilter.ts | 133 ++- .../filters/hooks/useRemoveStepFilterGroup.ts | 92 +- .../hooks/useUpsertStepFilterSettings.ts | 106 +- .../currentStepFilterGroupsComponentState.ts | 4 +- .../currentStepFiltersComponentState.ts | 4 +- ...entStepFilterGroupsComponentFamilyState.ts | 4 +- ...dCurrentStepFiltersComponentFamilyState.ts | 4 +- ...otLevelStepFilterGroupComponentSelector.ts | 8 +- .../workflow-steps/hooks/useCreateStep.ts | 6 +- .../hooks/useCreateWorkflowVersionStep.ts | 4 +- .../workflow-steps/hooks/useDeleteStep.ts | 4 +- .../workflow-steps/hooks/useDuplicateStep.ts | 6 +- .../hooks/useDuplicateWorkflowVersionStep.ts | 4 +- .../hooks/useWorkflowRunStepInfo.ts | 4 +- .../workflowInsertStepIdsComponentState.ts | 4 +- .../components/WorkflowEditActionCode.tsx | 23 +- .../logicFunctionTestDataFamilyState.ts | 4 +- .../WorkflowEditActionEmailBase.tsx | 4 +- .../WorkflowEditActionFilterBody.tsx | 4 +- .../components/WorkflowFindRecordsFilters.tsx | 52 +- .../WorkflowFindRecordsFiltersEffect.tsx | 12 +- .../HttpRequestTestVariableInput.tsx | 12 +- .../hooks/useTestHttpRequest.ts | 12 +- .../states/httpRequestTestDataFamilyState.ts | 4 +- .../WorkflowEditActionIfElseBody.tsx | 14 +- .../WorkflowIteratorSubStepSwitcher.tsx | 4 +- .../components/CronExpressionHelper.tsx | 6 +- .../WorkflowEditTriggerCronForm.tsx | 6 +- .../WorkflowEditTriggerWebhookForm.tsx | 4 +- .../useAvailableVariablesInWorkflowStep.ts | 13 +- .../hooks/useSearchVariable.ts | 9 +- .../hooks/useStepsOutputSchema.ts | 245 ++--- .../hooks/useVariableDropdown.ts | 13 +- .../shouldRecomputeOutputSchemaFamilyState.ts | 4 +- .../states/stepsOutputSchemaFamilyState.ts | 4 +- .../workflow-version/hooks/useTidyUp.ts | 4 +- .../pages/object-record/RecordIndexPage.tsx | 4 +- .../object-record/RecordShowPageTitle.tsx | 4 +- .../pages/settings/ai/SettingsAgentForm.tsx | 17 +- .../ai/components/SettingsAgentRoleTab.tsx | 7 +- .../ai/components/SettingsToolsTable.tsx | 4 +- .../SettingsApplicationPermissionsTab.tsx | 7 +- .../data-model/SettingsObjectDetailPage.tsx | 7 +- .../data-model/SettingsObjectFieldTable.tsx | 14 +- .../data-model/SettingsObjectIndexTable.tsx | 14 +- .../states/updatedObjectNamePluralState.ts | 4 +- .../playground/GraphQLPlayground.stories.tsx | 11 +- .../playground/SettingsPlayground.stories.tsx | 11 +- .../SettingsDevelopersApiKeyDetail.tsx | 20 +- .../api-keys/SettingsDevelopersApiKeysNew.tsx | 17 +- .../SettingsEmailingDomains.tsx | 6 +- .../appearance/components/LocalePicker.tsx | 5 - .../roles/SettingsRoleAddObjectLevel.tsx | 7 +- .../pages/settings/roles/SettingsRoleEdit.tsx | 7 +- .../settings/security/SettingsSecurity.tsx | 3 +- .../decorators/ContextStoreDecorator.tsx | 4 +- .../testing/decorators/ProfilerDecorator.tsx | 8 +- .../decorators/RecordTableDecorator.tsx | 17 +- .../decorators/WorkflowStepDecorator.tsx | 103 +- .../testing/decorators/getFieldDecorator.tsx | 14 +- .../testing/jest/JestContextStoreSetter.tsx | 47 +- .../JestRecordIndexContextProviderWrapper.tsx | 51 +- ...dataAndApolloMocksAndActionMenuWrapper.tsx | 4 + .../getJestMetadataAndApolloMocksWrapper.tsx | 4 + .../src/testing/mock-data/roles/roles-mock.ts | 25 +- .../profiling/components/ProfilerWrapper.tsx | 82 +- .../components/ProfilingQueueEffect.tsx | 10 +- .../components/ProfilingReporter.tsx | 8 +- .../states/currentProfilingRunIndexState.ts | 6 +- .../states/currentProfilingRunState.ts | 6 +- .../profiling/states/profilingQueueState.ts | 6 +- .../states/profilingSessionDataPointsState.ts | 8 +- .../states/profilingSessionRunsState.ts | 6 +- .../profiling/states/profilingSessionState.ts | 14 +- .../states/profilingSessionStatusState.ts | 11 +- 1326 files changed, 19248 insertions(+), 19389 deletions(-) delete mode 100644 packages/twenty-front/src/localization/states/dateLocaleState.ts delete mode 100644 packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleStateV2.ts delete mode 100644 packages/twenty-front/src/modules/command-menu/states/isCommandMenuOpenedState.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelector.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts rename packages/twenty-front/src/modules/object-record/record-store/states/selectors/{recordStoreIdentifierSelector.ts => recordStoreIdentifierFamilySelectorV2.ts} (58%) rename packages/twenty-front/src/modules/object-record/record-store/states/selectors/{recordStoreMorphOneToManyValueWithObjectNameFamilySelector.ts => recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2.ts} (71%) delete mode 100644 packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelector.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelectorV2.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/selectors/isAtLeastOneTableRowSelectedSelector.ts create mode 100644 packages/twenty-front/src/modules/settings/roles/hooks/useSettingsAllRoles.ts delete mode 100644 packages/twenty-front/src/modules/settings/roles/states/settingsAllRolesSelector.ts delete mode 100644 packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentFamilySelectorV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentSelectorV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentSelectorV2.ts diff --git a/packages/twenty-front/src/localization/states/dateLocaleState.ts b/packages/twenty-front/src/localization/states/dateLocaleState.ts deleted file mode 100644 index 0eaf9af87e..0000000000 --- a/packages/twenty-front/src/localization/states/dateLocaleState.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { type Locale } from 'date-fns'; -import { enUS } from 'date-fns/locale'; -import { type APP_LOCALES } from 'twenty-shared/translations'; -import { createState } from '@/ui/utilities/state/utils/createState'; - -type DateLocaleState = { - locale?: keyof typeof APP_LOCALES; - localeCatalog: Locale; -}; - -export const dateLocaleState = createState({ - key: 'dateLocaleState', - defaultValue: { - locale: undefined, - localeCatalog: enUS, - }, -}); diff --git a/packages/twenty-front/src/modules/action-menu/actions/components/ActionOpenSidePanelPage.tsx b/packages/twenty-front/src/modules/action-menu/actions/components/ActionOpenSidePanelPage.tsx index e301a6559f..d63f92cd32 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/components/ActionOpenSidePanelPage.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/components/ActionOpenSidePanelPage.tsx @@ -2,10 +2,10 @@ import { ActionDisplay } from '@/action-menu/actions/display/components/ActionDi import { ActionConfigContext } from '@/action-menu/contexts/ActionConfigContext'; import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type MessageDescriptor } from '@lingui/core'; import { t } from '@lingui/core/macro'; import { useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { type CommandMenuPages } from 'twenty-shared/types'; import { type IconComponent } from 'twenty-ui/display'; @@ -26,7 +26,7 @@ export const ActionOpenSidePanelPage = ({ const { navigateCommandMenu } = useNavigateCommandMenu(); - const setCommandMenuSearchState = useSetRecoilState(commandMenuSearchState); + const setCommandMenuSearchState = useSetRecoilStateV2(commandMenuSearchState); if (!actionConfig) { return null; diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/HeadlessFrontComponentAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/HeadlessFrontComponentAction.tsx index 9260ae0a41..95bff6f83c 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/display/components/HeadlessFrontComponentAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/HeadlessFrontComponentAction.tsx @@ -1,8 +1,8 @@ import { ActionConfigContext } from '@/action-menu/contexts/ActionConfigContext'; import { useCloseActionMenu } from '@/action-menu/hooks/useCloseActionMenu'; import { isHeadlessFrontComponentMountedFamilySelector } from '@/front-components/selectors/isHeadlessFrontComponentMountedFamilySelector'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { ActionDisplay } from './ActionDisplay'; @@ -20,8 +20,9 @@ export const HeadlessFrontComponentAction = ({ closeSidePanelOnCommandMenuListActionExecution: false, }); - const isMounted = useRecoilValue( - isHeadlessFrontComponentMountedFamilySelector(frontComponentId), + const isMounted = useFamilySelectorValueV2( + isHeadlessFrontComponentMountedFamilySelector, + frontComponentId, ); if (!actionConfig) { diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DeleteMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DeleteMultipleRecordsAction.tsx index 83b4697f30..2ff1d7d00b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DeleteMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DeleteMultipleRecordsAction.tsx @@ -14,7 +14,7 @@ import { useRemoveSelectedRecordsFromRecordBoard } from '@/object-record/record- import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -22,8 +22,9 @@ export const DeleteMultipleRecordsAction = () => { const { recordIndexId, objectMetadataItem } = useRecordIndexIdFromCurrentContextStore(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, + recordIndexId, ); if (!contextStoreCurrentViewId) { @@ -32,20 +33,24 @@ export const DeleteMultipleRecordsAction = () => { const { resetTableRowSelection } = useResetTableRowSelection(recordIndexId); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, + recordIndexId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, + recordIndexId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, + recordIndexId, ); const { removeSelectedRecordsFromRecordBoard } = diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx index e2de61d2df..db0a4a50cb 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx @@ -14,7 +14,7 @@ import { useRemoveSelectedRecordsFromRecordBoard } from '@/object-record/record- import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { useContext } from 'react'; import { type RecordGqlOperationFilter } from 'twenty-shared/types'; @@ -24,8 +24,9 @@ export const DestroyMultipleRecordsAction = () => { const { recordIndexId, objectMetadataItem } = useRecordIndexIdFromCurrentContextStore(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, + recordIndexId, ); if (!contextStoreCurrentViewId) { @@ -36,20 +37,24 @@ export const DestroyMultipleRecordsAction = () => { const { removeSelectedRecordsFromRecordBoard } = useRemoveSelectedRecordsFromRecordBoard(recordIndexId); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, + recordIndexId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, + recordIndexId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, + recordIndexId, ); const { filterValueDependencies } = useFilterValueDependencies(); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/ExportMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/ExportMultipleRecordsAction.tsx index f1d6154f90..79ab2219e4 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/ExportMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/ExportMultipleRecordsAction.tsx @@ -7,14 +7,14 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useRecordIndexExportRecords } from '@/object-record/record-index/export/hooks/useRecordIndexExportRecords'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const ExportMultipleRecordsAction = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/MergeMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/MergeMultipleRecordsAction.tsx index 0f46c5f214..4e17d26f6a 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/MergeMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/MergeMultipleRecordsAction.tsx @@ -3,12 +3,12 @@ import { useSelectedRecordIds } from '@/action-menu/actions/record-actions/singl import { useOpenMergeRecordsPageInCommandMenu } from '@/command-menu/hooks/useOpenMergeRecordsPageInCommandMenu'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const MergeMultipleRecordsAction = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx index 37975f9ea5..665f21bb97 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx @@ -12,7 +12,7 @@ import { useRemoveSelectedRecordsFromRecordBoard } from '@/object-record/record- import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { type RecordGqlOperationFilter } from 'twenty-shared/types'; @@ -20,8 +20,9 @@ export const RestoreMultipleRecordsAction = () => { const { recordIndexId, objectMetadataItem } = useRecordIndexIdFromCurrentContextStore(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, + recordIndexId, ); if (!contextStoreCurrentViewId) { @@ -36,20 +37,24 @@ export const RestoreMultipleRecordsAction = () => { objectNameSingular: objectMetadataItem.nameSingular, }); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, + recordIndexId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, + recordIndexId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, + recordIndexId, ); const { filterValueDependencies } = useFilterValueDependencies(); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewViewNoSelectionRecord.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewViewNoSelectionRecord.tsx index c602c70b0c..68ec33ccf9 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewViewNoSelectionRecord.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewViewNoSelectionRecord.tsx @@ -3,8 +3,8 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode'; import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState'; @@ -13,7 +13,7 @@ export const CreateNewViewNoSelectionRecord = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); const { openDropdown } = useOpenDropdown(); - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); @@ -26,7 +26,7 @@ export const CreateNewViewNoSelectionRecord = () => { currentViewId, ); - const setViewPickerReferenceViewId = useSetRecoilComponentState( + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/HideDeletedRecordsNoSelectionRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/HideDeletedRecordsNoSelectionRecordAction.tsx index 3b33a16b64..0a306f97bb 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/HideDeletedRecordsNoSelectionRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/HideDeletedRecordsNoSelectionRecordAction.tsx @@ -6,13 +6,13 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRe import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const HideDeletedRecordsNoSelectionRecordAction = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); @@ -32,7 +32,7 @@ export const HideDeletedRecordsNoSelectionRecordAction = () => { const { isRecordFilterAboutSoftDelete } = useCheckIsSoftDeleteFilter(); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/SeeDeletedRecordsNoSelectionRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/SeeDeletedRecordsNoSelectionRecordAction.tsx index 3c8a4d355f..65a89c7560 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/SeeDeletedRecordsNoSelectionRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/SeeDeletedRecordsNoSelectionRecordAction.tsx @@ -3,12 +3,12 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const SeeDeletedRecordsNoSelectionRecordAction = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx index cc7d0fea6f..78d333a52c 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx @@ -7,14 +7,16 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useActiveWorkflowVersionsWithManualTrigger } from '@/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger'; import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion'; import { type WorkflowVersion } from '@/workflow/types/Workflow'; import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants/CommandMenuDefaultIcon'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { QUERY_MAX_RECORDS } from 'twenty-shared/constants'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -28,12 +30,16 @@ export const useRunWorkflowRecordActions = ({ }) => { const { getIcon } = useIcons(); const { enqueueWarningSnackBar } = useSnackBar(); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const { recordIndexId } = useRecordIndexIdFromCurrentContextStore(); + + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const isPageInEditMode = useRecoilComponentValue( + const isPageInEditMode = useRecoilComponentValueV2( contextStoreIsPageInEditModeComponentState, + recordIndexId, ); const selectedRecordIds = @@ -49,69 +55,68 @@ export const useRunWorkflowRecordActions = ({ const { runWorkflowVersion } = useRunWorkflowVersion(); - const runWorkflowVersionOnSelectedRecords = useRecoilCallback( - ({ snapshot }) => - async ( - selectedRecordIds: string[], - activeWorkflowVersion: Pick< - WorkflowVersion, - 'id' | 'workflowId' | 'trigger' - >, - ) => { - if (selectedRecordIds.length > QUERY_MAX_RECORDS) { - const selectedCountFormatted = - selectedRecordIds.length.toLocaleString(); - const limitFormatted = QUERY_MAX_RECORDS.toLocaleString(); + const runWorkflowVersionOnSelectedRecords = useCallback( + async ( + selectedRecordIds: string[], + activeWorkflowVersion: Pick< + WorkflowVersion, + 'id' | 'workflowId' | 'trigger' + >, + ) => { + if (selectedRecordIds.length > QUERY_MAX_RECORDS) { + const selectedCountFormatted = + selectedRecordIds.length.toLocaleString(); + const limitFormatted = QUERY_MAX_RECORDS.toLocaleString(); - enqueueWarningSnackBar({ - message: t`You selected ${selectedCountFormatted} records but manual triggers can run on at most ${limitFormatted} records at once. Only the first ${limitFormatted} records will be processed.`, - options: { - dedupeKey: 'workflow-manual-trigger-selection-limit', - }, - }); - } + enqueueWarningSnackBar({ + message: t`You selected ${selectedCountFormatted} records but manual triggers can run on at most ${limitFormatted} records at once. Only the first ${limitFormatted} records will be processed.`, + options: { + dedupeKey: 'workflow-manual-trigger-selection-limit', + }, + }); + } - const limitedSelectedRecordIds = selectedRecordIds.slice( - 0, - QUERY_MAX_RECORDS, - ); + const limitedSelectedRecordIds = selectedRecordIds.slice( + 0, + QUERY_MAX_RECORDS, + ); - if ( - isDefined(activeWorkflowVersion?.trigger) && - isBulkRecordsManualTrigger(activeWorkflowVersion.trigger) - ) { - const objectNamePlural = objectMetadataItem.namePlural; - const selectedRecords = limitedSelectedRecordIds - .map((recordId) => - snapshot.getLoadable(recordStoreFamilyState(recordId)).getValue(), - ) - .filter(isDefined); + if ( + isDefined(activeWorkflowVersion?.trigger) && + isBulkRecordsManualTrigger(activeWorkflowVersion.trigger) + ) { + const objectNamePlural = objectMetadataItem.namePlural; + const selectedRecords = limitedSelectedRecordIds + .map((recordId) => + jotaiStore.get(recordStoreFamilyState.atomFamily(recordId)), + ) + .filter(isDefined); + + await runWorkflowVersion({ + workflowId: activeWorkflowVersion.workflowId, + workflowVersionId: activeWorkflowVersion.id, + payload: { + [objectNamePlural]: selectedRecords, + }, + }); + } else { + for (const selectedRecordId of limitedSelectedRecordIds) { + const selectedRecord = jotaiStore.get( + recordStoreFamilyState.atomFamily(selectedRecordId), + ); + + if (!isDefined(selectedRecord)) { + continue; + } await runWorkflowVersion({ workflowId: activeWorkflowVersion.workflowId, workflowVersionId: activeWorkflowVersion.id, - payload: { - [objectNamePlural]: selectedRecords, - }, + payload: selectedRecord, }); - } else { - for (const selectedRecordId of limitedSelectedRecordIds) { - const selectedRecord = snapshot - .getLoadable(recordStoreFamilyState(selectedRecordId)) - .getValue(); - - if (!isDefined(selectedRecord)) { - continue; - } - - await runWorkflowVersion({ - workflowId: activeWorkflowVersion.workflowId, - workflowVersionId: activeWorkflowVersion.id, - payload: selectedRecord, - }); - } } - }, + } + }, [runWorkflowVersion, objectMetadataItem, enqueueWarningSnackBar], ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/AddToFavoritesSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/AddToFavoritesSingleRecordAction.tsx index cac5779fb9..302dcd41b3 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/AddToFavoritesSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/AddToFavoritesSingleRecordAction.tsx @@ -3,7 +3,7 @@ import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; export const AddToFavoritesSingleRecordAction = () => { @@ -13,7 +13,10 @@ export const AddToFavoritesSingleRecordAction = () => { const { createFavorite } = useCreateFavorite(); - const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); + const selectedRecord = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const handleClick = () => { if (!isDefined(selectedRecord)) { diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportNoteActionSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportNoteActionSingleRecordAction.tsx index b13808f00c..4f6df7f5f2 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportNoteActionSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportNoteActionSingleRecordAction.tsx @@ -1,13 +1,16 @@ import { Action } from '@/action-menu/actions/components/Action'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; export const ExportNoteActionSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); + const selectedRecord = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const filename = `${(selectedRecord?.title || 'Untitled Note').replace(/[<>:"/\\|?*]/g, '-')}`; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportSingleRecordAction.tsx index 902324d581..71e3c36d76 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/ExportSingleRecordAction.tsx @@ -2,14 +2,14 @@ import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useExportSingleRecord } from '@/object-record/record-show/hooks/useExportSingleRecord'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { Action } from '@/action-menu/actions/components/Action'; export const ExportSingleRecordAction = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/CancelDashboardSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/CancelDashboardSingleRecordAction.tsx index 3f6291977c..5cd84cef3a 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/CancelDashboardSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/CancelDashboardSingleRecordAction.tsx @@ -4,12 +4,15 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useResetDraftPageLayoutToPersistedPageLayout } from '@/page-layout/hooks/useResetDraftPageLayoutToPersistedPageLayout'; import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; export const CancelDashboardSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); + const selectedRecord = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const pageLayoutId = selectedRecord?.pageLayoutId; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx index dd9676dede..ba3378279e 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx @@ -2,13 +2,16 @@ import { Action } from '@/action-menu/actions/components/Action'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useResetLocationHash } from 'twenty-ui/utilities'; export const EditDashboardSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); + const selectedRecord = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const pageLayoutId = selectedRecord?.pageLayoutId; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/SaveDashboardSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/SaveDashboardSingleRecordAction.tsx index 67fa3d70e9..370d551afc 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/SaveDashboardSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/SaveDashboardSingleRecordAction.tsx @@ -4,12 +4,15 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useSavePageLayout } from '@/page-layout/hooks/useSavePageLayout'; import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; export const SaveDashboardSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); + const selectedRecord = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const pageLayoutId = selectedRecord?.pageLayoutId; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow.tsx index 5e7ab0a76c..605409f1e1 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow.tsx @@ -1,9 +1,13 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useSelectedRecordIdOrThrow = () => { - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const { recordIndexId } = useRecordIndexIdFromCurrentContextStore(); + + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); if ( diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIds.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIds.tsx index 1f44b822d5..683358c4a5 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIds.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIds.tsx @@ -1,9 +1,13 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useSelectedRecordIds = () => { - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const { recordIndexId } = useRecordIndexIdFromCurrentContextStore(); + + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); if ( diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx index 113ae2d7a2..20ec531a59 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/components/TidyUpWorkflowSingleRecordAction.tsx @@ -4,7 +4,7 @@ import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUp import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId'; import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState'; import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isDefined } from 'twenty-shared/utils'; export const TidyUpWorkflowSingleRecordAction = () => { @@ -16,26 +16,20 @@ export const TidyUpWorkflowSingleRecordAction = () => { const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersionOrThrow(instanceId); - const onClick = useRecoilCallback( - ({ snapshot }) => - async () => { - const workflowDiagramState = workflowDiagramComponentState.atomFamily({ - instanceId, - }); - const workflowDiagram = snapshot - .getLoadable(workflowDiagramState) - .getValue(); + const onClick = async () => { + const workflowDiagramAtom = workflowDiagramComponentState.atomFamily({ + instanceId, + }); + const workflowDiagram = jotaiStore.get(workflowDiagramAtom); - if (!isDefined(workflowDiagram)) { - return; - } + if (!isDefined(workflowDiagram)) { + return; + } - const workflowVersionId = await getUpdatableWorkflowVersion(); + const workflowVersionId = await getUpdatableWorkflowVersion(); - await tidyUpWorkflowVersion(workflowVersionId, workflowDiagram); - }, - [getUpdatableWorkflowVersion, tidyUpWorkflowVersion, instanceId], - ); + await tidyUpWorkflowVersion(workflowVersionId, workflowDiagram); + }; return ; }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeVersionWorkflowRunSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeVersionWorkflowRunSingleRecordAction.tsx index 0979867045..0da2cb62ac 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeVersionWorkflowRunSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeVersionWorkflowRunSingleRecordAction.tsx @@ -2,13 +2,13 @@ import { ActionLink } from '@/action-menu/actions/components/ActionLink'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { AppPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const SeeVersionWorkflowRunSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const workflowRun = useRecoilValue(recordStoreFamilyState(recordId)); + const workflowRun = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); if (!isDefined(workflowRun) || !isDefined(workflowRun?.workflowVersion?.id)) { return null; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeWorkflowWorkflowRunSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeWorkflowWorkflowRunSingleRecordAction.tsx index 91d951f725..2b9dddf4ef 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeWorkflowWorkflowRunSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/SeeWorkflowWorkflowRunSingleRecordAction.tsx @@ -2,13 +2,13 @@ import { ActionLink } from '@/action-menu/actions/components/ActionLink'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { AppPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const SeeWorkflowWorkflowRunSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const workflowRun = useRecoilValue(recordStoreFamilyState(recordId)); + const workflowRun = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); if (!isDefined(workflowRun) || !isDefined(workflowRun?.workflow?.id)) { return null; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/StopWorkflowRunSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/StopWorkflowRunSingleRecordAction.tsx index 232aa4c8e9..0312268f6f 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/StopWorkflowRunSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-run-actions/components/StopWorkflowRunSingleRecordAction.tsx @@ -9,26 +9,31 @@ import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryP import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useStopWorkflowRun } from '@/workflow/hooks/useStopWorkflowRun'; export const StopWorkflowRunSingleRecordAction = () => { - const { objectMetadataItem } = useRecordIndexIdFromCurrentContextStore(); + const { objectMetadataItem, recordIndexId } = + useRecordIndexIdFromCurrentContextStore(); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, + recordIndexId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, + recordIndexId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, + recordIndexId, ); const { filterValueDependencies } = useFilterValueDependencies(); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeRunsWorkflowVersionSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeRunsWorkflowVersionSingleRecordAction.tsx index 5e450ccfbb..c5c3f074a5 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeRunsWorkflowVersionSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeRunsWorkflowVersionSingleRecordAction.tsx @@ -2,8 +2,8 @@ import { ActionLink } from '@/action-menu/actions/components/ActionLink'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { useRecoilValue } from 'recoil'; import { AppPath, ViewFilterOperand } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -40,7 +40,10 @@ const SeeRunsWorkflowVersionSingleRecordActionContent = ({ export const SeeRunsWorkflowVersionSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const workflowVersion = useRecoilValue(recordStoreFamilyState(recordId)); + const workflowVersion = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const workflowId = workflowVersion?.workflow?.id; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeVersionsWorkflowVersionSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeVersionsWorkflowVersionSingleRecordAction.tsx index 18fe5326a1..bd71e4a33c 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeVersionsWorkflowVersionSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeVersionsWorkflowVersionSingleRecordAction.tsx @@ -3,7 +3,7 @@ import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { AppPath, ViewFilterOperand } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -33,7 +33,10 @@ const SeeVersionsWorkflowVersionSingleRecordActionContent = ({ export const SeeVersionsWorkflowVersionSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const workflowVersion = useRecoilValue(recordStoreFamilyState(recordId)); + const workflowVersion = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); if (!isDefined(workflowVersion) || !isDefined(workflowVersion.workflowId)) { return null; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeWorkflowWorkflowVersionSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeWorkflowWorkflowVersionSingleRecordAction.tsx index 5c888ccc6c..be7aa2adb4 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeWorkflowWorkflowVersionSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeWorkflowWorkflowVersionSingleRecordAction.tsx @@ -2,12 +2,15 @@ import { ActionLink } from '@/action-menu/actions/components/ActionLink'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { AppPath } from 'twenty-shared/types'; export const SeeWorkflowWorkflowVersionSingleRecordAction = () => { const recordId = useSelectedRecordIdOrThrow(); - const workflowVersion = useRecoilValue(recordStoreFamilyState(recordId)); + const workflowVersion = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); return ( { const { getIcon } = useIcons(); - const isPageInEditMode = useRecoilComponentValue( + const isPageInEditMode = useRecoilComponentValueV2( contextStoreIsPageInEditModeComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const { actionMenuType } = useContext(ActionMenuContext); diff --git a/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts b/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts index 76ece40fb7..f64b60267b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const forceRegisteredActionsByKeyState = createState< +export const forceRegisteredActionsByKeyState = createStateV2< Record >({ key: 'forceRegisteredActionsByKeyComponentState', diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx index 9373ed3ce8..22bc6ae1f9 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx @@ -1,13 +1,15 @@ import { PageHeaderActionMenuButtons } from '@/action-menu/components/PageHeaderActionMenuButtons'; import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIndexActionMenuDropdown'; import { ActionMenuContextProvider } from '@/action-menu/contexts/ActionMenuContextProvider'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsMobile } from 'twenty-ui/utilities'; export const RecordIndexActionMenu = () => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const isMobile = useIsMobile(); diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx index 511ec5dc6b..422e65f8f5 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx @@ -15,7 +15,6 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; @@ -50,7 +49,7 @@ export const RecordIndexActionMenuDropdown = () => { const dropdownId = getActionMenuDropdownIdFromActionMenuId(actionMenuId); const { closeDropdown } = useCloseDropdown(); - const actionMenuDropdownPosition = useRecoilComponentValue( + const actionMenuDropdownPosition = useRecoilComponentValueV2( recordIndexActionMenuDropdownPositionComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx index a34468b55f..cee4ee76c6 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx @@ -1,17 +1,20 @@ import { PageHeaderActionMenuButtons } from '@/action-menu/components/PageHeaderActionMenuButtons'; import { ActionMenuContextProvider } from '@/action-menu/contexts/ActionMenuContextProvider'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsMobile } from 'twenty-ui/utilities'; export const RecordShowActionMenu = () => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const hasSelectedRecord = diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx index c052e4b5ed..37accb98b8 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx @@ -1,11 +1,13 @@ import { CommandMenuActionMenuDropdown } from '@/action-menu/components/CommandMenuActionMenuDropdown'; import { ActionMenuContextProvider } from '@/action-menu/contexts/ActionMenuContextProvider'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const RecordShowRightDrawerActionMenu = () => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); return ( diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx index ca7e2915b3..be4fce8c46 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerOpenRecordButton.tsx @@ -14,11 +14,13 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback, useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { AppPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { IconBrowserMaximize } from 'twenty-ui/display'; @@ -35,9 +37,10 @@ export const RecordShowRightDrawerOpenRecordButton = ({ objectNameSingular, recordId, }: RecordShowRightDrawerOpenRecordButtonProps) => { - const record = useRecoilValue( - recordStoreFamilyState(recordId), - ); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId) as + | ObjectRecord + | null + | undefined; const { closeCommandMenu } = useCommandMenu(); const commandMenuPageComponentInstance = useComponentInstanceStateContext( @@ -63,11 +66,13 @@ export const RecordShowRightDrawerOpenRecordButton = ({ tabListComponentIdInRecordPage, ); - const parentViewState = useRecoilComponentCallbackState( + const parentViewState = useRecoilComponentStateCallbackStateV2( contextStoreRecordShowParentViewComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); + const store = useStore(); + const navigate = useNavigateApp(); const actionMenuId = useAvailableComponentInstanceIdOrThrow( @@ -76,48 +81,45 @@ export const RecordShowRightDrawerOpenRecordButton = ({ const { closeDropdown } = useCloseDropdown(); - const handleOpenRecord = useRecoilCallback( - ({ snapshot, reset }) => - () => { - const tabIdToOpen = - activeTabIdInRightDrawer === 'home' - ? objectNameSingular === CoreObjectNameSingular.Note || - objectNameSingular === CoreObjectNameSingular.Task - ? 'richText' - : 'timeline' - : activeTabIdInRightDrawer; + const handleOpenRecord = useCallback(() => { + const tabIdToOpen = + activeTabIdInRightDrawer === 'home' + ? objectNameSingular === CoreObjectNameSingular.Note || + objectNameSingular === CoreObjectNameSingular.Task + ? 'richText' + : 'timeline' + : activeTabIdInRightDrawer; - setActiveTabIdInRecordPage(tabIdToOpen); + setActiveTabIdInRecordPage(tabIdToOpen); - const parentView = snapshot.getLoadable(parentViewState).getValue(); + const parentView = store.get(parentViewState); - if (parentView?.parentViewObjectNameSingular !== objectNameSingular) { - reset(parentViewState); - } + if (parentView?.parentViewObjectNameSingular !== objectNameSingular) { + store.set(parentViewState, undefined); + } - navigate(AppPath.RecordShowPage, { - objectNameSingular, - objectRecordId: recordId, - }); - - closeDropdown( - getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId), - ); - - closeCommandMenu(); - }, - [ - actionMenuId, - activeTabIdInRightDrawer, - closeCommandMenu, - closeDropdown, - navigate, + navigate(AppPath.RecordShowPage, { objectNameSingular, - parentViewState, - recordId, - setActiveTabIdInRecordPage, - ], - ); + objectRecordId: recordId, + }); + + closeDropdown( + getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId), + ); + + closeCommandMenu(); + }, [ + actionMenuId, + activeTabIdInRightDrawer, + closeCommandMenu, + closeDropdown, + navigate, + objectNameSingular, + parentViewState, + recordId, + setActiveTabIdInRecordPage, + store, + ]); useHotkeysOnFocusedElement({ keys: ['ctrl+Enter,meta+Enter'], diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/CommandMenuActionMenuDropdown.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/CommandMenuActionMenuDropdown.stories.tsx index 4b38eb8591..19884ae8fa 100644 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/CommandMenuActionMenuDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/CommandMenuActionMenuDropdown.stories.tsx @@ -1,5 +1,5 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { RecoilRoot } from 'recoil'; +import { Provider as JotaiProvider } from 'jotai'; import * as test from 'storybook/test'; import { expect, userEvent, waitFor, within } from 'storybook/test'; @@ -7,10 +7,14 @@ import { CommandMenuActionMenuDropdown } from '@/action-menu/components/CommandM import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { createMockActionMenuActions } from '@/action-menu/mock/action-menu-actions.mock'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; -import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; +import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; +import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter'; const deleteMock = test.fn(); const addToFavoritesMock = test.fn(); const exportMock = test.fn(); @@ -20,47 +24,43 @@ const meta: Meta = { component: CommandMenuActionMenuDropdown, decorators: [ (Story) => ( - { - set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: 'story-action-menu', - }), - { + + + - - - - - - + + + + + + + + ), ComponentDecorator, ContextStoreDecorator, + ObjectMetadataItemsDecorator, + SnackBarDecorator, RouterDecorator, ], args: { diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx index 06071a46fc..eef73c0015 100644 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx @@ -1,6 +1,5 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { Provider as JotaiProvider } from 'jotai'; -import { RecoilRoot } from 'recoil'; import * as test from 'storybook/test'; import { expect, userEvent, waitFor, within } from 'storybook/test'; @@ -30,38 +29,33 @@ const meta: Meta = { }), true, ); + jotaiStore.set( + recordIndexActionMenuDropdownPositionComponentState.atomFamily({ + instanceId: 'action-menu-dropdown-story', + }), + { x: 10, y: 10 }, + ); return ( - { - set( - recordIndexActionMenuDropdownPositionComponentState.atomFamily({ - instanceId: 'action-menu-dropdown-story', - }), - { x: 10, y: 10 }, - ); - }} + - - - - - - + + + ); }, diff --git a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx index 9b1af7a97c..ee52c30ce9 100644 --- a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx +++ b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx @@ -1,11 +1,12 @@ import { type ActionMenuContextType } from '@/action-menu/contexts/ActionMenuContext'; import { ActionMenuContextProviderDefault } from '@/action-menu/contexts/ActionMenuContextProviderDefault'; import { ActionMenuContextProviderWorkflowObjects } from '@/action-menu/contexts/ActionMenuContextProviderWorkflowObjects'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; @@ -19,8 +20,9 @@ export const ActionMenuContextProvider = ({ children: React.ReactNode; objectMetadataItemOverride?: ObjectMetadataItem; }) => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); diff --git a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx index 256383cb29..322a230cb6 100644 --- a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx +++ b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx @@ -7,9 +7,10 @@ import { import { useRegisteredActions } from '@/action-menu/hooks/useRegisteredActions'; import { useShouldActionBeRegisteredParams } from '@/action-menu/hooks/useShouldActionBeRegisteredParams'; import { useCommandMenuItemFrontComponentActions } from '@/command-menu-item/hooks/useCommandMenuItemFrontComponentActions'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const ActionMenuContextProviderDefault = ({ objectMetadataItem, @@ -34,8 +35,9 @@ export const ActionMenuContextProviderDefault = ({ const actions = useRegisteredActions(shouldBeRegisteredParams); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const isRecordSelection = diff --git a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowObjects.tsx b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowObjects.tsx index d2fc025099..cd97f1b001 100644 --- a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowObjects.tsx +++ b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowObjects.tsx @@ -6,13 +6,14 @@ import { import { useRegisteredActions } from '@/action-menu/hooks/useRegisteredActions'; import { useShouldActionBeRegisteredParams } from '@/action-menu/hooks/useShouldActionBeRegisteredParams'; import { useCommandMenuItemFrontComponentActions } from '@/command-menu-item/hooks/useCommandMenuItemFrontComponentActions'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; type ActionMenuContextProviderWorkflowObjectsProps = { @@ -122,8 +123,9 @@ export const ActionMenuContextProviderWorkflowObjects = ({ actionMenuType, children, }: ActionMenuContextProviderWorkflowObjectsProps) => { - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const recordId = @@ -133,7 +135,7 @@ export const ActionMenuContextProviderWorkflowObjects = ({ : undefined; const selectedRecord = - useRecoilValue(recordStoreFamilyState(recordId ?? '')) || undefined; + useFamilyRecoilValueV2(recordStoreFamilyState, recordId ?? '') || undefined; if (isDefined(selectedRecord?.id)) { return ( diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts index 0e583568b2..0a0bb7a00b 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts @@ -4,11 +4,13 @@ import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { type ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/types/ShouldBeRegisteredFunctionParams'; import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig'; import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -20,16 +22,21 @@ export const useRegisteredActions = ( const { getIcon } = useIcons(); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const contextStoreCurrentViewType = useRecoilComponentValue( + const contextStoreCurrentViewType = useRecoilComponentValueV2( contextStoreCurrentViewTypeComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const isFullTabWidgetInEditMode = useRecoilComponentValue( + const { recordIndexId } = useRecordIndexIdFromCurrentContextStore(); + + const isFullTabWidgetInEditMode = useRecoilComponentValueV2( contextStoreIsPageInEditModeComponentState, + recordIndexId, ); const viewType = getActionViewType( diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts b/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts index 1c3f4c9939..5b98c56e3d 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts @@ -4,6 +4,7 @@ import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; @@ -12,15 +13,17 @@ import { useFavorites } from '@/favorites/hooks/useFavorites'; import { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useCallback, useContext, useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -35,8 +38,9 @@ export const useShouldActionBeRegisteredParams = ({ FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED, ); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const recordId = @@ -71,7 +75,7 @@ export const useShouldActionBeRegisteredParams = ({ ]); const selectedRecord = - useRecoilValue(recordStoreFamilyState(recordId ?? '')) || undefined; + useFamilyRecoilValueV2(recordStoreFamilyState, recordId ?? '') || undefined; const objectPermissions = useObjectPermissionsForObject( objectMetadataItem?.id ?? '', @@ -83,20 +87,27 @@ export const useShouldActionBeRegisteredParams = ({ const { isInRightDrawer } = useContext(ActionMenuContext); - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const { recordIndexId } = useRecordIndexIdFromCurrentContextStore(); + + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, + recordIndexId, ); const isShowPage = - useRecoilComponentValue(contextStoreCurrentViewTypeComponentState) === - ContextStoreViewType.ShowPage; + useRecoilComponentValueV2( + contextStoreCurrentViewTypeComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, + ) === ContextStoreViewType.ShowPage; - const numberOfSelectedRecords = useRecoilComponentValue( + const numberOfSelectedRecords = useRecoilComponentValueV2( contextStoreNumberOfSelectedRecordsComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const contextStoreCurrentViewType = useRecoilComponentValue( + const contextStoreCurrentViewType = useRecoilComponentValueV2( contextStoreCurrentViewTypeComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const viewType = getActionViewType( @@ -128,7 +139,7 @@ export const useShouldActionBeRegisteredParams = ({ [], ); - const forceRegisteredActionsByKey = useRecoilValue( + const forceRegisteredActionsByKey = useRecoilValueV2( forceRegisteredActionsByKeyState, ); diff --git a/packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts b/packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts index 88f13fce0e..5116c24d21 100644 --- a/packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts +++ b/packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts @@ -1,9 +1,9 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { type PositionType } from '@/action-menu/types/PositionType'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordIndexActionMenuDropdownPositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexActionMenuDropdownPositionComponentState', defaultValue: { x: null, diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx index 3dfb6c0e10..622ce272c4 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx @@ -1,7 +1,7 @@ +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { format, getYear } from 'date-fns'; -import { useRecoilValue } from 'recoil'; import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard'; import { TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE } from '@/activities/calendar/constants/Calendar'; @@ -26,7 +26,7 @@ import { Section, } from 'twenty-ui/layout'; import { type TimelineCalendarEventsWithTotal } from '~/generated/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; const StyledContainer = styled.div` box-sizing: border-box; @@ -49,7 +49,7 @@ const StyledTitleContainer = styled.div` export const CalendarEventsCard = () => { const { t } = useLingui(); const targetRecord = useTargetRecord(); - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const [query, queryName] = targetRecord.targetObjectNameSingular === CoreObjectNameSingular.Person diff --git a/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx b/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx index 963d0a4c56..091e748206 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx @@ -1,10 +1,11 @@ import { useCallback, useMemo } from 'react'; -import { useRecoilCallback, useRecoilState } from 'recoil'; +import { useAtom, useStore } from 'jotai'; import { v4 } from 'uuid'; import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttachmentFile'; import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity'; import { canCreateActivityState } from '@/activities/states/canCreateActivityState'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -56,7 +57,10 @@ export const ActivityRichTextEditor = ({ activityId, activityObjectNameSingular, }: ActivityRichTextEditorProps) => { - const [activityInStore] = useRecoilState(recordStoreFamilyState(activityId)); + const store = useStore(); + const [activityInStore] = useAtom( + recordStoreFamilyState.atomFamily(activityId), + ); const cache = useApolloCoreClient().cache; const activity = activityInStore as Task | Note | null; @@ -122,7 +126,7 @@ export const ActivityRichTextEditor = ({ } }, 300); - const [canCreateActivity, setCanCreateActivity] = useRecoilState( + const [canCreateActivity, setCanCreateActivity] = useRecoilStateV2( canCreateActivityState, ); @@ -145,47 +149,45 @@ export const ActivityRichTextEditor = ({ [canCreateActivity, persistBodyDebounced, setCanCreateActivity], ); - const handleBodyChange = useRecoilCallback( - ({ set, snapshot }) => - async (newStringifiedBody: string) => { - const oldActivity = snapshot - .getLoadable(recordStoreFamilyState(activityId)) - .getValue(); + const handleBodyChange = useCallback( + async (newStringifiedBody: string) => { + const oldActivity = store.get( + recordStoreFamilyState.atomFamily(activityId), + ); - set(recordStoreFamilyState(activityId), (oldActivity) => { - return { - ...oldActivity, - id: activityId, - bodyV2: { + store.set( + recordStoreFamilyState.atomFamily(activityId), + (prev: typeof oldActivity) => ({ + ...prev, + id: activityId, + bodyV2: { + blocknote: newStringifiedBody, + markdown: null, + }, + __typename: 'Activity', + }), + ); + + modifyRecordFromCache({ + recordId: activityId, + fieldModifiers: { + bodyV2: () => { + return { blocknote: newStringifiedBody, markdown: null, - }, - __typename: 'Activity', - }; - }); - - modifyRecordFromCache({ - recordId: activityId, - fieldModifiers: { - bodyV2: () => { - return { - blocknote: newStringifiedBody, - markdown: null, - }; - }, + }; }, - cache, - objectMetadataItem: objectMetadataItemActivity, - }); + }, + cache, + objectMetadataItem: objectMetadataItemActivity, + }); - handlePersistBody(newStringifiedBody); + handlePersistBody(newStringifiedBody); - await syncAttachments( - newStringifiedBody, - oldActivity?.bodyV2.blocknote, - ); - }, + await syncAttachments(newStringifiedBody, oldActivity?.bodyV2.blocknote); + }, [ + store, activityId, cache, objectMetadataItemActivity, @@ -299,59 +301,43 @@ export const ActivityRichTextEditor = ({ // but this leaves the door open for unpredicted behavior with click handlers conflicts, // we recently had a bug which was deleting what the user typed and closed the right drawer if he used backspace key. // We could maybe use the types of components in the focus stack. - const handleBlockEditorFocus = useRecoilCallback( - ({ snapshot }) => - () => { - // TODO: Here we want to detect anything that is open to avoid conflicts with the library click event - // that is not prevented and propagate to other click handlers in the app. - // Because that is how we do in the app, for example with stacked dropdowns, we always close what's open before - // letting the click being captured by a button or input that can capture it. - const isRecordTitleCellOpen = snapshot - .getLoadable( - isTitleCellInEditModeComponentState.atomFamily({ - instanceId: recordTitleCellId, - }), - ) - .getValue(); + const handleBlockEditorFocus = useCallback(() => { + const isRecordTitleCellOpen = store.get( + isTitleCellInEditModeComponentState.atomFamily({ + instanceId: recordTitleCellId, + }), + ); - if (isRecordTitleCellOpen) { - editor.domElement?.blur(); - return; - } + if (isRecordTitleCellOpen) { + editor.domElement?.blur(); + return; + } - pushFocusItemToFocusStack({ - component: { - instanceId: activityId, - type: FocusComponentType.ACTIVITY_RICH_TEXT_EDITOR, - }, - focusId: activityId, - globalHotkeysConfig: BLOCK_EDITOR_GLOBAL_HOTKEYS_CONFIG, - }); + pushFocusItemToFocusStack({ + component: { + instanceId: activityId, + type: FocusComponentType.ACTIVITY_RICH_TEXT_EDITOR, }, - [recordTitleCellId, activityId, editor, pushFocusItemToFocusStack], - ); + focusId: activityId, + globalHotkeysConfig: BLOCK_EDITOR_GLOBAL_HOTKEYS_CONFIG, + }); + }, [recordTitleCellId, activityId, editor, pushFocusItemToFocusStack, store]); - const handlerBlockEditorBlur = useRecoilCallback( - ({ snapshot }) => - () => { - const isRecordTitleCellOpen = snapshot - .getLoadable( - isTitleCellInEditModeComponentState.atomFamily({ - instanceId: recordTitleCellId, - }), - ) - .getValue(); + const handlerBlockEditorBlur = useCallback(() => { + const isRecordTitleCellOpen = store.get( + isTitleCellInEditModeComponentState.atomFamily({ + instanceId: recordTitleCellId, + }), + ); - if (isRecordTitleCellOpen) { - return; - } + if (isRecordTitleCellOpen) { + return; + } - removeFocusItemFromFocusStackById({ - focusId: activityId, - }); - }, - [activityId, recordTitleCellId, removeFocusItemFromFocusStackById], - ); + removeFocusItemFromFocusStackById({ + focusId: activityId, + }); + }, [activityId, recordTitleCellId, removeFocusItemFromFocusStackById, store]); return ( <> diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx index 233b63e077..ce026d9445 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx @@ -1,8 +1,8 @@ +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; type EmailThreadHeaderProps = { @@ -43,7 +43,7 @@ export const EmailThreadHeader = ({ subject, lastMessageSentAt, }: EmailThreadHeaderProps) => { - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const lastMessageSentAtFormatted = beautifyPastDateRelativeToNow( lastMessageSentAt, localeCatalog, diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx index 97291f4f17..02bb62e67e 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx @@ -1,10 +1,10 @@ import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { ParticipantChip } from '@/activities/components/ParticipantChip'; import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { AppTooltip, TooltipPosition } from 'twenty-ui/display'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyPastDateRelativeToNow, formatToHumanReadableDate, @@ -31,7 +31,7 @@ export const EmailThreadMessageSender = ({ sender, sentAt, }: EmailThreadMessageSenderProps) => { - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const tooltipId = `date-tooltip-${sentAt.replace(/[^a-zA-Z0-9]/g, '-')}`; return ( diff --git a/packages/twenty-front/src/modules/activities/emails/states/lastViewableEmailThreadIdState.ts b/packages/twenty-front/src/modules/activities/emails/states/lastViewableEmailThreadIdState.ts index 8990ecaf17..b7cb289080 100644 --- a/packages/twenty-front/src/modules/activities/emails/states/lastViewableEmailThreadIdState.ts +++ b/packages/twenty-front/src/modules/activities/emails/states/lastViewableEmailThreadIdState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const emailThreadIdWhenEmailThreadWasClosedState = createState< +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const emailThreadIdWhenEmailThreadWasClosedState = createStateV2< string | null >({ key: 'emailThreadIdWhenEmailThreadWasClosedState', diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx index c170b3eab8..470e197bbc 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx @@ -3,12 +3,13 @@ import { MockedProvider } from '@apollo/client/testing'; import { act, renderHook } from '@testing-library/react'; import { type ReactNode } from 'react'; import { Provider as JotaiProvider } from 'jotai'; -import { RecoilRoot, useSetRecoilState } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext'; import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter'; @@ -139,8 +140,9 @@ describe('useActivityTargetObjectRecords', () => { const { result } = renderHook( () => { - const setRecordFromStore = useSetRecoilState( - recordStoreFamilyState(task.id), + const setRecordFromStore = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + task.id, ); const { activityTargetObjectRecords } = useActivityTargetObjectRecords( diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx index 161db27750..1dad9988b4 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx @@ -1,11 +1,11 @@ import { type MockedResponse } from '@apollo/client/testing'; import { act, renderHook } from '@testing-library/react'; -import { useRecoilValue } from 'recoil'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import gql from 'graphql-tag'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; @@ -83,7 +83,7 @@ describe('useOpenCreateActivityDrawer', () => { const openActivityRightDrawer = useOpenCreateActivityDrawer({ activityObjectNameSingular: CoreObjectNameSingular.Note, }); - const viewableRecordId = useRecoilValue(viewableRecordIdState); + const viewableRecordId = useRecoilValueV2(viewableRecordIdState); return { openActivityRightDrawer, viewableRecordId, diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts index 4e61d3b3ff..9edee49591 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useActivityTargetsForTargetableObjects } from '@/activities/hooks/useActivityTargetsForTargetableObjects'; import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { type Note } from '@/activities/types/Note'; @@ -7,7 +10,6 @@ import { type TaskTarget } from '@/activities/types/TaskTarget'; import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilCallback } from 'recoil'; import { type RecordGqlOperationOrderBy } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -24,15 +26,15 @@ export const useActivities = ({ skip?: boolean; limit: number; }) => { - const updateActivitiesInStore = useRecoilCallback( - ({ set }) => - (activityTargets: (TaskTarget | NoteTarget)[]) => { - for (const activityTarget of activityTargets) { - const activity = activityTarget[objectNameSingular]; - set(recordStoreFamilyState(activity.id), activity); - } - }, - [objectNameSingular], + const store = useStore(); + const updateActivitiesInStore = useCallback( + (activityTargets: (TaskTarget | NoteTarget)[]) => { + for (const activityTarget of activityTargets) { + const activity = activityTarget[objectNameSingular]; + store.set(recordStoreFamilyState.atomFamily(activity.id), activity); + } + }, + [store, objectNameSingular], ); const { diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts index 563b1a6889..38a5fab531 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts @@ -1,5 +1,3 @@ -import { useRecoilValue } from 'recoil'; - import { type Note } from '@/activities/types/Note'; import { type NoteTarget } from '@/activities/types/NoteTarget'; import { type Task } from '@/activities/types/Task'; @@ -7,6 +5,7 @@ import { type TaskTarget } from '@/activities/types/TaskTarget'; import { getActivityTargetObjectRecords } from '@/activities/utils/getActivityTargetObjectRecords'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { type Nullable } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -17,8 +16,9 @@ export const useActivityTargetObjectRecords = ( ) => { const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); - const activity = useRecoilValue( - recordStoreFamilyState(activityRecordId ?? ''), + const activity = useFamilyRecoilValueV2( + recordStoreFamilyState, + activityRecordId ?? '', ) as Note | Task | null; if (!isDefined(activity) && !isDefined(activityTargets)) { diff --git a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts index c22431a339..099cfe5567 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts @@ -1,3 +1,5 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { isNonEmptyArray } from '@sniptt/guards'; import { type ActivityForEditor } from '@/activities/types/ActivityForEditor'; @@ -15,7 +17,6 @@ import { createOneActivityOperationSignatureFactory } from '@/activities/graphql import { type NoteTarget } from '@/activities/types/NoteTarget'; import { type TaskTarget } from '@/activities/types/TaskTarget'; import { getJoinObjectNameSingular } from '@/activities/utils/getJoinObjectNameSingular'; -import { useRecoilCallback } from 'recoil'; import { capitalize } from 'twenty-shared/utils'; export const useCreateActivityInDB = ({ @@ -56,53 +57,52 @@ export const useCreateActivityInDB = ({ }); const cache = useApolloCoreClient().cache; + const store = useStore(); - const createActivityInDB = useRecoilCallback( - ({ set }) => - async (activityToCreate: ActivityForEditor) => { - const createdActivity = await createOneActivity?.({ - ...activityToCreate, - updatedAt: new Date().toISOString(), + const createActivityInDB = useCallback( + async (activityToCreate: ActivityForEditor) => { + const createdActivity = await createOneActivity?.({ + ...activityToCreate, + updatedAt: new Date().toISOString(), + }); + + const activityTargetsToCreate = + activityToCreate.noteTargets ?? activityToCreate.taskTargets ?? []; + + if (isNonEmptyArray(activityTargetsToCreate)) { + await createManyActivityTargets({ + recordsToCreate: activityTargetsToCreate, }); + } - const activityTargetsToCreate = - activityToCreate.noteTargets ?? activityToCreate.taskTargets ?? []; + const activityTargetsConnection = getRecordConnectionFromRecords({ + objectMetadataItems, + objectMetadataItem: objectMetadataItemActivityTarget, + records: activityTargetsToCreate.map((activityTarget) => ({ + ...activityTarget, + __typename: capitalize(objectMetadataItemActivityTarget.nameSingular), + })), + withPageInfo: false, + computeReferences: true, + isRootLevel: false, + }); - if (isNonEmptyArray(activityTargetsToCreate)) { - await createManyActivityTargets({ - recordsToCreate: activityTargetsToCreate, - }); - } + modifyRecordFromCache({ + recordId: createdActivity.id, + cache, + fieldModifiers: { + activityTargets: () => activityTargetsConnection, + }, + objectMetadataItem: objectMetadataItemActivity, + }); - const activityTargetsConnection = getRecordConnectionFromRecords({ - objectMetadataItems, - objectMetadataItem: objectMetadataItemActivityTarget, - records: activityTargetsToCreate.map((activityTarget) => ({ - ...activityTarget, - __typename: capitalize( - objectMetadataItemActivityTarget.nameSingular, - ), - })), - withPageInfo: false, - computeReferences: true, - isRootLevel: false, - }); - - modifyRecordFromCache({ - recordId: createdActivity.id, - cache, - fieldModifiers: { - activityTargets: () => activityTargetsConnection, - }, - objectMetadataItem: objectMetadataItemActivity, - }); - - set(recordStoreFamilyState(createdActivity.id), { - ...createdActivity, - activityTargets: activityTargetsToCreate, - }); - }, + store.set(recordStoreFamilyState.atomFamily(createdActivity.id), { + ...createdActivity, + activityTargets: activityTargetsToCreate, + }); + }, [ + store, cache, createManyActivityTargets, createOneActivity, diff --git a/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts b/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts index dcdd3a1838..3834611674 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts @@ -1,5 +1,3 @@ -import { useSetRecoilState } from 'recoil'; - import { activityTargetableEntityArrayState } from '@/activities/states/activityTargetableEntityArrayState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; @@ -7,6 +5,7 @@ import { viewableRecordNameSingularState } from '@/object-record/record-right-dr import { type WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { isUpsertingActivityInDBState } from '@/activities/states/isCreatingActivityInDBState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { type Note } from '@/activities/types/Note'; import { type NoteTarget } from '@/activities/types/NoteTarget'; @@ -40,15 +39,15 @@ export const useOpenCreateActivityDrawer = ({ shouldMatchRootQueryFilter: true, }); - const setActivityTargetableEntityArray = useSetRecoilState( + const setActivityTargetableEntityArray = useSetRecoilStateV2( activityTargetableEntityArrayState, ); - const setViewableRecordId = useSetRecoilState(viewableRecordIdState); - const setViewableRecordNameSingular = useSetRecoilState( + const setViewableRecordId = useSetRecoilStateV2(viewableRecordIdState); + const setViewableRecordNameSingular = useSetRecoilStateV2( viewableRecordNameSingularState, ); - const setIsUpsertingActivityInDB = useSetRecoilState( + const setIsUpsertingActivityInDB = useSetRecoilStateV2( isUpsertingActivityInDBState, ); diff --git a/packages/twenty-front/src/modules/activities/hooks/useReplaceActivityBlockEditorContent.ts b/packages/twenty-front/src/modules/activities/hooks/useReplaceActivityBlockEditorContent.ts index 7f7acc5b3d..f6cb4a7392 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useReplaceActivityBlockEditorContent.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useReplaceActivityBlockEditorContent.ts @@ -1,31 +1,33 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { type BLOCK_SCHEMA } from '@/blocknote-editor/blocks/Schema'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useReplaceActivityBlockEditorContent = ( editor: typeof BLOCK_SCHEMA.BlockNoteEditor, ) => { - const replaceBlockEditorContent = useRecoilCallback( - ({ snapshot }) => - (activityId: string) => { - if (isDefined(editor)) { - const activityInStore = snapshot - .getLoadable(recordStoreFamilyState(activityId)) - .getValue(); + const store = useStore(); + const replaceBlockEditorContent = useCallback( + (activityId: string) => { + if (isDefined(editor)) { + const activityInStore = store.get( + recordStoreFamilyState.atomFamily(activityId), + ); - const content = isNonEmptyString(activityInStore?.bodyV2.blocknote) - ? JSON.parse(activityInStore?.bodyV2.blocknote) - : [{ type: 'paragraph', content: '' }]; + const content = isNonEmptyString(activityInStore?.bodyV2.blocknote) + ? JSON.parse(activityInStore?.bodyV2.blocknote) + : [{ type: 'paragraph', content: '' }]; - if (!isDeeplyEqual(editor.document, content)) { - editor.replaceBlocks(editor.document, content); - } + if (!isDeeplyEqual(editor.document, content)) { + editor.replaceBlocks(editor.document, content); } - }, - [editor], + } + }, + [store, editor], ); return { diff --git a/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts b/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts index 0ae4cee740..7064b671fb 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts @@ -1,5 +1,3 @@ -import { useRecoilState } from 'recoil'; - import { useCreateActivityInDB } from '@/activities/hooks/useCreateActivityInDB'; import { useRefreshShowPageFindManyActivitiesQueries } from '@/activities/hooks/useRefreshShowPageFindManyActivitiesQueries'; import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState'; @@ -30,7 +28,7 @@ export const useUpsertActivity = ({ activityObjectNameSingular, }); - const [, setIsUpsertingActivityInDB] = useRecoilState( + const [, setIsUpsertingActivityInDB] = useRecoilStateV2( isUpsertingActivityInDBState, ); diff --git a/packages/twenty-front/src/modules/activities/inline-cell/hooks/useOpenActivityTargetCellEditMode.ts b/packages/twenty-front/src/modules/activities/inline-cell/hooks/useOpenActivityTargetCellEditMode.ts index 8a1652bc56..2334762e28 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/hooks/useOpenActivityTargetCellEditMode.ts +++ b/packages/twenty-front/src/modules/activities/inline-cell/hooks/useOpenActivityTargetCellEditMode.ts @@ -9,7 +9,7 @@ import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/ import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; type OpenActivityTargetCellEditModeProps = { recordPickerInstanceId: string; @@ -24,81 +24,80 @@ export const useOpenActivityTargetCellEditMode = () => { const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); - const openActivityTargetCellEditMode = useRecoilCallback( - ({ set }) => - ({ - recordPickerInstanceId, - activityTargetObjectRecords, - }: OpenActivityTargetCellEditModeProps) => { - const objectMetadataItems = jotaiStore - .get(objectMetadataItemsState.atom) - .filter( - (objectMetadataItem) => - objectMetadataItem.isSearchable && - objectMetadataItem.isActive && - objectMetadataItem.nameSingular !== CoreObjectNameSingular.Task && - objectMetadataItem.nameSingular !== CoreObjectNameSingular.Note && - objectMetadataItem.nameSingular !== - CoreObjectNameSingular.WorkspaceMember, - ); + const openActivityTargetCellEditMode = useCallback( + ({ + recordPickerInstanceId, + activityTargetObjectRecords, + }: OpenActivityTargetCellEditModeProps) => { + const objectMetadataItems = jotaiStore + .get(objectMetadataItemsState.atom) + .filter( + (objectMetadataItem) => + objectMetadataItem.isSearchable && + objectMetadataItem.isActive && + objectMetadataItem.nameSingular !== CoreObjectNameSingular.Task && + objectMetadataItem.nameSingular !== CoreObjectNameSingular.Note && + objectMetadataItem.nameSingular !== + CoreObjectNameSingular.WorkspaceMember, + ); - set( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ + jotaiStore.set( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ + instanceId: recordPickerInstanceId, + }), + activityTargetObjectRecords.map((activityTargetObjectRecord) => ({ + recordId: activityTargetObjectRecord.targetObject.id, + objectMetadataId: + activityTargetObjectRecord.targetObjectMetadataItem.id, + isSelected: true, + isMatchingSearchFilter: true, + })), + ); + + jotaiStore.set( + multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( + { instanceId: recordPickerInstanceId, - }), - activityTargetObjectRecords.map((activityTargetObjectRecord) => ({ + }, + ), + objectMetadataItems, + ); + + jotaiStore.set( + multipleRecordPickerSearchFilterComponentState.atomFamily({ + instanceId: recordPickerInstanceId, + }), + '', + ); + + openMultipleRecordPicker(recordPickerInstanceId); + + multipleRecordPickerPerformSearch({ + multipleRecordPickerInstanceId: recordPickerInstanceId, + forceSearchFilter: '', + forceSearchableObjectMetadataItems: objectMetadataItems, + forcePickableMorphItems: activityTargetObjectRecords.map( + (activityTargetObjectRecord) => ({ recordId: activityTargetObjectRecord.targetObject.id, objectMetadataId: activityTargetObjectRecord.targetObjectMetadataItem.id, isSelected: true, isMatchingSearchFilter: true, - })), - ); - - set( - multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( - { - instanceId: recordPickerInstanceId, - }, - ), - objectMetadataItems, - ); - - set( - multipleRecordPickerSearchFilterComponentState.atomFamily({ - instanceId: recordPickerInstanceId, }), - '', - ); + ), + }); - openMultipleRecordPicker(recordPickerInstanceId); - - multipleRecordPickerPerformSearch({ - multipleRecordPickerInstanceId: recordPickerInstanceId, - forceSearchFilter: '', - forceSearchableObjectMetadataItems: objectMetadataItems, - forcePickableMorphItems: activityTargetObjectRecords.map( - (activityTargetObjectRecord) => ({ - recordId: activityTargetObjectRecord.targetObject.id, - objectMetadataId: - activityTargetObjectRecord.targetObjectMetadataItem.id, - isSelected: true, - isMatchingSearchFilter: true, - }), - ), - }); - - pushFocusItemToFocusStack({ - focusId: recordPickerInstanceId, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: recordPickerInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - }, + pushFocusItemToFocusStack({ + focusId: recordPickerInstanceId, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: recordPickerInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, [ multipleRecordPickerPerformSearch, openMultipleRecordPicker, diff --git a/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts b/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts index 3ae3d426c8..676062f64b 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts +++ b/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts @@ -10,12 +10,13 @@ import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { searchRecordStoreFamilyState } from '@/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; type UpdateActivityTargetFromCellProps = { recordPickerInstanceId: string; @@ -64,148 +65,148 @@ export const useUpdateActivityTargetFromCell = ({ ? isTaskTargetMigrated : isNoteTargetMigrated; - const setActivityFromStore = useSetRecoilState( - recordStoreFamilyState(activityId), + const store = useStore(); + const setActivityFromStore = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + activityId, ); - const updateActivityTargetFromCell = useRecoilCallback( - ({ snapshot }) => - async ({ - morphItem, - activityTargetWithTargetRecords, - }: UpdateActivityTargetFromCellProps) => { - const targetObjectName = - activityObjectNameSingular === CoreObjectNameSingular.Task - ? 'task' - : 'note'; + const updateActivityTargetFromCell = useCallback( + async ({ + morphItem, + activityTargetWithTargetRecords, + }: UpdateActivityTargetFromCellProps) => { + const targetObjectName = + activityObjectNameSingular === CoreObjectNameSingular.Task + ? 'task' + : 'note'; - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, + const objectMetadataItems = store.get(objectMetadataItemsState.atom); + + const pickedObjectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.id === morphItem.objectMetadataId, + ); + + if (!isDefined(pickedObjectMetadataItem)) { + throw new Error('Could not find object metadata item'); + } + + const targetFieldName = getActivityTargetFieldNameForObject({ + activityObjectNameSingular, + targetObjectMetadataId: morphItem.objectMetadataId, + objectMetadataItems, + isMorphRelation, + }); + + if (!isDefined(targetFieldName)) { + throw new Error( + `Could not find field on activity target for object ${pickedObjectMetadataItem.nameSingular}`, ); + } - const pickedObjectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.id === morphItem.objectMetadataId, - ); + let activityTargetsAfterUpdate: (TaskTarget | NoteTarget)[] = []; - if (!isDefined(pickedObjectMetadataItem)) { - throw new Error('Could not find object metadata item'); - } + const existingActivityTarget = activityTargetWithTargetRecords.find( + (activityTarget) => + activityTarget.targetObject.id === morphItem.recordId, + ); - const targetFieldName = getActivityTargetFieldNameForObject({ - activityObjectNameSingular, - targetObjectMetadataId: morphItem.objectMetadataId, - objectMetadataItems, - isMorphRelation, - }); + if (isDefined(existingActivityTarget)) { + activityTargetsAfterUpdate = activityTargetWithTargetRecords + .map((activityTarget) => { + if ( + activityTarget.targetObject.id === morphItem.recordId && + !morphItem.isSelected + ) { + return undefined; + } - if (!isDefined(targetFieldName)) { - throw new Error( - `Could not find field on activity target for object ${pickedObjectMetadataItem.nameSingular}`, + return activityTarget.activityTarget; + }) + .filter(isDefined); + + if (!morphItem.isSelected) { + await deleteOneActivityTarget( + existingActivityTarget.activityTarget.id, ); } - - let activityTargetsAfterUpdate: (TaskTarget | NoteTarget)[] = []; - - const existingActivityTarget = activityTargetWithTargetRecords.find( - (activityTarget) => - activityTarget.targetObject.id === morphItem.recordId, + } else { + const searchRecord = store.get( + searchRecordStoreFamilyState.atomFamily(morphItem.recordId), ); - if (isDefined(existingActivityTarget)) { - activityTargetsAfterUpdate = activityTargetWithTargetRecords - .map((activityTarget) => { - if ( - activityTarget.targetObject.id === morphItem.recordId && - !morphItem.isSelected - ) { - return undefined; - } - - return activityTarget.activityTarget; - }) - .filter(isDefined); - - if (!morphItem.isSelected) { - await deleteOneActivityTarget( - existingActivityTarget.activityTarget.id, - ); - } - } else { - const searchRecord = snapshot - .getLoadable(searchRecordStoreFamilyState(morphItem.recordId)) - .getValue(); - - if (!isDefined(searchRecord) || !isDefined(searchRecord?.record)) { - return; - } - - if (!morphItem.isSelected) { - return; - } - - const targetRecord = searchRecord.record; - - const activityTarget: NoteTarget | TaskTarget = - activityObjectNameSingular === CoreObjectNameSingular.Task - ? { - id: v4(), - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - __typename: 'TaskTarget', - taskId: activityId, - task: { - id: activityId, - __typename: 'Task', - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }, - [targetFieldName]: targetRecord, - } - : { - id: v4(), - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - __typename: 'NoteTarget', - noteId: activityId, - note: { - id: activityId, - __typename: 'Note', - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }, - [targetFieldName]: targetRecord, - }; - - activityTargetsAfterUpdate = [ - ...activityTargetWithTargetRecords.map((activityTarget) => { - return activityTarget.activityTarget; - }), - activityTarget, - ]; - - const activityTargetInput: Partial = { - ...activityTarget, - [targetObjectName]: undefined, - [targetFieldName]: undefined, - [`${targetFieldName}Id`]: morphItem.recordId, - }; - - await createOneActivityTarget(activityTargetInput); + if (!isDefined(searchRecord) || !isDefined(searchRecord?.record)) { + return; } - setActivityFromStore((currentActivity) => { - if (!isDefined(currentActivity)) { - return null; - } + if (!morphItem.isSelected) { + return; + } - return { - ...currentActivity, - [`${targetObjectName}Targets`]: activityTargetsAfterUpdate, - }; - }); - }, + const targetRecord = searchRecord.record; + + const activityTarget: NoteTarget | TaskTarget = + activityObjectNameSingular === CoreObjectNameSingular.Task + ? { + id: v4(), + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + __typename: 'TaskTarget', + taskId: activityId, + task: { + id: activityId, + __typename: 'Task', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + [targetFieldName]: targetRecord, + } + : { + id: v4(), + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + __typename: 'NoteTarget', + noteId: activityId, + note: { + id: activityId, + __typename: 'Note', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + [targetFieldName]: targetRecord, + }; + + activityTargetsAfterUpdate = [ + ...activityTargetWithTargetRecords.map((activityTarget) => { + return activityTarget.activityTarget; + }), + activityTarget, + ]; + + const activityTargetInput: Partial = { + ...activityTarget, + [targetObjectName]: undefined, + [targetFieldName]: undefined, + [`${targetFieldName}Id`]: morphItem.recordId, + }; + + await createOneActivityTarget(activityTargetInput); + } + + setActivityFromStore((currentActivity) => { + if (!isDefined(currentActivity)) { + return null; + } + + return { + ...currentActivity, + [`${targetObjectName}Targets`]: activityTargetsAfterUpdate, + }; + }); + }, [ + store, activityId, activityObjectNameSingular, createOneActivityTarget, diff --git a/packages/twenty-front/src/modules/activities/states/activityBodyFamilyState.ts b/packages/twenty-front/src/modules/activities/states/activityBodyFamilyState.ts index b9d5579573..94cb81297b 100644 --- a/packages/twenty-front/src/modules/activities/states/activityBodyFamilyState.ts +++ b/packages/twenty-front/src/modules/activities/states/activityBodyFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const activityBodyFamilyState = createFamilyState< +export const activityBodyFamilyState = createFamilyStateV2< string, { activityId: string } >({ diff --git a/packages/twenty-front/src/modules/activities/states/activityTargetableEntityArrayState.ts b/packages/twenty-front/src/modules/activities/states/activityTargetableEntityArrayState.ts index f2c2112f03..c89dd1b33a 100644 --- a/packages/twenty-front/src/modules/activities/states/activityTargetableEntityArrayState.ts +++ b/packages/twenty-front/src/modules/activities/states/activityTargetableEntityArrayState.ts @@ -1,7 +1,7 @@ import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const activityTargetableEntityArrayState = createState< +export const activityTargetableEntityArrayState = createStateV2< ActivityTargetableObject[] >({ key: 'activities/targetable-entity-array', diff --git a/packages/twenty-front/src/modules/activities/states/canCreateActivityState.ts b/packages/twenty-front/src/modules/activities/states/canCreateActivityState.ts index f10791e406..63e59a07af 100644 --- a/packages/twenty-front/src/modules/activities/states/canCreateActivityState.ts +++ b/packages/twenty-front/src/modules/activities/states/canCreateActivityState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const canCreateActivityState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const canCreateActivityState = createStateV2({ key: 'canCreateActivityState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/activities/states/isCreatingActivityInDBState.ts b/packages/twenty-front/src/modules/activities/states/isCreatingActivityInDBState.ts index 87ef641f46..3bba22da26 100644 --- a/packages/twenty-front/src/modules/activities/states/isCreatingActivityInDBState.ts +++ b/packages/twenty-front/src/modules/activities/states/isCreatingActivityInDBState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const isUpsertingActivityInDBState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const isUpsertingActivityInDBState = createStateV2({ key: 'isUpsertingActivityInDBState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx index 3fe577b858..f0dca9899e 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx @@ -1,7 +1,6 @@ import styled from '@emotion/styled'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { TimelineActivityContext } from '@/activities/timeline-activities/contexts/TimelineActivityContext'; @@ -14,7 +13,8 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons'; @@ -99,11 +99,14 @@ export const EventRow = ({ allowRequestsToTwentyIconsState, ); - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const { recordId } = useContext(TimelineActivityContext); - const recordFromStore = useRecoilValue(recordStoreFamilyState(recordId)); + const recordFromStore = useFamilyRecoilValueV2( + recordStoreFamilyState, + recordId, + ); const beautifiedCreatedAt = beautifyPastDateRelativeToNow( event.createdAt, diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect.tsx index 687fb35bbc..400a470cb5 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect.tsx @@ -1,9 +1,9 @@ import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { isDefined } from 'twenty-shared/utils'; export const EventFieldDiffValueEffect = ({ @@ -17,8 +17,9 @@ export const EventFieldDiffValueEffect = ({ mainObjectMetadataItem: ObjectMetadataItem; fieldMetadataItem: FieldMetadataItem; }) => { - const setEntity = useSetRecoilState( - recordStoreFamilyState(diffArtificialRecordStoreId), + const setEntity = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + diffArtificialRecordStoreId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx b/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx index 7852554930..fb19f44013 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx @@ -1,5 +1,4 @@ import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { AgentChatFilePreview } from '@/ai/components/internal/AgentChatFilePreview'; import { AgentMessageRole } from '@/ai/constants/AgentMessageRole'; @@ -7,9 +6,10 @@ import { AgentMessageRole } from '@/ai/constants/AgentMessageRole'; import { AIChatAssistantMessageRenderer } from '@/ai/components/AIChatAssistantMessageRenderer'; import { AIChatErrorRenderer } from '@/ai/components/AIChatErrorRenderer'; import { LightCopyIconButton } from '@/object-record/record-field/ui/components/LightCopyIconButton'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { type ExtendedUIMessage } from 'twenty-shared/ai'; import { isDefined } from 'twenty-shared/utils'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; const StyledMessageBubble = styled.div<{ isUser?: boolean }>` @@ -141,7 +141,7 @@ export const AIChatMessage = ({ isLastMessageStreaming: boolean; error?: Error | null; }) => { - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const isUser = message.role === AgentMessageRole.USER; const showError = diff --git a/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx b/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx index fdeacc62bc..297a15b05a 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx @@ -1,6 +1,6 @@ import { agentChatUsageStateV2 } from '@/ai/states/agentChatUsageStateV2'; import { currentAIChatThreadStateV2 } from '@/ai/states/currentAIChatThreadStateV2'; -import { currentAIChatThreadTitleStateV2 } from '@/ai/states/currentAIChatThreadTitleStateV2'; +import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState'; import { useOpenAskAIPageInCommandMenu } from '@/command-menu/hooks/useOpenAskAIPageInCommandMenu'; import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; @@ -83,7 +83,7 @@ export const AIChatThreadGroup = ({ currentAIChatThreadStateV2, ); const setCurrentAIChatThreadTitle = useSetRecoilStateV2( - currentAIChatThreadTitleStateV2, + currentAIChatThreadTitleState, ); const setAgentChatUsage = useSetRecoilStateV2(agentChatUsageStateV2); const { openAskAIPage } = useOpenAskAIPageInCommandMenu(); diff --git a/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts b/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts index 39e5f9c8e4..a5d24a2a2b 100644 --- a/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts +++ b/packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts @@ -3,7 +3,7 @@ import { agentChatSelectedFilesStateV2 } from '@/ai/states/agentChatSelectedFile import { agentChatUploadedFilesStateV2 } from '@/ai/states/agentChatUploadedFilesStateV2'; import { agentChatUsageStateV2 } from '@/ai/states/agentChatUsageStateV2'; import { currentAIChatThreadStateV2 } from '@/ai/states/currentAIChatThreadStateV2'; -import { currentAIChatThreadTitleStateV2 } from '@/ai/states/currentAIChatThreadTitleStateV2'; +import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState'; import { agentChatInputStateV2 } from '@/ai/states/agentChatInputStateV2'; import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; @@ -26,7 +26,7 @@ export const useAgentChat = (uiMessages: ExtendedUIMessage[]) => { const { getBrowsingContext } = useGetBrowsingContext(); const setCurrentAIChatThreadTitle = useSetRecoilStateV2( - currentAIChatThreadTitleStateV2, + currentAIChatThreadTitleState, ); const agentChatSelectedFiles = useRecoilValueV2( diff --git a/packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts b/packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts index 1d4e9b3174..71fab08ce6 100644 --- a/packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts +++ b/packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts @@ -4,7 +4,7 @@ import { type AgentChatUsageState, } from '@/ai/states/agentChatUsageStateV2'; import { currentAIChatThreadStateV2 } from '@/ai/states/currentAIChatThreadStateV2'; -import { currentAIChatThreadTitleStateV2 } from '@/ai/states/currentAIChatThreadTitleStateV2'; +import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState'; import { isCreatingChatThreadStateV2 } from '@/ai/states/isCreatingChatThreadStateV2'; import { mapDBMessagesToUIMessages } from '@/ai/utils/mapDBMessagesToUIMessages'; import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; @@ -46,7 +46,7 @@ export const useAgentChatData = () => { ); const setAgentChatUsage = useSetRecoilStateV2(agentChatUsageStateV2); const setCurrentAIChatThreadTitle = useSetRecoilStateV2( - currentAIChatThreadTitleStateV2, + currentAIChatThreadTitleState, ); const [isCreatingChatThread, setIsCreatingChatThread] = useRecoilStateV2( isCreatingChatThreadStateV2, diff --git a/packages/twenty-front/src/modules/ai/hooks/useBrowsingContext.ts b/packages/twenty-front/src/modules/ai/hooks/useBrowsingContext.ts index aaf8d77a29..bf6d08a6c7 100644 --- a/packages/twenty-front/src/modules/ai/hooks/useBrowsingContext.ts +++ b/packages/twenty-front/src/modules/ai/hooks/useBrowsingContext.ts @@ -1,5 +1,5 @@ import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type BrowsingContext } from '@/ai/types/BrowsingContext'; @@ -11,7 +11,7 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useStore } from 'jotai'; @@ -20,139 +20,129 @@ import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreV export const useGetBrowsingContext = () => { const store = useStore(); - const getBrowsingContext = useRecoilCallback( - ({ snapshot }) => - (): BrowsingContext | null => { - const instanceId = MAIN_CONTEXT_STORE_INSTANCE_ID; + const getBrowsingContext = useCallback((): BrowsingContext | null => { + const instanceId = MAIN_CONTEXT_STORE_INSTANCE_ID; - const viewType = snapshot - .getLoadable( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId, - }), - ) - .getValue(); + const viewType = store.get( + contextStoreCurrentViewTypeComponentState.atomFamily({ + instanceId, + }), + ); - const objectMetadataItemId = snapshot - .getLoadable( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId, - }), - ) - .getValue(); + const objectMetadataItemId = store.get( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId, + }), + ); - const objectMetadataItems = store.get(objectMetadataItemsState.atom); + const objectMetadataItems = store.get(objectMetadataItemsState.atom); - const objectMetadataItem = objectMetadataItems.find( - (item) => item.id === objectMetadataItemId, + const objectMetadataItem = objectMetadataItems.find( + (item) => item.id === objectMetadataItemId, + ); + + if (!objectMetadataItem) { + return null; + } + + if (viewType === ContextStoreViewType.ShowPage) { + const targetedRecordsRule = store.get( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId, + }), + ); + + if ( + targetedRecordsRule.mode !== 'selection' || + targetedRecordsRule.selectedRecordIds.length !== 1 + ) { + return null; + } + + const recordContext: BrowsingContext = { + type: 'recordPage', + objectNameSingular: objectMetadataItem.nameSingular, + recordId: targetedRecordsRule.selectedRecordIds[0], + }; + + const pageLayoutId = store.get( + recordStoreFamilySelectorV2.selectorFamily({ + recordId: targetedRecordsRule.selectedRecordIds[0], + fieldName: 'pageLayoutId', + }), + ) as string | null | undefined; + + if (isDefined(pageLayoutId)) { + const tabListInstanceId = + getTabListInstanceIdFromPageLayoutId(pageLayoutId); + const activeTabId = store.get( + activeTabIdComponentState.atomFamily({ + instanceId: tabListInstanceId, + }), ); - if (!objectMetadataItem) { - return null; - } + return { + ...recordContext, + pageLayoutId, + activeTabId, + }; + } - if (viewType === ContextStoreViewType.ShowPage) { - const targetedRecordsRule = snapshot - .getLoadable( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId, - }), - ) - .getValue(); + return recordContext; + } - if ( - targetedRecordsRule.mode !== 'selection' || - targetedRecordsRule.selectedRecordIds.length !== 1 - ) { - return null; - } + if ( + viewType === ContextStoreViewType.Table || + viewType === ContextStoreViewType.Kanban + ) { + const currentViewId = store.get( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId, + }), + ); - const recordContext: BrowsingContext = { - type: 'recordPage', - objectNameSingular: objectMetadataItem.nameSingular, - recordId: targetedRecordsRule.selectedRecordIds[0], - }; - - const pageLayoutId = snapshot - .getLoadable( - recordStoreFamilySelector({ - recordId: targetedRecordsRule.selectedRecordIds[0], - fieldName: 'pageLayoutId', - }), - ) - .getValue(); - - if (isDefined(pageLayoutId)) { - const tabListInstanceId = - getTabListInstanceIdFromPageLayoutId(pageLayoutId); - const activeTabId = store.get( - activeTabIdComponentState.atomFamily({ - instanceId: tabListInstanceId, - }), - ); - - return { - ...recordContext, - pageLayoutId, - activeTabId, - }; - } - - return recordContext; - } - - if ( - viewType === ContextStoreViewType.Table || - viewType === ContextStoreViewType.Kanban - ) { - const currentViewId = snapshot - .getLoadable( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId, - }), - ) - .getValue(); - - const currentView = store.get( - coreViewFromViewIdFamilySelector.selectorFamily({ - viewId: currentViewId ?? '', - }), - ); - - if (!currentView) { - return null; - } - - const contextStoreFilters = snapshot - .getLoadable( - contextStoreFiltersComponentState.atomFamily({ - instanceId, - }), - ) - .getValue(); - - const filterDescriptions = contextStoreFilters.map((filter) => { - const fieldMetadataItem = objectMetadataItem.fields.find( - (field) => field.id === filter.fieldMetadataId, - ); - const fieldLabel = fieldMetadataItem?.label ?? t`Unknown field`; - - return `${fieldLabel} ${filter.operand} "${filter.displayValue}"`; - }); - - return { - type: 'listView', - objectNameSingular: objectMetadataItem.nameSingular, - viewId: currentView.id, - viewName: currentView.name, - filterDescriptions, - }; - } + const currentView = store.get( + coreViewFromViewIdFamilySelector.selectorFamily({ + viewId: currentViewId ?? '', + }), + ); + if (!currentView) { return null; - }, - [store], - ); + } + + const contextStoreFilters = store.get( + contextStoreFiltersComponentState.atomFamily({ + instanceId, + }), + ); + + const filterDescriptions = contextStoreFilters.map( + (filter: { + fieldMetadataId: string; + operand: string; + displayValue: string; + }) => { + const fieldMetadataItem = objectMetadataItem.fields.find( + (field) => field.id === filter.fieldMetadataId, + ); + const fieldLabel = fieldMetadataItem?.label ?? t`Unknown field`; + + return `${fieldLabel} ${filter.operand} "${filter.displayValue}"`; + }, + ); + + return { + type: 'listView', + objectNameSingular: objectMetadataItem.nameSingular, + viewId: currentView.id, + viewName: currentView.name, + filterDescriptions, + }; + } + + return null; + }, [store]); return { getBrowsingContext }; }; diff --git a/packages/twenty-front/src/modules/ai/hooks/useCreateNewAIChatThread.ts b/packages/twenty-front/src/modules/ai/hooks/useCreateNewAIChatThread.ts index 4d6dc7c918..bb4a72aa2b 100644 --- a/packages/twenty-front/src/modules/ai/hooks/useCreateNewAIChatThread.ts +++ b/packages/twenty-front/src/modules/ai/hooks/useCreateNewAIChatThread.ts @@ -1,6 +1,6 @@ import { agentChatUsageStateV2 } from '@/ai/states/agentChatUsageStateV2'; import { currentAIChatThreadStateV2 } from '@/ai/states/currentAIChatThreadStateV2'; -import { currentAIChatThreadTitleStateV2 } from '@/ai/states/currentAIChatThreadTitleStateV2'; +import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState'; import { useOpenAskAIPageInCommandMenu } from '@/command-menu/hooks/useOpenAskAIPageInCommandMenu'; import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; @@ -12,7 +12,7 @@ export const useCreateNewAIChatThread = () => { ); const setAgentChatUsage = useSetRecoilStateV2(agentChatUsageStateV2); const setCurrentAIChatThreadTitle = useSetRecoilStateV2( - currentAIChatThreadTitleStateV2, + currentAIChatThreadTitleState, ); const { openAskAIPage } = useOpenAskAIPageInCommandMenu(); diff --git a/packages/twenty-front/src/modules/ai/states/agentChatMessagesComponentState.ts b/packages/twenty-front/src/modules/ai/states/agentChatMessagesComponentState.ts index a0111cca9d..d87e69405f 100644 --- a/packages/twenty-front/src/modules/ai/states/agentChatMessagesComponentState.ts +++ b/packages/twenty-front/src/modules/ai/states/agentChatMessagesComponentState.ts @@ -1,11 +1,11 @@ import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type AgentMessage } from '~/generated-metadata/graphql'; export const AgentChatMessagesComponentInstanceContext = createComponentInstanceContext(); -export const agentChatMessagesComponentState = createComponentState< +export const agentChatMessagesComponentState = createComponentStateV2< AgentMessage[] >({ key: 'agentChatMessagesComponentState', diff --git a/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleState.ts b/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleState.ts index af58c57ed1..d11788ffd5 100644 --- a/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleState.ts +++ b/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleState.ts @@ -1,6 +1,6 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const currentAIChatThreadTitleState = atom({ +export const currentAIChatThreadTitleState = createStateV2({ key: 'ai/currentAIChatThreadTitleState', - default: null, + defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleStateV2.ts b/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleStateV2.ts deleted file mode 100644 index 737745fefb..0000000000 --- a/packages/twenty-front/src/modules/ai/states/currentAIChatThreadTitleStateV2.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; - -export const currentAIChatThreadTitleStateV2 = createStateV2({ - key: 'ai/currentAIChatThreadTitleStateV2', - defaultValue: null, -}); diff --git a/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx b/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx index 45f3c2521d..459ef643b4 100644 --- a/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx +++ b/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx @@ -7,14 +7,13 @@ import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirec import { useRequestFreshCaptchaToken } from '@/captcha/hooks/useRequestFreshCaptchaToken'; import { isCaptchaScriptLoadedState } from '@/captcha/states/isCaptchaScriptLoadedState'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { matchPath, useLocation, useNavigate, useParams, } from 'react-router-dom'; -import { useRecoilCallback } from 'recoil'; import { isCaptchaRequiredForPath } from '@/captcha/utils/isCaptchaRequiredForPath'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; @@ -35,7 +34,8 @@ import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/u import { PageFocusId } from '@/types/PageFocusId'; import { useResetFocusStackToFocusItem } from '@/ui/utilities/focus/hooks/useResetFocusStackToFocusItem'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { AppBasePath, AppPath, CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { AnalyticsType } from '~/generated-metadata/graphql'; @@ -65,12 +65,12 @@ export const PageChangeEffect = () => { const objectNamePlural = useParams().objectNamePlural ?? CoreObjectNamePlural.Person; - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const contextStoreCurrentViewType = useRecoilComponentValue( + const contextStoreCurrentViewType = useRecoilComponentValueV2( contextStoreCurrentViewTypeComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); @@ -98,19 +98,13 @@ export const PageChangeEffect = () => { const { closeCommandMenu } = useCommandMenu(); - const closeCommandMenuUnlessOnEditPage = useRecoilCallback( - ({ snapshot }) => - () => { - const currentPage = snapshot - .getLoadable(commandMenuPageState) - .getValue(); - if (currentPage === CommandMenuPages.NavigationMenuItemEdit) { - return; - } - closeCommandMenu(); - }, - [closeCommandMenu], - ); + const closeCommandMenuUnlessOnEditPage = useCallback(() => { + const currentPage = jotaiStore.get(commandMenuPageState.atom); + if (currentPage === CommandMenuPages.NavigationMenuItemEdit) { + return; + } + closeCommandMenu(); + }, [closeCommandMenu]); const { resetFocusStackToFocusItem } = useResetFocusStackToFocusItem(); diff --git a/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts b/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts index 07b2440f84..a7c5b36bbe 100644 --- a/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts +++ b/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts @@ -1,8 +1,7 @@ -import { useRecoilCallback } from 'recoil'; - import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { currentPageLayoutIdState } from '@/page-layout/states/currentPageLayoutIdState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { hasInitializedFieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState'; import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; @@ -11,84 +10,76 @@ import { pageLayoutIsInitializedComponentState } from '@/page-layout/states/page import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts'; import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useExecuteTasksOnAnyLocationChange = () => { const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown(); - const resetPageLayoutEditMode = useRecoilCallback( - ({ set, snapshot }) => - () => { - const pageLayoutId = snapshot - .getLoadable(currentPageLayoutIdState) - .getValue(); + const resetPageLayoutEditMode = useCallback(() => { + const pageLayoutId = jotaiStore.get(currentPageLayoutIdState.atom); - if (isDefined(pageLayoutId)) { - const pageLayoutPersisted = snapshot - .getLoadable( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: pageLayoutId, - }), - ) - .getValue(); + if (isDefined(pageLayoutId)) { + const pageLayoutPersisted = jotaiStore.get( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: pageLayoutId, + }), + ); - if (isDefined(pageLayoutPersisted)) { - set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: pageLayoutId, - }), - { - id: pageLayoutPersisted.id, - name: pageLayoutPersisted.name, - type: pageLayoutPersisted.type, - objectMetadataId: pageLayoutPersisted.objectMetadataId, - tabs: pageLayoutPersisted.tabs, - }, - ); - - const tabLayouts = - convertPageLayoutToTabLayouts(pageLayoutPersisted); - set( - pageLayoutCurrentLayoutsComponentState.atomFamily({ - instanceId: pageLayoutId, - }), - tabLayouts, - ); - } - - set( - isPageLayoutInEditModeComponentState.atomFamily({ - instanceId: pageLayoutId, - }), - false, - ); - - set( - pageLayoutIsInitializedComponentState.atomFamily({ - instanceId: pageLayoutId, - }), - false, - ); - - set( - hasInitializedFieldsWidgetGroupsDraftComponentState.atomFamily({ - instanceId: pageLayoutId, - }), - {}, - ); - - set(currentPageLayoutIdState, null); - } - - set( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + if (isDefined(pageLayoutPersisted)) { + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: pageLayoutId, }), - false, + { + id: pageLayoutPersisted.id, + name: pageLayoutPersisted.name, + type: pageLayoutPersisted.type, + objectMetadataId: pageLayoutPersisted.objectMetadataId, + tabs: pageLayoutPersisted.tabs, + }, ); - }, - [], - ); + + const tabLayouts = convertPageLayoutToTabLayouts(pageLayoutPersisted); + jotaiStore.set( + pageLayoutCurrentLayoutsComponentState.atomFamily({ + instanceId: pageLayoutId, + }), + tabLayouts, + ); + } + + jotaiStore.set( + isPageLayoutInEditModeComponentState.atomFamily({ + instanceId: pageLayoutId, + }), + false, + ); + + jotaiStore.set( + pageLayoutIsInitializedComponentState.atomFamily({ + instanceId: pageLayoutId, + }), + false, + ); + + jotaiStore.set( + hasInitializedFieldsWidgetGroupsDraftComponentState.atomFamily({ + instanceId: pageLayoutId, + }), + {}, + ); + + jotaiStore.set(currentPageLayoutIdState.atom, null); + } + + jotaiStore.set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + false, + ); + }, []); /** * Be careful to put idempotent tasks here. diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index 2ac3132fdb..d7760142bb 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -1,10 +1,6 @@ import { ApolloError, useApolloClient } from '@apollo/client'; import { useCallback } from 'react'; -import { - snapshot_UNSTABLE, - useGotoRecoilSnapshot, - useRecoilCallback, -} from 'recoil'; +import { snapshot_UNSTABLE, useGotoRecoilSnapshot } from 'recoil'; import { AppPath } from 'twenty-shared/types'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; @@ -59,7 +55,6 @@ import { useRedirect } from '@/domain-manager/hooks/useRedirect'; import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain'; import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState'; import { sseClientState } from '@/sse-db-event/states/sseClientState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser'; import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState'; import { i18n } from '@lingui/core'; @@ -123,81 +118,69 @@ export const useAuth = () => { const navigate = useNavigate(); - const clearSession = useRecoilCallback( - ({ snapshot }) => - async () => { - const sseClient = getSnapshotValue(snapshot, sseClientState); + const clearSession = useCallback(async () => { + const sseClient = jotaiStore.get(sseClientState.atom); - sseClient?.dispose(); + sseClient?.dispose(); - const emptySnapshot = snapshot_UNSTABLE(); + const emptySnapshot = snapshot_UNSTABLE(); - const authProvidersValue = jotaiStore.get( - workspaceAuthProvidersState.atom, - ); - const domainConfigurationValue = jotaiStore.get( - domainConfigurationState.atom, - ); - const workspacePublicDataValue = jotaiStore.get( - workspacePublicDataState.atom, - ); - const lastAuthenticatedMethod = jotaiStore.get( - lastAuthenticatedMethodState.atom, - ); - const isCaptchaScriptLoadedValue = jotaiStore.get( - isCaptchaScriptLoadedState.atom, - ); + const authProvidersValue = jotaiStore.get(workspaceAuthProvidersState.atom); + const domainConfigurationValue = jotaiStore.get( + domainConfigurationState.atom, + ); + const workspacePublicDataValue = jotaiStore.get( + workspacePublicDataState.atom, + ); + const lastAuthenticatedMethod = jotaiStore.get( + lastAuthenticatedMethodState.atom, + ); + const isCaptchaScriptLoadedValue = jotaiStore.get( + isCaptchaScriptLoadedState.atom, + ); - const initialSnapshot = emptySnapshot.map(() => { - return undefined; - }); + const initialSnapshot = emptySnapshot.map(() => { + return undefined; + }); - sessionStorage.clear(); - localStorage.clear(); + sessionStorage.clear(); + localStorage.clear(); - goToRecoilSnapshot(initialSnapshot); + goToRecoilSnapshot(initialSnapshot); - jotaiStore.set(workspaceAuthProvidersState.atom, authProvidersValue); - jotaiStore.set(workspacePublicDataState.atom, workspacePublicDataValue); - jotaiStore.set(domainConfigurationState.atom, domainConfigurationValue); - jotaiStore.set( - isCaptchaScriptLoadedState.atom, - isCaptchaScriptLoadedValue, - ); - jotaiStore.set( - lastAuthenticatedMethodState.atom, - lastAuthenticatedMethod, - ); + jotaiStore.set(workspaceAuthProvidersState.atom, authProvidersValue); + jotaiStore.set(workspacePublicDataState.atom, workspacePublicDataValue); + jotaiStore.set(domainConfigurationState.atom, domainConfigurationValue); + jotaiStore.set(isCaptchaScriptLoadedState.atom, isCaptchaScriptLoadedValue); + jotaiStore.set(lastAuthenticatedMethodState.atom, lastAuthenticatedMethod); - // Reset user-data Jotai states that were migrated from Recoil - // (Recoil snapshot reset no longer handles these since they are Jotai V2) - jotaiStore.set(tokenPairState.atom, null); - jotaiStore.set(currentUserState.atom, null); - jotaiStore.set(currentWorkspaceState.atom, null); - jotaiStore.set(currentUserWorkspaceState.atom, null); - jotaiStore.set(currentWorkspaceMemberState.atom, null); - jotaiStore.set(currentWorkspaceMembersState.atom, []); - jotaiStore.set(availableWorkspacesState.atom, { - availableWorkspacesForSignIn: [], - availableWorkspacesForSignUp: [], - }); - jotaiStore.set(loginTokenState.atom, null); - jotaiStore.set(signInUpStepState.atom, SignInUpStep.Init); - jotaiStore.set(coreViewsState.atom, []); + // Reset user-data Jotai states that were migrated from Recoil + // (Recoil snapshot reset no longer handles these since they are Jotai V2) + jotaiStore.set(tokenPairState.atom, null); + jotaiStore.set(currentUserState.atom, null); + jotaiStore.set(currentWorkspaceState.atom, null); + jotaiStore.set(currentUserWorkspaceState.atom, null); + jotaiStore.set(currentWorkspaceMemberState.atom, null); + jotaiStore.set(currentWorkspaceMembersState.atom, []); + jotaiStore.set(availableWorkspacesState.atom, { + availableWorkspacesForSignIn: [], + availableWorkspacesForSignUp: [], + }); + jotaiStore.set(loginTokenState.atom, null); + jotaiStore.set(signInUpStepState.atom, SignInUpStep.Init); + jotaiStore.set(coreViewsState.atom, []); - await client.clearStore(); - setLastAuthenticateWorkspaceDomain(null); - await resetToMockedMetadata(); - navigate(AppPath.SignInUp); - }, - [ - goToRecoilSnapshot, - client, - setLastAuthenticateWorkspaceDomain, - resetToMockedMetadata, - navigate, - ], - ); + await client.clearStore(); + setLastAuthenticateWorkspaceDomain(null); + await resetToMockedMetadata(); + navigate(AppPath.SignInUp); + }, [ + goToRecoilSnapshot, + client, + setLastAuthenticateWorkspaceDomain, + resetToMockedMetadata, + navigate, + ]); const handleSetAuthTokens = useCallback( (tokens: AuthTokenPair) => { diff --git a/packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx b/packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx index 78b38fb397..9d59c91e10 100644 --- a/packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx +++ b/packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx @@ -2,8 +2,9 @@ import { type BLOCK_SCHEMA } from '@/blocknote-editor/blocks/Schema'; import { isSlashMenuOpenComponentState } from '@/blocknote-editor/states/isSlashMenuOpenComponentState'; import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export type BlockEditorDropdownFocusEffectProps = { editor: typeof BLOCK_SCHEMA.BlockNoteEditor; @@ -12,7 +13,7 @@ export type BlockEditorDropdownFocusEffectProps = { export const BlockEditorDropdownFocusEffect = ({ editor, }: BlockEditorDropdownFocusEffectProps) => { - const isSlashMenuOpenState = useRecoilComponentCallbackState( + const isSlashMenuOpenState = useRecoilComponentStateCallbackStateV2( isSlashMenuOpenComponentState, ); @@ -22,41 +23,39 @@ export const BlockEditorDropdownFocusEffect = ({ const { goBackToPreviousDropdownFocusId } = useGoBackToPreviousDropdownFocusId(); - const updateCallBack = useRecoilCallback( - ({ snapshot, set }) => - (event: any) => { - // TODO: This triggers before the onClick event of the slash menu item, so the click outside of the editor dropdown is triggered and everything closes. - // This is due to useRecoilCallback being executed before the onClick event of the slash menu item. - const eventWantsToOpen = event.show === true; + const store = useStore(); - const isAlreadyOpen = snapshot - .getLoadable(isSlashMenuOpenState) - .getValue(); + const updateCallBack = useCallback( + (event: any) => { + const eventWantsToOpen = event.show === true; - const shouldOpen = eventWantsToOpen && !isAlreadyOpen; + const isAlreadyOpen = store.get(isSlashMenuOpenState); - if (shouldOpen) { - setActiveDropdownFocusIdAndMemorizePrevious('custom-slash-menu'); - set(isSlashMenuOpenState, true); - return; - } + const shouldOpen = eventWantsToOpen && !isAlreadyOpen; - const eventWantsToClose = event.show === false; + if (shouldOpen) { + setActiveDropdownFocusIdAndMemorizePrevious('custom-slash-menu'); + store.set(isSlashMenuOpenState, true); + return; + } - const isAlreadyClosed = !isAlreadyOpen; + const eventWantsToClose = event.show === false; - const shouldClose = eventWantsToClose && !isAlreadyClosed; + const isAlreadyClosed = !isAlreadyOpen; - if (shouldClose) { - goBackToPreviousDropdownFocusId(); - set(isSlashMenuOpenState, false); - return; - } - }, + const shouldClose = eventWantsToClose && !isAlreadyClosed; + + if (shouldClose) { + goBackToPreviousDropdownFocusId(); + store.set(isSlashMenuOpenState, false); + return; + } + }, [ isSlashMenuOpenState, setActiveDropdownFocusIdAndMemorizePrevious, goBackToPreviousDropdownFocusId, + store, ], ); diff --git a/packages/twenty-front/src/modules/blocknote-editor/states/isSlashMenuOpenComponentState.ts b/packages/twenty-front/src/modules/blocknote-editor/states/isSlashMenuOpenComponentState.ts index edaf11375e..28f6d3a217 100644 --- a/packages/twenty-front/src/modules/blocknote-editor/states/isSlashMenuOpenComponentState.ts +++ b/packages/twenty-front/src/modules/blocknote-editor/states/isSlashMenuOpenComponentState.ts @@ -1,7 +1,7 @@ import { BlockEditorComponentInstanceContext } from '@/blocknote-editor/contexts/BlockEditorCompoponeInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const isSlashMenuOpenComponentState = createComponentState({ +export const isSlashMenuOpenComponentState = createComponentStateV2({ key: 'isSlashMenuOpenComponentState', defaultValue: false, componentInstanceContext: BlockEditorComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentActions.tsx b/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentActions.tsx index 225819440e..4e5f529b63 100644 --- a/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentActions.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/hooks/useCommandMenuItemFrontComponentActions.tsx @@ -8,7 +8,7 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useMountHeadlessFrontComponent } from '@/front-components/hooks/useMountHeadlessFrontComponent'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -94,17 +94,17 @@ export const useCommandMenuItemFrontComponentActions = () => { useOpenFrontComponentInCommandMenu(); const mountHeadlessFrontComponent = useMountHeadlessFrontComponent(); - const isPageInEditMode = useRecoilComponentValue( + const isPageInEditMode = useRecoilComponentValueV2( contextStoreIsPageInEditModeComponentState, ); const { actionMenuType } = useContext(ActionMenuContext); - const currentObjectMetadataItemId = useRecoilComponentValue( + const currentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, ); - const targetedRecordsRule = useRecoilComponentValue( + const targetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx index 53fd2266c5..65be0254b8 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx @@ -7,9 +7,9 @@ import { useMatchingCommandMenuActions } from '@/command-menu/hooks/useMatchingC import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export type ActionGroupConfig = { @@ -20,7 +20,7 @@ export type ActionGroupConfig = { export const CommandMenu = () => { const { t } = useLingui(); - const commandMenuSearch = useRecoilValue(commandMenuSearchState); + const commandMenuSearch = useRecoilValueV2(commandMenuSearchState); const { objectMetadataItems } = useObjectMetadataItems(); const { @@ -40,12 +40,12 @@ export const CommandMenu = () => { }); const previousContextStoreCurrentObjectMetadataItemId = - useRecoilComponentValue( + useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, 'command-menu-previous', ); - const objectMetadataItemId = useRecoilComponentValue( + const objectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, ); const currentObjectMetadataItem = objectMetadataItems.find( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx index 41c04bdf9c..5894f39305 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx @@ -1,4 +1,4 @@ -import { currentAIChatThreadTitleStateV2 } from '@/ai/states/currentAIChatThreadTitleStateV2'; +import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -12,7 +12,7 @@ const StyledPageTitle = styled.div` export const CommandMenuAskAIInfo = () => { const currentAIChatThreadTitle = useRecoilValueV2( - currentAIChatThreadTitleStateV2, + currentAIChatThreadTitleState, ); return ( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx index 2b8520d197..084b1e4cd6 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx @@ -8,7 +8,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; const StyledCommandMenuContainer = styled.div<{ isMobile: boolean }>` @@ -29,7 +29,7 @@ type CommandMenuContainerProps = { export const CommandMenuContainer = ({ children, }: CommandMenuContainerProps) => { - const objectMetadataItemId = useRecoilComponentValue( + const objectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, COMMAND_MENU_COMPONENT_INSTANCE_ID, ); @@ -41,7 +41,7 @@ export const CommandMenuContainer = ({ (objectMetadataItem) => objectMetadataItem.id === objectMetadataItemId, ); - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, COMMAND_MENU_COMPONENT_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuDefaultSelectionEffect.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuDefaultSelectionEffect.tsx index c62755077d..39f4b48186 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuDefaultSelectionEffect.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuDefaultSelectionEffect.tsx @@ -3,8 +3,8 @@ import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelect import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const CommandMenuDefaultSelectionEffect = ({ @@ -21,7 +21,7 @@ export const CommandMenuDefaultSelectionEffect = ({ COMMAND_MENU_LIST_SELECTABLE_LIST_ID, ); - const hasUserSelectedCommand = useRecoilValue(hasUserSelectedCommandState); + const hasUserSelectedCommand = useRecoilValueV2(hasUserSelectedCommandState); useEffect(() => { if ( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuFolderInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuFolderInfo.tsx index 0c74b8e275..323760b4fc 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuFolderInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuFolderInfo.tsx @@ -1,7 +1,6 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { useIcons } from 'twenty-ui/display'; import { CommandMenuPageInfoLayout } from '@/command-menu/components/CommandMenuPageInfoLayout'; @@ -17,7 +16,7 @@ import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValu import { getNavigationMenuItemIconColors } from '@/navigation-menu-item/utils/getNavigationMenuItemIconColors'; import { IconPicker } from '@/ui/input/components/IconPicker'; import { TitleInput } from '@/ui/input/components/TitleInput'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; const StyledClickableIconWrapper = styled.div` cursor: pointer; @@ -27,9 +26,9 @@ export const CommandMenuFolderInfo = () => { const theme = useTheme(); const { t } = useLingui(); const { getIcon } = useIcons(); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); + const commandMenuPageInfo = useRecoilValueV2(commandMenuPageInfoState); const [shouldFocusTitleInput, setShouldFocusTitleInput] = - useRecoilComponentState( + useRecoilComponentStateV2( commandMenuShouldFocusTitleInputComponentState, commandMenuPageInfo.instanceId, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuLinkInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuLinkInfo.tsx index 142d984f8b..4c2d6d32fc 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuLinkInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuLinkInfo.tsx @@ -1,6 +1,5 @@ import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { IconLink } from 'twenty-ui/display'; import { CommandMenuPageInfoLayout } from '@/command-menu/components/CommandMenuPageInfoLayout'; @@ -14,14 +13,14 @@ import { selectedNavigationMenuItemInEditModeStateV2 } from '@/navigation-menu-i import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { getNavigationMenuItemIconColors } from '@/navigation-menu-item/utils/getNavigationMenuItemIconColors'; import { TitleInput } from '@/ui/input/components/TitleInput'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; export const CommandMenuLinkInfo = () => { const theme = useTheme(); const { t } = useLingui(); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); + const commandMenuPageInfo = useRecoilValueV2(commandMenuPageInfoState); const [shouldFocusTitleInput, setShouldFocusTitleInput] = - useRecoilComponentState( + useRecoilComponentStateV2( commandMenuShouldFocusTitleInputComponentState, commandMenuPageInfo.instanceId, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx index b126bbf939..b5cbfde474 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx @@ -8,10 +8,10 @@ import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/Comman import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useSetRecoilState } from 'recoil'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; export type CommandMenuListProps = { @@ -63,7 +63,7 @@ export const CommandMenuList = ({ noResults = false, noResultsText, }: CommandMenuListProps) => { - const setHasUserSelectedCommand = useSetRecoilState( + const setHasUserSelectedCommand = useSetRecoilStateV2( hasUserSelectedCommandState, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfo.tsx index 27964aae7e..5aae47e50f 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfo.tsx @@ -3,11 +3,11 @@ import { CommandMenuRecordPageLayoutInfo } from '@/command-menu/components/Comma import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const CommandMenuPageLayoutInfo = () => { - const objectMetadataId = useRecoilComponentValue( + const objectMetadataId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx index ed38acedac..7ad3e73eca 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx @@ -9,12 +9,12 @@ import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDr import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; import { TitleInput } from '@/ui/input/components/TitleInput'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import { isNonEmptyString } from '@sniptt/guards'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -27,11 +27,11 @@ export const CommandMenuPageLayoutInfoContent = ({ }) => { const theme = useTheme(); const { getIcon } = useIcons(); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); + const commandMenuPageInfo = useRecoilValueV2(commandMenuPageInfoState); const [shouldFocusTitleInput, setShouldFocusTitleInput] = - useRecoilComponentState( + useRecoilComponentStateV2( commandMenuShouldFocusTitleInputComponentState, commandMenuPageInfo.instanceId, ); @@ -40,17 +40,17 @@ export const CommandMenuPageLayoutInfoContent = ({ setShouldFocusTitleInput(false); }; - const draftPageLayout = useRecoilComponentValue( + const draftPageLayout = useRecoilComponentValueV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutEditingWidgetId = useRecoilComponentValue( + const pageLayoutEditingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); - const [openTabId] = useRecoilComponentState( + const [openTabId] = useRecoilComponentStateV2( pageLayoutTabSettingsOpenTabIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuRecordInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuRecordInfo.tsx index 308227b6bc..0523302ff1 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuRecordInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuRecordInfo.tsx @@ -7,23 +7,22 @@ import { useIsRecordFieldReadOnly } from '@/object-record/read-only/hooks/useIsR import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions'; import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { recordStoreIdentifierFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreIdentifierFamilySelectorV2'; import { RecordTitleCell } from '@/object-record/record-title-cell/components/RecordTitleCell'; import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { Trans } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilValue } from 'recoil'; - +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { Avatar } from 'twenty-ui/display'; import { FeatureFlagKey, FieldMetadataType, } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; import { CommandMenuPageInfoLayout } from './CommandMenuPageInfoLayout'; @@ -32,7 +31,7 @@ export const CommandMenuRecordInfo = ({ }: { commandMenuPageInstanceId: string; }) => { - const viewableRecordNameSingular = useRecoilComponentValue( + const viewableRecordNameSingular = useRecoilComponentValueV2( viewableRecordNameSingularComponentState, commandMenuPageInstanceId, ); @@ -40,7 +39,7 @@ export const CommandMenuRecordInfo = ({ allowRequestsToTwentyIconsState, ); - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, commandMenuPageInstanceId, ); @@ -50,26 +49,25 @@ export const CommandMenuRecordInfo = ({ viewableRecordId!, ); - const recordCreatedAt = useRecoilValue( - recordStoreFamilySelector({ - recordId: objectRecordId, - fieldName: 'createdAt', - }), - ); + const recordCreatedAt = useFamilySelectorValueV2( + recordStoreFamilySelectorV2, + { recordId: objectRecordId, fieldName: 'createdAt' }, + ) as string | null; const isFilesFieldMigrated = useIsFeatureEnabled( FeatureFlagKey.IS_FILES_FIELD_MIGRATED, ); - const recordIdentifier = useRecoilValue( - recordStoreIdentifierFamilySelector({ + const recordIdentifier = useFamilySelectorValueV2( + recordStoreIdentifierFamilySelectorV2, + { recordId: objectRecordId, allowRequestsToTwentyIcons, isFilesFieldMigrated, - }), + }, ); - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const beautifiedCreatedAt = isNonEmptyString(recordCreatedAt) ? beautifyPastDateRelativeToNow(recordCreatedAt, localeCatalog) : ''; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx index 7a238216ad..f15841353d 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx @@ -5,10 +5,10 @@ import { COMMAND_MENU_PAGES_CONFIG } from '@/command-menu/constants/CommandMenuP import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; const StyledCommandMenuContent = styled.div` @@ -17,8 +17,8 @@ const StyledCommandMenuContent = styled.div` `; export const CommandMenuRouter = () => { - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); + const commandMenuPageInfo = useRecoilValueV2(commandMenuPageInfoState); const commandMenuPageComponent = isDefined(commandMenuPage) ? ( COMMAND_MENU_PAGES_CONFIG.get(commandMenuPage) diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx index 90ff212b5b..be2a127171 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx @@ -12,10 +12,11 @@ import { tableWidthResizeIsActiveState } from '@/object-record/record-table/stat import { ModalContainerContext } from '@/ui/layout/modal/contexts/ModalContainerContext'; import { ResizablePanelGap } from '@/ui/layout/resizable-panel/components/ResizablePanelGap'; import { COMMAND_MENU_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/CommandMenuConstraints'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import styled from '@emotion/styled'; import { useCallback, useState } from 'react'; -import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; const StyledSidePanelWrapper = styled.div<{ isOpen: boolean; @@ -56,8 +57,8 @@ const GAP_WIDTH = 8; export const CommandMenuSidePanelForDesktop = () => { const isCommandMenuOpened = useRecoilValueV2(isCommandMenuOpenedStateV2); - const isCommandMenuClosing = useRecoilValue(isCommandMenuClosingState); - const [commandMenuWidth, setCommandMenuWidth] = useRecoilState( + const isCommandMenuClosing = useRecoilValueV2(isCommandMenuClosingState); + const [commandMenuWidth, setCommandMenuWidth] = useRecoilStateV2( commandMenuWidthState, ); const { closeCommandMenu } = useCommandMenu(); @@ -71,7 +72,7 @@ export const CommandMenuSidePanelForDesktop = () => { const [shouldRenderContent, setShouldRenderContent] = useState(isCommandMenuOpened); - const setTableWidthResizeIsActive = useSetRecoilState( + const setTableWidthResizeIsActive = useSetRecoilStateV2( tableWidthResizeIsActiveState, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx index 5bb58a0978..c5553af263 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx @@ -18,8 +18,9 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { AnimatePresence, motion } from 'framer-motion'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useRef } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconX } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; @@ -79,7 +80,7 @@ const StyledContentContainer = styled.div` `; export const CommandMenuTopBar = () => { - const [commandMenuSearch, setCommandMenuSearch] = useRecoilState( + const [commandMenuSearch, setCommandMenuSearch] = useRecoilStateV2( commandMenuSearchState, ); const inputRef = useRef(null); @@ -94,9 +95,9 @@ export const CommandMenuTopBar = () => { const { closeCommandMenu } = useCommandMenu(); - const commandMenuPage = useRecoilValue(commandMenuPageState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); - const commandMenuNavigationStack = useRecoilValue( + const commandMenuNavigationStack = useRecoilValueV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarInputFocusEffect.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarInputFocusEffect.tsx index fec745d997..03ca4f7581 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarInputFocusEffect.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarInputFocusEffect.tsx @@ -1,6 +1,5 @@ -import { useRecoilValue } from 'recoil'; - import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useEffect } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; @@ -11,7 +10,7 @@ type CommandMenuTopBarInputFocusEffectProps = { export const CommandMenuTopBarInputFocusEffect = ({ inputRef, }: CommandMenuTopBarInputFocusEffectProps) => { - const commandMenuPage = useRecoilValue(commandMenuPageState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); useEffect(() => { if ( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx index 2968339909..39f636ba72 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx @@ -1,9 +1,9 @@ import { useOpenAskAIPageInCommandMenu } from '@/command-menu/hooks/useOpenAskAIPageInCommandMenu'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconEdit, IconSparkles } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; @@ -19,7 +19,7 @@ const StyledIconButton = styled(IconButton)` export const CommandMenuTopBarRightCornerIcon = () => { const isMobile = useIsMobile(); const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED); - const commandMenuPage = useRecoilValue(commandMenuPageState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); const { openAskAIPage } = useOpenAskAIPageInCommandMenu(); const { createChatThread } = useCreateNewAIChatThread(); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuWidthEffect.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuWidthEffect.tsx index 875b22bc61..3726df41c8 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuWidthEffect.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuWidthEffect.tsx @@ -1,13 +1,13 @@ import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { COMMAND_MENU_WIDTH_VAR, commandMenuWidthState, } from '@/command-menu/states/commandMenuWidthState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; export const CommandMenuWidthEffect = () => { - const commandMenuWidth = useRecoilValue(commandMenuWidthState); + const commandMenuWidth = useRecoilValueV2(commandMenuWidthState); useEffect(() => { document.documentElement.style.setProperty( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx index a0bb489b91..81ec0ec34a 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx @@ -5,7 +5,7 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { TitleInput } from '@/ui/input/components/TitleInput'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { getAgentIdFromStep } from '@/workflow/utils/getAgentIdFromStep'; @@ -19,8 +19,8 @@ import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor'; import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; @@ -35,11 +35,11 @@ export const CommandMenuWorkflowStepInfo = ({ const theme = useTheme(); const { getIcon } = useIcons(); - const commandMenuPage = useRecoilValue(commandMenuPageState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); const workflowId = useCommandMenuWorkflowIdOrThrow(); - const workflowStepId = useRecoilComponentValue( + const workflowStepId = useRecoilComponentValueV2( commandMenuWorkflowStepIdComponentState, commandMenuPageInstanceId, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx b/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx index 34b8d61b26..98530afe62 100644 --- a/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx @@ -7,19 +7,19 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { IconArrowBackUp } from 'twenty-ui/display'; export const ResetContextToSelectionCommandButton = () => { - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, 'command-menu-previous', ); - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, 'command-menu-previous', ); diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index 1274cccf22..8956c75eae 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -3,12 +3,11 @@ import { type Meta, type StoryObj, } from '@storybook/react-vite'; -import { useSetRecoilState } from 'recoil'; import { expect, userEvent, within } from 'storybook/test'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; -import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; @@ -28,13 +27,18 @@ import { CommandMenuRouter } from '@/command-menu/components/CommandMenuRouter'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; +import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; +import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { HttpResponse, graphql } from 'msw'; import { CommandMenuPages } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; import { IconDotsVertical } from 'twenty-ui/display'; import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter'; @@ -73,26 +77,17 @@ const meta: Meta = { component: CommandMenuRouter, decorators: [ (Story) => { - const setCurrentWorkspace = useSetRecoilStateV2(currentWorkspaceState); - const setCurrentUserWorkspace = useSetRecoilStateV2( - currentUserWorkspaceState, + jotaiStore.set(currentWorkspaceState.atom, mockCurrentWorkspace); + jotaiStore.set( + currentWorkspaceMemberState.atom, + mockedWorkspaceMemberData, ); - const setCurrentWorkspaceMember = useSetRecoilStateV2( - currentWorkspaceMemberState, + jotaiStore.set( + currentUserWorkspaceState.atom, + mockedUserData.currentUserWorkspace, ); - const setIsCommandMenuOpened = useSetRecoilState( - isCommandMenuOpenedState, - ); - const setCommandMenuNavigationStack = useSetRecoilState( - commandMenuNavigationStackState, - ); - - setCurrentWorkspace(mockCurrentWorkspace); - setCurrentWorkspaceMember(mockedWorkspaceMemberData); - setCurrentUserWorkspace(mockedUserData.currentUserWorkspace); - - setIsCommandMenuOpened(true); - setCommandMenuNavigationStack([ + jotaiStore.set(isCommandMenuOpenedStateV2.atom, true); + jotaiStore.set(commandMenuNavigationStackState.atom, [ { page: CommandMenuPages.Root, pageTitle: 'Command Menu', @@ -101,6 +96,25 @@ const meta: Meta = { }, ]); + const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); + const companyMetadataItem = objectMetadataItems.find( + (item) => item.nameSingular === 'company', + ); + if (isDefined(companyMetadataItem)) { + jotaiStore.set( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + companyMetadataItem.id, + ); + jotaiStore.set( + contextStoreCurrentViewTypeComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + ContextStoreViewType.Table, + ); + } + return ; }, ContextStoreDecorator, @@ -139,10 +153,8 @@ export const LimitedPermissions: Story = { }, decorators: [ (Story) => { - const setCurrentUserWorkspace = useSetRecoilStateV2( - currentUserWorkspaceState, - ); - setCurrentUserWorkspace( + jotaiStore.set( + currentUserWorkspaceState.atom, mockedLimitedPermissionsUserData.currentUserWorkspace, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextRecordChip.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextRecordChip.stories.tsx index 5c93d6ec85..4263432658 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextRecordChip.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextRecordChip.stories.tsx @@ -9,6 +9,7 @@ import { CommandMenuContextRecordsChip } from '@/command-menu/components/Command import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; import { type RecordChipData } from '@/object-record/record-field/ui/types/RecordChipData'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ComponentDecorator } from 'twenty-ui/testing'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; @@ -190,9 +191,12 @@ const createContextStoreWrapper = ({ selectedRecordIds: companies.map((company) => company.id), }, contextStoreNumberOfSelectedRecords: companies.length, - onInitializeRecoilSnapshot: (snapshot) => { + onInitializeJotaiStore: () => { for (const company of companies) { - snapshot.set(recordStoreFamilyState(company.id), company); + jotaiStore.set( + recordStoreFamilyState.atomFamily(company.id), + company as ObjectRecord, + ); } }, }); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx index 3aaa5e2ab8..95bfefcc99 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx @@ -1,13 +1,14 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; +import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconDotsVertical } from 'twenty-ui/display'; @@ -26,19 +27,9 @@ const renderHooks = () => { const { result } = renderHook( () => { const commandMenu = useCommandMenu(); - const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState); - const commandMenuNavigationStack = useRecoilValue( - commandMenuNavigationStackState, - ); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); return { commandMenu, - isCommandMenuOpened, - commandMenuNavigationStack, - commandMenuPage, - commandMenuPageInfo, }; }, { @@ -60,31 +51,31 @@ describe('useCommandMenu', () => { result.current.commandMenu.openCommandMenu(); }); - expect(result.current.isCommandMenuOpened).toBe(true); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(true); act(() => { result.current.commandMenu.closeCommandMenu(); }); - expect(result.current.isCommandMenuOpened).toBe(false); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(false); }); it('should toggle the command menu', () => { const { result } = renderHooks(); - expect(result.current.isCommandMenuOpened).toBe(false); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(false); act(() => { result.current.commandMenu.toggleCommandMenu(); }); - expect(result.current.isCommandMenuOpened).toBe(true); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(true); act(() => { result.current.commandMenu.toggleCommandMenu(); }); - expect(result.current.isCommandMenuOpened).toBe(false); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(false); }); it('should navigate command menu and reset navigation stack when resetNavigationStack is true', () => { @@ -99,9 +90,15 @@ describe('useCommandMenu', () => { }); }); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root); - expect(result.current.commandMenuPageInfo.title).toBe('First Page'); - expect(result.current.commandMenuNavigationStack).toHaveLength(1); + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.Root, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom).title).toBe( + 'First Page', + ); + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toHaveLength( + 1, + ); act(() => { result.current.commandMenu.navigateCommandMenu({ @@ -112,7 +109,9 @@ describe('useCommandMenu', () => { }); }); - expect(result.current.commandMenuNavigationStack).toHaveLength(2); + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toHaveLength( + 2, + ); act(() => { result.current.commandMenu.navigateCommandMenu({ @@ -123,8 +122,14 @@ describe('useCommandMenu', () => { }); }); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root); - expect(result.current.commandMenuPageInfo.title).toBe('Reset Page'); - expect(result.current.commandMenuNavigationStack).toHaveLength(1); + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.Root, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom).title).toBe( + 'Reset Page', + ); + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toHaveLength( + 1, + ); }); }); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx index cca8a59ea5..7cc86a6256 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx @@ -1,21 +1,23 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/constants/CommandMenuContextChipGroupsDropdownId'; import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId'; import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup'; -import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; +import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconList } from 'twenty-ui/display'; @@ -65,62 +67,13 @@ describe('useCommandMenuCloseAnimationCompleteCleanup', () => { const { commandMenuCloseAnimationCompleteCleanup } = useCommandMenuCloseAnimationCompleteCleanup(); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); - const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState); - const commandMenuSearch = useRecoilValue(commandMenuSearchState); - const commandMenuNavigationStack = useRecoilValue( - commandMenuNavigationStackState, - ); + const viewableRecordId = useRecoilValueV2(viewableRecordIdState); - const commandMenuNavigationMorphItemsByPage = useRecoilValue( - commandMenuNavigationMorphItemsByPageState, - ); - const hasUserSelectedCommand = useRecoilValue( - hasUserSelectedCommandState, - ); - const isCommandMenuClosing = useRecoilValue(isCommandMenuClosingState); - const viewableRecordId = useRecoilValue(viewableRecordIdState); - - // Get setters for state modification in tests - const setCommandMenuPage = useSetRecoilState(commandMenuPageState); - const setCommandMenuPageInfo = useSetRecoilState( - commandMenuPageInfoState, - ); - const setIsCommandMenuOpened = useSetRecoilState( - isCommandMenuOpenedState, - ); - const setCommandMenuSearch = useSetRecoilState(commandMenuSearchState); - const setCommandMenuNavigationStack = useSetRecoilState( - commandMenuNavigationStackState, - ); - - const setHasUserSelectedCommand = useSetRecoilState( - hasUserSelectedCommandState, - ); - const setIsCommandMenuClosing = useSetRecoilState( - isCommandMenuClosingState, - ); - const setViewableRecordId = useSetRecoilState(viewableRecordIdState); + const setViewableRecordId = useSetRecoilStateV2(viewableRecordIdState); return { commandMenuCloseAnimationCompleteCleanup, - commandMenuPage, - commandMenuPageInfo, - isCommandMenuOpened, - commandMenuSearch, - commandMenuNavigationStack, - commandMenuNavigationMorphItemsByPage, - hasUserSelectedCommand, - isCommandMenuClosing, viewableRecordId, - setCommandMenuPage, - setCommandMenuPageInfo, - setIsCommandMenuOpened, - setCommandMenuSearch, - setCommandMenuNavigationStack, - setHasUserSelectedCommand, - setIsCommandMenuClosing, setViewableRecordId, }; }, @@ -135,15 +88,15 @@ describe('useCommandMenuCloseAnimationCompleteCleanup', () => { const { result } = renderHooks(); act(() => { - result.current.setCommandMenuPage(CommandMenuPages.ViewRecord); - result.current.setCommandMenuPageInfo({ + jotaiStore.set(commandMenuPageState.atom, CommandMenuPages.ViewRecord); + jotaiStore.set(commandMenuPageInfoState.atom, { title: 'Test Record', Icon: IconList, instanceId: 'test-id', }); - result.current.setIsCommandMenuOpened(true); - result.current.setCommandMenuSearch('test search'); - result.current.setCommandMenuNavigationStack([ + jotaiStore.set(isCommandMenuOpenedStateV2.atom, true); + jotaiStore.set(commandMenuSearchState.atom, 'test search'); + jotaiStore.set(commandMenuNavigationStackState.atom, [ { page: CommandMenuPages.SearchRecords, pageTitle: 'Search', @@ -151,20 +104,22 @@ describe('useCommandMenuCloseAnimationCompleteCleanup', () => { pageId: '1', }, ]); - result.current.setHasUserSelectedCommand(true); - result.current.setIsCommandMenuClosing(true); + jotaiStore.set(hasUserSelectedCommandState.atom, true); + jotaiStore.set(isCommandMenuClosingState.atom, true); result.current.setViewableRecordId('record-123'); }); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.ViewRecord); - expect(result.current.commandMenuPageInfo).toEqual({ + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.ViewRecord, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom)).toEqual({ title: 'Test Record', Icon: IconList, instanceId: 'test-id', }); - expect(result.current.isCommandMenuOpened).toBe(true); - expect(result.current.commandMenuSearch).toBe('test search'); - expect(result.current.commandMenuNavigationStack).toEqual([ + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(true); + expect(jotaiStore.get(commandMenuSearchState.atom)).toBe('test search'); + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toEqual([ { page: CommandMenuPages.SearchRecords, pageTitle: 'Search', @@ -172,25 +127,27 @@ describe('useCommandMenuCloseAnimationCompleteCleanup', () => { pageId: '1', }, ]); - expect(result.current.hasUserSelectedCommand).toBe(true); - expect(result.current.isCommandMenuClosing).toBe(true); + expect(jotaiStore.get(hasUserSelectedCommandState.atom)).toBe(true); + expect(jotaiStore.get(isCommandMenuClosingState.atom)).toBe(true); expect(result.current.viewableRecordId).toBe('record-123'); act(() => { result.current.commandMenuCloseAnimationCompleteCleanup(); }); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root); - expect(result.current.commandMenuPageInfo).toEqual({ + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.Root, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom)).toEqual({ title: undefined, Icon: undefined, instanceId: '', }); - expect(result.current.isCommandMenuOpened).toBe(false); - expect(result.current.commandMenuSearch).toBe(''); - expect(result.current.commandMenuNavigationStack).toEqual([]); - expect(result.current.hasUserSelectedCommand).toBe(false); - expect(result.current.isCommandMenuClosing).toBe(false); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(false); + expect(jotaiStore.get(commandMenuSearchState.atom)).toBe(''); + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toEqual([]); + expect(jotaiStore.get(hasUserSelectedCommandState.atom)).toBe(false); + expect(jotaiStore.get(isCommandMenuClosingState.atom)).toBe(false); expect(result.current.viewableRecordId).toBe(null); }); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuHistory.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuHistory.test.tsx index 74d7dd5442..2b63f7a3e2 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuHistory.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuHistory.test.tsx @@ -1,7 +1,7 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup'; @@ -9,7 +9,8 @@ import { useCommandMenuHistory } from '@/command-menu/hooks/useCommandMenuHistor import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; +import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconList, IconSearch } from 'twenty-ui/display'; @@ -26,20 +27,10 @@ const renderHooks = () => { const commandMenuHistory = useCommandMenuHistory(); const commandMenuCloseAnimationCompleteCleanup = useCommandMenuCloseAnimationCompleteCleanup(); - const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState); - const commandMenuNavigationStack = useRecoilValue( - commandMenuNavigationStackState, - ); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); return { commandMenu, commandMenuHistory, - isCommandMenuOpened, - commandMenuNavigationStack, - commandMenuPage, - commandMenuPageInfo, commandMenuCloseAnimationCompleteCleanup, }; }, @@ -72,7 +63,7 @@ describe('useCommandMenuHistory', () => { }); }); - expect(result.current.commandMenuNavigationStack).toEqual([ + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toEqual([ { page: CommandMenuPages.SearchRecords, pageTitle: 'Search', @@ -91,7 +82,7 @@ describe('useCommandMenuHistory', () => { result.current.commandMenuHistory.goBackFromCommandMenu(); }); - expect(result.current.commandMenuNavigationStack).toEqual([ + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toEqual([ { page: CommandMenuPages.SearchRecords, pageTitle: 'Search', @@ -99,8 +90,10 @@ describe('useCommandMenuHistory', () => { pageId: '1', }, ]); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords); - expect(result.current.commandMenuPageInfo).toEqual({ + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.SearchRecords, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom)).toEqual({ title: 'Search', Icon: IconSearch, instanceId: '1', @@ -111,14 +104,16 @@ describe('useCommandMenuHistory', () => { result.current.commandMenuCloseAnimationCompleteCleanup.commandMenuCloseAnimationCompleteCleanup(); }); - expect(result.current.commandMenuNavigationStack).toEqual([]); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root); - expect(result.current.commandMenuPageInfo).toEqual({ + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toEqual([]); + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.Root, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom)).toEqual({ title: undefined, instanceId: '', Icon: undefined, }); - expect(result.current.isCommandMenuOpened).toBe(false); + expect(jotaiStore.get(isCommandMenuOpenedStateV2.atom)).toBe(false); }); it('should navigate to a page in history', () => { @@ -137,8 +132,10 @@ describe('useCommandMenuHistory', () => { result.current.commandMenuHistory.navigateCommandMenuHistory(0); }); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords); - expect(result.current.commandMenuPageInfo).toEqual({ + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.SearchRecords, + ); + expect(jotaiStore.get(commandMenuPageInfoState.atom)).toEqual({ title: 'Search', Icon: IconSearch, instanceId: '1', diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuOnItemClick.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuOnItemClick.test.tsx index 53a30aed6f..801e2f1c43 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuOnItemClick.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuOnItemClick.test.tsx @@ -1,8 +1,7 @@ -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick'; const Wrapper = ({ children }: { children: React.ReactNode }) => ( @@ -21,11 +20,8 @@ const renderHooks = () => { () => { const { onItemClick } = useCommandMenuOnItemClick(); - const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState); - return { onItemClick, - isCommandMenuOpened, }; }, { diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuUpdateNavigationMorphItemsByPage.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuUpdateNavigationMorphItemsByPage.test.tsx index c75feaaddd..10b2bf1514 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuUpdateNavigationMorphItemsByPage.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuUpdateNavigationMorphItemsByPage.test.tsx @@ -1,59 +1,45 @@ import { useCommandMenuUpdateNavigationMorphItemsByPage } from '@/command-menu/hooks/useCommandMenuUpdateNavigationMorphItemsByPage'; import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; const pageId = 'merge-page-id'; const objectMetadataId = 'company-metadata-id'; -const Wrapper = ({ - children, - initialRecordIds, -}: { - children: React.ReactNode; - initialRecordIds: string[]; -}) => ( - { - set( - commandMenuNavigationMorphItemsByPageState, - new Map([ - [ - pageId, - initialRecordIds.map((recordId) => ({ - objectMetadataId, - recordId, - })), - ], - ]), - ); - }} - > - {children} - +const Wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} ); -const renderHooks = (initialRecordIds: string[]) => - renderHook( +const renderHooks = (initialRecordIds: string[]) => { + jotaiStore.set( + commandMenuNavigationMorphItemsByPageState.atom, + new Map([ + [ + pageId, + initialRecordIds.map((recordId) => ({ + objectMetadataId, + recordId, + })), + ], + ]), + ); + + return renderHook( () => { const { updateCommandMenuNavigationMorphItemsByPage } = useCommandMenuUpdateNavigationMorphItemsByPage(); - const commandMenuNavigationMorphItemsByPage = useRecoilValue( - commandMenuNavigationMorphItemsByPageState, - ); return { updateCommandMenuNavigationMorphItemsByPage, - commandMenuNavigationMorphItemsByPage, }; }, { - wrapper: ({ children }) => ( - {children} - ), + wrapper: Wrapper, }, ); +}; describe('useCommandMenuUpdateNavigationMorphItemsByPage', () => { it('should replace existing items for a page instead of appending', async () => { @@ -68,7 +54,9 @@ describe('useCommandMenuUpdateNavigationMorphItemsByPage', () => { }); expect( - result.current.commandMenuNavigationMorphItemsByPage.get(pageId), + jotaiStore + .get(commandMenuNavigationMorphItemsByPageState.atom) + .get(pageId), ).toEqual([ { objectMetadataId, @@ -98,7 +86,9 @@ describe('useCommandMenuUpdateNavigationMorphItemsByPage', () => { }); expect( - result.current.commandMenuNavigationMorphItemsByPage.get(pageId), + jotaiStore + .get(commandMenuNavigationMorphItemsByPageState.atom) + .get(pageId), ).toEqual([ { objectMetadataId, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useNavigateCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useNavigateCommandMenu.test.tsx index bad5eb1fa0..af8869bc8d 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useNavigateCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useNavigateCommandMenu.test.tsx @@ -1,12 +1,12 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { useRecoilValue } from 'recoil'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; import { CommandMenuPages } from 'twenty-shared/types'; import { Icon123, useIcons } from 'twenty-ui/display'; @@ -40,19 +40,10 @@ const renderHooks = () => { () => { const { navigateCommandMenu } = useNavigateCommandMenu(); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuNavigationStack = useRecoilValue( - commandMenuNavigationStackState, - ); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); - const { getIcon } = useIcons(); return { navigateCommandMenu, - commandMenuPage, - commandMenuNavigationStack, - commandMenuPageInfo, getIcon, }; }, @@ -82,8 +73,10 @@ describe('useNavigateCommandMenu', () => { }); }); - expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root); - expect(result.current.commandMenuNavigationStack).toEqual([ + expect(jotaiStore.get(commandMenuPageState.atom)).toBe( + CommandMenuPages.Root, + ); + expect(jotaiStore.get(commandMenuNavigationStackState.atom)).toEqual([ { page: CommandMenuPages.Root, pageTitle: 'Root', @@ -92,7 +85,7 @@ describe('useNavigateCommandMenu', () => { pageId: 'mocked-uuid', }, ]); - expect(result.current.commandMenuPageInfo).toEqual({ + expect(jotaiStore.get(commandMenuPageInfoState.atom)).toEqual({ title: 'Root', Icon: Icon123, instanceId: 'mocked-uuid', diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenCalendarEventInCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenCalendarEventInCommandMenu.test.tsx index 0be5b688ea..867672d52d 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenCalendarEventInCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenCalendarEventInCommandMenu.test.tsx @@ -5,7 +5,7 @@ import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/Com import { useOpenCalendarEventInCommandMenu } from '@/command-menu/hooks/useOpenCalendarEventInCommandMenu'; import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconCalendarEvent } from 'twenty-ui/display'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; @@ -46,7 +46,7 @@ const renderHooks = () => { const { openCalendarEventInCommandMenu } = useOpenCalendarEventInCommandMenu(); - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, 'mocked-uuid', ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenEmailThreadInCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenEmailThreadInCommandMenu.test.tsx index 8597d04a8a..6a52f69a7e 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenEmailThreadInCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenEmailThreadInCommandMenu.test.tsx @@ -5,7 +5,7 @@ import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/Com import { useOpenEmailThreadInCommandMenu } from '@/command-menu/hooks/useOpenEmailThreadInCommandMenu'; import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconMail } from 'twenty-ui/display'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; @@ -46,7 +46,7 @@ const renderHooks = () => { const { openEmailThreadInCommandMenu } = useOpenEmailThreadInCommandMenu(); - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, 'mocked-uuid', ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenRecordInCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenRecordInCommandMenu.test.tsx index 13d927f87e..444dd3348b 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenRecordInCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useOpenRecordInCommandMenu.test.tsx @@ -1,19 +1,18 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { useRecoilValue } from 'recoil'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu'; import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState'; import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState'; import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; -import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { CommandMenuPages } from 'twenty-shared/types'; import { useIcons } from 'twenty-ui/display'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; @@ -53,32 +52,27 @@ const renderHooks = () => { () => { const { openRecordInCommandMenu } = useOpenRecordInCommandMenu(); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuNavigationMorphItemsByPage = useRecoilValue( - commandMenuNavigationMorphItemsByPageState, - ); - - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, 'mocked-uuid', ); - const viewableRecordNameSingular = useRecoilComponentValue( + const viewableRecordNameSingular = useRecoilComponentValueV2( viewableRecordNameSingularComponentState, 'mocked-uuid', ); - const currentObjectMetadataItemId = useRecoilComponentValue( + const currentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, 'mocked-uuid', ); - const targetedRecordsRule = useRecoilComponentValue( + const targetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, 'mocked-uuid', ); - const numberOfSelectedRecords = useRecoilComponentValue( + const numberOfSelectedRecords = useRecoilComponentValueV2( contextStoreNumberOfSelectedRecordsComponentState, 'mocked-uuid', ); - const currentViewType = useRecoilComponentValue( + const currentViewType = useRecoilComponentValueV2( contextStoreCurrentViewTypeComponentState, 'mocked-uuid', ); @@ -87,8 +81,6 @@ const renderHooks = () => { return { openRecordInCommandMenu, viewableRecordId, - commandMenuPage, - commandMenuNavigationMorphItemsByPage, viewableRecordNameSingular, currentObjectMetadataItemId, targetedRecordsRule, @@ -134,10 +126,11 @@ describe('useOpenRecordInCommandMenu', () => { expect(result.current.numberOfSelectedRecords).toBe(1); expect(result.current.currentViewType).toBe(ContextStoreViewType.ShowPage); - expect(result.current.commandMenuNavigationMorphItemsByPage.size).toBe(1); - expect( - result.current.commandMenuNavigationMorphItemsByPage.get('mocked-uuid'), - ).toEqual([ + const commandMenuNavigationMorphItemsByPage = jotaiStore.get( + commandMenuNavigationMorphItemsByPageState.atom, + ); + expect(commandMenuNavigationMorphItemsByPage.size).toBe(1); + expect(commandMenuNavigationMorphItemsByPage.get('mocked-uuid')).toEqual([ { objectMetadataId: personMockObjectMetadataItem.id, recordId, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx index 1525b47a65..a01758f699 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx @@ -1,12 +1,12 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { useRecoilValue } from 'recoil'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId'; import { useSetGlobalCommandMenuContext } from '@/command-menu/hooks/useSetGlobalCommandMenuContext'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { contextStoreAnyFieldFilterValueComponentState } from '@/context-store/states/contextStoreAnyFieldFilterValueComponentState'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; @@ -14,6 +14,7 @@ import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-sto import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; @@ -47,9 +48,15 @@ const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({ }, contextStoreNumberOfSelectedRecords: 2, contextStoreCurrentViewType: ContextStoreViewType.Table, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set(recordStoreFamilyState(peopleMock[0].id), peopleMock[0]); - snapshot.set(recordStoreFamilyState(peopleMock[1].id), peopleMock[1]); + onInitializeRecoilSnapshot: (_snapshot) => { + jotaiStore.set( + recordStoreFamilyState.atomFamily(peopleMock[0].id), + peopleMock[0], + ); + jotaiStore.set( + recordStoreFamilyState.atomFamily(peopleMock[1].id), + peopleMock[1], + ); }, }); @@ -64,46 +71,34 @@ describe('useSetGlobalCommandMenuContext', () => { const { setGlobalCommandMenuContext } = useSetGlobalCommandMenuContext(); - const targetedRecordsRule = useRecoilValue( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), + const targetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, ); - const numberOfSelectedRecords = useRecoilValue( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), + const numberOfSelectedRecords = useRecoilComponentValueV2( + contextStoreNumberOfSelectedRecordsComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, ); - const filters = useRecoilValue( - contextStoreFiltersComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), + const filters = useRecoilComponentValueV2( + contextStoreFiltersComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, ); - const filterGroups = useRecoilValue( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), + const filterGroups = useRecoilComponentValueV2( + contextStoreFilterGroupsComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, ); - const anyFieldFilterValue = useRecoilValue( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), + const anyFieldFilterValue = useRecoilComponentValueV2( + contextStoreAnyFieldFilterValueComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, ); - const currentViewType = useRecoilValue( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - ); - - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); - - const hasUserSelectedCommand = useRecoilValue( - hasUserSelectedCommandState, + const currentViewType = useRecoilComponentValueV2( + contextStoreCurrentViewTypeComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, ); return { @@ -113,8 +108,6 @@ describe('useSetGlobalCommandMenuContext', () => { filters, filterGroups, currentViewType, - commandMenuPageInfo, - hasUserSelectedCommand, anyFieldFilterValue, }; }, @@ -131,12 +124,16 @@ describe('useSetGlobalCommandMenuContext', () => { expect(result.current.filters).toEqual([]); expect(result.current.anyFieldFilterValue).toEqual(''); expect(result.current.currentViewType).toBe(ContextStoreViewType.Table); - expect(result.current.commandMenuPageInfo).toEqual({ + const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom); + expect(commandMenuPageInfo).toEqual({ title: undefined, Icon: undefined, instanceId: '', }); - expect(result.current.hasUserSelectedCommand).toBe(false); + const hasUserSelectedCommand = jotaiStore.get( + hasUserSelectedCommandState.atom, + ); + expect(hasUserSelectedCommand).toBe(false); act(() => { result.current.setGlobalCommandMenuContext(); @@ -150,12 +147,18 @@ describe('useSetGlobalCommandMenuContext', () => { expect(result.current.filters).toEqual([]); expect(result.current.anyFieldFilterValue).toEqual(''); expect(result.current.currentViewType).toBe(ContextStoreViewType.Table); - expect(result.current.commandMenuPageInfo).toEqual({ + const commandMenuPageInfoAfter = jotaiStore.get( + commandMenuPageInfoState.atom, + ); + expect(commandMenuPageInfoAfter).toEqual({ title: undefined, Icon: undefined, instanceId: '', }); - expect(result.current.hasUserSelectedCommand).toBe(false); + const hasUserSelectedCommandAfter = jotaiStore.get( + hasUserSelectedCommandState.atom, + ); + expect(hasUserSelectedCommandAfter).toBe(false); }); it('should call copyContextStoreStates with correct parameters', () => { diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx index 5d723946bb..84686295ea 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx @@ -1,9 +1,10 @@ import { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateCommandMenuPageInfo'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconArrowDown, IconDotsVertical } from 'twenty-ui/display'; @@ -23,30 +24,22 @@ const mockedNavigationStack = [ ]; const Wrapper = ({ children }: { children: React.ReactNode }) => ( - { - set(commandMenuNavigationStackState, mockedNavigationStack); - set(commandMenuPageInfoState, mockedPageInfo); - }} - > - {children} - + {children} ); describe('useUpdateCommandMenuPageInfo', () => { + beforeEach(() => { + jotaiStore.set(commandMenuNavigationStackState.atom, mockedNavigationStack); + jotaiStore.set(commandMenuPageInfoState.atom, mockedPageInfo); + }); + const renderHooks = () => { const { result } = renderHook( () => { const { updateCommandMenuPageInfo } = useUpdateCommandMenuPageInfo(); - const commandMenuNavigationStack = useRecoilValue( - commandMenuNavigationStackState, - ); - const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState); return { updateCommandMenuPageInfo, - commandMenuNavigationStack, - commandMenuPageInfo, }; }, { wrapper: Wrapper }, @@ -67,7 +60,10 @@ describe('useUpdateCommandMenuPageInfo', () => { }); }); - expect(result.current.commandMenuNavigationStack).toEqual([ + const commandMenuNavigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); + expect(commandMenuNavigationStack).toEqual([ { page: CommandMenuPages.Root, pageTitle: 'New Title', @@ -76,7 +72,8 @@ describe('useUpdateCommandMenuPageInfo', () => { }, ]); - expect(result.current.commandMenuPageInfo).toEqual({ + const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom); + expect(commandMenuPageInfo).toEqual({ title: 'New Title', Icon: IconArrowDown, instanceId: 'test-instance', @@ -92,7 +89,10 @@ describe('useUpdateCommandMenuPageInfo', () => { }); }); - expect(result.current.commandMenuNavigationStack).toEqual([ + const commandMenuNavigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); + expect(commandMenuNavigationStack).toEqual([ { page: CommandMenuPages.Root, pageTitle: 'New Title', @@ -101,7 +101,8 @@ describe('useUpdateCommandMenuPageInfo', () => { }, ]); - expect(result.current.commandMenuPageInfo).toEqual({ + const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom); + expect(commandMenuPageInfo).toEqual({ title: 'New Title', Icon: IconDotsVertical, instanceId: 'test-instance', @@ -117,7 +118,10 @@ describe('useUpdateCommandMenuPageInfo', () => { }); }); - expect(result.current.commandMenuNavigationStack).toEqual([ + const commandMenuNavigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); + expect(commandMenuNavigationStack).toEqual([ { page: CommandMenuPages.Root, pageTitle: 'Initial Title', @@ -126,7 +130,8 @@ describe('useUpdateCommandMenuPageInfo', () => { }, ]); - expect(result.current.commandMenuPageInfo).toEqual({ + const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom); + expect(commandMenuPageInfo).toEqual({ title: 'Initial Title', Icon: IconArrowDown, instanceId: 'test-instance', diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx index cf6707e93b..aa8d7b33c5 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx @@ -1,5 +1,4 @@ import { renderHook } from '@testing-library/react'; -import { useRecoilValue } from 'recoil'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; @@ -7,14 +6,12 @@ import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState'; import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState'; import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState'; -import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; -import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { act } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; @@ -67,40 +64,36 @@ const renderHooks = () => { openWorkflowEditStepTypeInCommandMenu, openWorkflowViewStepInCommandMenu, } = useWorkflowCommandMenu(); - const commandMenuPage = useRecoilValue(commandMenuPageState); - const commandMenuNavigationMorphItemsByPage = useRecoilValue( - commandMenuNavigationMorphItemsByPageState, - ); - const viewableRecordId = useRecoilComponentValue( + const _viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, 'mocked-uuid', ); - const viewableRecordNameSingular = useRecoilComponentValue( + const viewableRecordNameSingular = useRecoilComponentValueV2( viewableRecordNameSingularComponentState, 'mocked-uuid', ); - const currentObjectMetadataItemId = useRecoilComponentValue( + const currentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, 'mocked-uuid', ); - const targetedRecordsRule = useRecoilComponentValue( + const targetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, 'mocked-uuid', ); - const numberOfSelectedRecords = useRecoilComponentValue( + const numberOfSelectedRecords = useRecoilComponentValueV2( contextStoreNumberOfSelectedRecordsComponentState, 'mocked-uuid', ); - const currentViewType = useRecoilComponentValue( + const currentViewType = useRecoilComponentValueV2( contextStoreCurrentViewTypeComponentState, 'mocked-uuid', ); - const workflowId = useRecoilComponentValue( + const workflowId = useRecoilComponentValueV2( commandMenuWorkflowIdComponentState, 'mocked-uuid', ); - const workflowVersionId = useRecoilComponentValue( + const workflowVersionId = useRecoilComponentValueV2( commandMenuWorkflowVersionIdComponentState, 'mocked-uuid', ); @@ -114,9 +107,6 @@ const renderHooks = () => { openWorkflowViewStepInCommandMenu, workflowId, workflowVersionId, - viewableRecordId, - commandMenuPage, - commandMenuNavigationMorphItemsByPage, viewableRecordNameSingular, currentObjectMetadataItemId, targetedRecordsRule, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts index c495ace928..0740bcfbaa 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts @@ -1,17 +1,14 @@ -import { useRecoilCallback } from 'recoil'; - import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId'; import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; import { addToNavPayloadRegistryStateV2 } from '@/navigation-menu-item/states/addToNavPayloadRegistryStateV2'; import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; import { emitSidePanelOpenEvent } from '@/ui/layout/right-drawer/utils/emitSidePanelOpenEvent'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { t } from '@lingui/core/macro'; -import { useStore } from 'jotai'; import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconDotsVertical } from 'twenty-ui/display'; @@ -23,28 +20,19 @@ export const useCommandMenu = () => { const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const store = useStore(); + const closeCommandMenu = useCallback(() => { + const isCommandMenuOpened = jotaiStore.get(isCommandMenuOpenedStateV2.atom); - const closeCommandMenu = useRecoilCallback( - ({ set, snapshot }) => - () => { - const isCommandMenuOpened = snapshot - .getLoadable(isCommandMenuOpenedState) - .getValue(); - - if (isCommandMenuOpened) { - store.set(addToNavPayloadRegistryStateV2.atom, new Map()); - set(isCommandMenuOpenedState, false); - store.set(isCommandMenuOpenedStateV2.atom, false); - set(isCommandMenuClosingState, true); - closeAnyOpenDropdown(); - removeFocusItemFromFocusStackById({ - focusId: SIDE_PANEL_FOCUS_ID, - }); - } - }, - [closeAnyOpenDropdown, removeFocusItemFromFocusStackById, store], - ); + if (isCommandMenuOpened) { + jotaiStore.set(addToNavPayloadRegistryStateV2.atom, new Map()); + jotaiStore.set(isCommandMenuOpenedStateV2.atom, false); + jotaiStore.set(isCommandMenuClosingState.atom, true); + closeAnyOpenDropdown(); + removeFocusItemFromFocusStackById({ + focusId: SIDE_PANEL_FOCUS_ID, + }); + } + }, [closeAnyOpenDropdown, removeFocusItemFromFocusStackById]); const openCommandMenu = useCallback(() => { emitSidePanelOpenEvent(); @@ -57,23 +45,17 @@ export const useCommandMenu = () => { }); }, [closeAnyOpenDropdown, navigateCommandMenu]); - const toggleCommandMenu = useRecoilCallback( - ({ snapshot, set }) => - async () => { - const isCommandMenuOpened = snapshot - .getLoadable(isCommandMenuOpenedState) - .getValue(); + const toggleCommandMenu = useCallback(() => { + const isCommandMenuOpened = jotaiStore.get(isCommandMenuOpenedStateV2.atom); - set(commandMenuSearchState, ''); + jotaiStore.set(commandMenuSearchState.atom, ''); - if (isCommandMenuOpened) { - closeCommandMenu(); - } else { - openCommandMenu(); - } - }, - [closeCommandMenu, openCommandMenu], - ); + if (isCommandMenuOpened) { + closeCommandMenu(); + } else { + openCommandMenu(); + } + }, [closeCommandMenu, openCommandMenu]); return { openCommandMenu, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts index 9a3bf3b798..7d0c2bdc18 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts @@ -10,7 +10,6 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; @@ -23,10 +22,10 @@ import { emitSidePanelCloseEvent } from '@/ui/layout/right-drawer/utils/emitSide import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowLogicFunctionTabListComponentId'; import { WorkflowLogicFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowLogicFunctionTabId'; -import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -39,107 +38,98 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => { const { closeDropdown } = useCloseDropdown(); - const store = useStore(); + const commandMenuCloseAnimationCompleteCleanup = useCallback(() => { + closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID); - const commandMenuCloseAnimationCompleteCleanup = useRecoilCallback( - ({ snapshot, set }) => - () => { - closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID); + resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID); + resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID); - resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID); - resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID); + const currentPage = jotaiStore.get(commandMenuPageState.atom); - const currentPage = snapshot - .getLoadable(commandMenuPageState) - .getValue(); + const isPageLayoutEditingPage = + currentPage === CommandMenuPages.PageLayoutWidgetTypeSelect || + currentPage === CommandMenuPages.PageLayoutGraphTypeSelect || + currentPage === CommandMenuPages.PageLayoutIframeSettings || + currentPage === CommandMenuPages.PageLayoutTabSettings; - const isPageLayoutEditingPage = - currentPage === CommandMenuPages.PageLayoutWidgetTypeSelect || - currentPage === CommandMenuPages.PageLayoutGraphTypeSelect || - currentPage === CommandMenuPages.PageLayoutIframeSettings || - currentPage === CommandMenuPages.PageLayoutTabSettings; + if (isPageLayoutEditingPage) { + const targetedRecordsRule = jotaiStore.get( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + ); - if (isPageLayoutEditingPage) { - const targetedRecordsRule = snapshot - .getLoadable( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - ) - .getValue(); - - if ( - targetedRecordsRule.mode === 'selection' && - targetedRecordsRule.selectedRecordIds.length === 1 - ) { - const recordId = targetedRecordsRule.selectedRecordIds[0]; - const record = snapshot - .getLoadable(recordStoreFamilyState(recordId)) - .getValue(); - - if (isDefined(record) && isDefined(record.pageLayoutId)) { - set( - pageLayoutEditingWidgetIdComponentState.atomFamily({ - instanceId: record.pageLayoutId, - }), - null, - ); - set( - pageLayoutTabSettingsOpenTabIdComponentState.atomFamily({ - instanceId: record.pageLayoutId, - }), - null, - ); - set( - pageLayoutDraggedAreaComponentState.atomFamily({ - instanceId: record.pageLayoutId, - }), - null, - ); - } - } - } - - set(viewableRecordIdState, null); - set(commandMenuPageState, CommandMenuPages.Root); - set(commandMenuPageInfoState, { - title: undefined, - Icon: undefined, - instanceId: '', - }); - set(isCommandMenuOpenedState, false); - store.set(isCommandMenuOpenedStateV2.atom, false); - set(commandMenuSearchState, ''); - set(commandMenuNavigationMorphItemsByPageState, new Map()); - set(commandMenuNavigationStackState, []); - resetSelectedItem(); - set(hasUserSelectedCommandState, false); - - emitSidePanelCloseEvent(); - set(isCommandMenuClosingState, false); - store.set( - activeTabIdComponentState.atomFamily({ - instanceId: WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID, - }), - WorkflowLogicFunctionTabId.CODE, + if ( + targetedRecordsRule.mode === 'selection' && + targetedRecordsRule.selectedRecordIds.length === 1 + ) { + const recordId = targetedRecordsRule.selectedRecordIds[0]; + const record = jotaiStore.get( + recordStoreFamilyState.atomFamily(recordId), ); - for (const [pageId, morphItems] of snapshot - .getLoadable(commandMenuNavigationMorphItemsByPageState) - .getValue()) { - store.set( - activeTabIdComponentState.atomFamily({ - instanceId: getShowPageTabListComponentId({ - pageId, - targetObjectId: morphItems[0].recordId, - }), + if (isDefined(record) && isDefined(record.pageLayoutId)) { + jotaiStore.set( + pageLayoutEditingWidgetIdComponentState.atomFamily({ + instanceId: record.pageLayoutId, + }), + null, + ); + jotaiStore.set( + pageLayoutTabSettingsOpenTabIdComponentState.atomFamily({ + instanceId: record.pageLayoutId, + }), + null, + ); + jotaiStore.set( + pageLayoutDraggedAreaComponentState.atomFamily({ + instanceId: record.pageLayoutId, }), null, ); } - }, - [closeDropdown, resetContextStoreStates, resetSelectedItem, store], - ); + } + } + + jotaiStore.set(viewableRecordIdState.atom, null); + jotaiStore.set(commandMenuPageState.atom, CommandMenuPages.Root); + jotaiStore.set(commandMenuPageInfoState.atom, { + title: undefined, + Icon: undefined, + instanceId: '', + }); + jotaiStore.set(isCommandMenuOpenedStateV2.atom, false); + jotaiStore.set(commandMenuSearchState.atom, ''); + jotaiStore.set(commandMenuNavigationMorphItemsByPageState.atom, new Map()); + jotaiStore.set(commandMenuNavigationStackState.atom, []); + resetSelectedItem(); + jotaiStore.set(hasUserSelectedCommandState.atom, false); + + emitSidePanelCloseEvent(); + jotaiStore.set(isCommandMenuClosingState.atom, false); + jotaiStore.set( + activeTabIdComponentState.atomFamily({ + instanceId: WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID, + }), + WorkflowLogicFunctionTabId.CODE, + ); + + const morphItemsByPage = jotaiStore.get( + commandMenuNavigationMorphItemsByPageState.atom, + ); + + for (const [pageId, morphItems] of morphItemsByPage) { + jotaiStore.set( + activeTabIdComponentState.atomFamily({ + instanceId: getShowPageTabListComponentId({ + pageId, + targetObjectId: morphItems[0].recordId, + }), + }), + null, + ); + } + }, [closeDropdown, resetContextStoreStates, resetSelectedItem]); return { commandMenuCloseAnimationCompleteCleanup, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx index 0c96227aa0..f24beb5d10 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx @@ -5,11 +5,10 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe import { CommandMenuPages } from 'twenty-shared/types'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { recordStoreIdentifiersFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifiersSelector'; -import { recordStoreRecordsSelector } from '@/object-record/record-store/states/selectors/recordStoreRecordsSelector'; +import { recordStoreRecordsSelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreRecordsSelectorV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; @@ -24,7 +23,7 @@ const StyledIconWrapper = styled.div` `; export const useCommandMenuContextChips = () => { - const commandMenuNavigationStack = useRecoilValue( + const commandMenuNavigationStack = useRecoilValueV2( commandMenuNavigationStackState, ); @@ -38,7 +37,7 @@ export const useCommandMenuContextChips = () => { const theme = useTheme(); - const commandMenuNavigationMorphItemsByPage = useRecoilValue( + const commandMenuNavigationMorphItemsByPage = useRecoilValueV2( commandMenuNavigationMorphItemsByPageState, ); @@ -55,11 +54,9 @@ export const useCommandMenuContextChips = () => { allowRequestsToTwentyIcons, }, ); - const records = useRecoilValue( - recordStoreRecordsSelector({ - recordIds: allRecordIds, - }), - ); + const records = useFamilySelectorValueV2(recordStoreRecordsSelectorV2, { + recordIds: allRecordIds, + }); const contextChips = useMemo(() => { const filteredCommandMenuNavigationStack = diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts index 0abf97e3b1..40d16028c6 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts @@ -1,4 +1,4 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; @@ -8,132 +8,123 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useStore } from 'jotai'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isNonEmptyArray } from '@sniptt/guards'; import { isDefined } from 'twenty-shared/utils'; export const useCommandMenuHistory = () => { const { closeCommandMenu } = useCommandMenu(); - const store = useStore(); + const goBackFromCommandMenu = useCallback(() => { + const currentNavigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); - const goBackFromCommandMenu = useRecoilCallback( - ({ snapshot, set }) => { - return () => { - const currentNavigationStack = snapshot - .getLoadable(commandMenuNavigationStackState) - .getValue(); + const newNavigationStack = currentNavigationStack.slice(0, -1); + const lastNavigationStackItem = newNavigationStack.at(-1); - const newNavigationStack = currentNavigationStack.slice(0, -1); - const lastNavigationStackItem = newNavigationStack.at(-1); + if (!isDefined(lastNavigationStackItem)) { + closeCommandMenu(); + return; + } - if (!isDefined(lastNavigationStackItem)) { - closeCommandMenu(); - return; - } + jotaiStore.set(commandMenuPageState.atom, lastNavigationStackItem.page); - set(commandMenuPageState, lastNavigationStackItem.page); + jotaiStore.set(commandMenuPageInfoState.atom, { + title: lastNavigationStackItem.pageTitle, + Icon: lastNavigationStackItem.pageIcon, + instanceId: lastNavigationStackItem.pageId, + }); - set(commandMenuPageInfoState, { - title: lastNavigationStackItem.pageTitle, - Icon: lastNavigationStackItem.pageIcon, - instanceId: lastNavigationStackItem.pageId, - }); + jotaiStore.set(commandMenuNavigationStackState.atom, newNavigationStack); - set(commandMenuNavigationStackState, newNavigationStack); + const currentMorphItems = jotaiStore.get( + commandMenuNavigationMorphItemsByPageState.atom, + ); - const currentMorphItems = snapshot - .getLoadable(commandMenuNavigationMorphItemsByPageState) - .getValue(); + if (currentNavigationStack.length > 0) { + const removedItem = currentNavigationStack.at(-1); - if (currentNavigationStack.length > 0) { - const removedItem = currentNavigationStack.at(-1); - - if (isDefined(removedItem)) { - const newMorphItems = new Map(currentMorphItems); - newMorphItems.delete(removedItem.pageId); - set(commandMenuNavigationMorphItemsByPageState, newMorphItems); - - const morphItems = currentMorphItems.get(removedItem.pageId); - if (isNonEmptyArray(morphItems)) { - store.set( - activeTabIdComponentState.atomFamily({ - instanceId: getShowPageTabListComponentId({ - pageId: removedItem.pageId, - targetObjectId: morphItems[0].recordId, - }), - }), - null, - ); - } - } - } - - set(hasUserSelectedCommandState, false); - }; - }, - [closeCommandMenu, store], - ); - - const navigateCommandMenuHistory = useRecoilCallback( - ({ snapshot, set }) => { - return (pageIndex: number) => { - const currentNavigationStack = snapshot - .getLoadable(commandMenuNavigationStackState) - .getValue(); - - const newNavigationStack = currentNavigationStack.slice( - 0, - pageIndex + 1, + if (isDefined(removedItem)) { + const newMorphItems = new Map(currentMorphItems); + newMorphItems.delete(removedItem.pageId); + jotaiStore.set( + commandMenuNavigationMorphItemsByPageState.atom, + newMorphItems, ); - set(commandMenuNavigationStackState, newNavigationStack); - - const newNavigationStackItem = newNavigationStack.at(-1); - - if (!isDefined(newNavigationStackItem)) { - throw new Error( - `No command menu navigation stack item found for index ${pageIndex}`, + const morphItems = currentMorphItems.get(removedItem.pageId); + if (isNonEmptyArray(morphItems)) { + jotaiStore.set( + activeTabIdComponentState.atomFamily({ + instanceId: getShowPageTabListComponentId({ + pageId: removedItem.pageId, + targetObjectId: morphItems[0].recordId, + }), + }), + null, ); } + } + } - set(commandMenuPageState, newNavigationStackItem.page); - set(commandMenuPageInfoState, { - title: newNavigationStackItem.pageTitle, - Icon: newNavigationStackItem.pageIcon, - instanceId: newNavigationStackItem.pageId, - }); - const currentMorphItems = snapshot - .getLoadable(commandMenuNavigationMorphItemsByPageState) - .getValue(); + jotaiStore.set(hasUserSelectedCommandState.atom, false); + }, [closeCommandMenu]); - for (const [pageId, morphItems] of currentMorphItems.entries()) { - if (!newNavigationStack.some((item) => item.pageId === pageId)) { - store.set( - activeTabIdComponentState.atomFamily({ - instanceId: getShowPageTabListComponentId({ - pageId, - targetObjectId: morphItems[0].recordId, - }), - }), - null, - ); - } - } + const navigateCommandMenuHistory = useCallback((pageIndex: number) => { + const currentNavigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); - const newMorphItems = new Map( - Array.from(currentMorphItems.entries()).filter(([pageId]) => - newNavigationStack.some((item) => item.pageId === pageId), - ), + const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1); + + jotaiStore.set(commandMenuNavigationStackState.atom, newNavigationStack); + + const newNavigationStackItem = newNavigationStack.at(-1); + + if (!isDefined(newNavigationStackItem)) { + throw new Error( + `No command menu navigation stack item found for index ${pageIndex}`, + ); + } + + jotaiStore.set(commandMenuPageState.atom, newNavigationStackItem.page); + jotaiStore.set(commandMenuPageInfoState.atom, { + title: newNavigationStackItem.pageTitle, + Icon: newNavigationStackItem.pageIcon, + instanceId: newNavigationStackItem.pageId, + }); + const currentMorphItems = jotaiStore.get( + commandMenuNavigationMorphItemsByPageState.atom, + ); + + for (const [pageId, morphItems] of currentMorphItems.entries()) { + if (!newNavigationStack.some((item) => item.pageId === pageId)) { + jotaiStore.set( + activeTabIdComponentState.atomFamily({ + instanceId: getShowPageTabListComponentId({ + pageId, + targetObjectId: morphItems[0].recordId, + }), + }), + null, ); + } + } - set(commandMenuNavigationMorphItemsByPageState, newMorphItems); + const newMorphItems = new Map( + Array.from(currentMorphItems.entries()).filter(([pageId]) => + newNavigationStack.some((item) => item.pageId === pageId), + ), + ); - set(hasUserSelectedCommandState, false); - }; - }, - [store], - ); + jotaiStore.set( + commandMenuNavigationMorphItemsByPageState.atom, + newMorphItems, + ); + + jotaiStore.set(hasUserSelectedCommandState.atom, false); + }, []); return { goBackFromCommandMenu, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts index e0cd2dfc09..571c40261e 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts @@ -11,10 +11,10 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu'; import { useGlobalHotkeys } from '@/ui/utilities/hotkey/hooks/useGlobalHotkeys'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { Key } from 'ts-key-enum'; import { CommandMenuPages } from 'twenty-shared/types'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -30,15 +30,15 @@ export const useCommandMenuHotKeys = () => { const { setGlobalCommandMenuContext } = useSetGlobalCommandMenuContext(); - const commandMenuSearch = useRecoilValue(commandMenuSearchState); + const commandMenuSearch = useRecoilValueV2(commandMenuSearchState); const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu(); - const commandMenuPage = useRecoilValue(commandMenuPageState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED); - const contextStoreTargetedRecordsRuleComponent = useRecoilComponentValue( + const contextStoreTargetedRecordsRuleComponent = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, COMMAND_MENU_COMPONENT_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx index 459584d5f8..e9c55eb086 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuSearchRecords.tsx @@ -11,15 +11,15 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId'; import { t } from '@lingui/core/macro'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; import { AppPath } from 'twenty-shared/types'; import { Avatar } from 'twenty-ui/display'; import { useDebounce } from 'use-debounce'; import { useSearchQuery } from '~/generated/graphql'; export const useCommandMenuSearchRecords = () => { - const commandMenuSearch = useRecoilValue(commandMenuSearchState); + const commandMenuSearch = useRecoilValueV2(commandMenuSearchState); const coreClient = useApolloCoreClient(); const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuUpdateNavigationMorphItemsByPage.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuUpdateNavigationMorphItemsByPage.tsx index faf0b0f226..c9b7838dc4 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuUpdateNavigationMorphItemsByPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuUpdateNavigationMorphItemsByPage.tsx @@ -1,5 +1,6 @@ import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; type UpdateNavigationMorphItemsByPageParams = { pageId: string; @@ -8,26 +9,28 @@ type UpdateNavigationMorphItemsByPageParams = { }; export const useCommandMenuUpdateNavigationMorphItemsByPage = () => { - const updateCommandMenuNavigationMorphItemsByPage = useRecoilCallback( - ({ set, snapshot }) => - async ({ - pageId, + const updateCommandMenuNavigationMorphItemsByPage = useCallback( + async ({ + pageId, + objectMetadataId, + objectRecordIds, + }: UpdateNavigationMorphItemsByPageParams) => { + const currentMorphItems = jotaiStore.get( + commandMenuNavigationMorphItemsByPageState.atom, + ); + + const newMorphItems = objectRecordIds.map((recordId) => ({ objectMetadataId, - objectRecordIds, - }: UpdateNavigationMorphItemsByPageParams) => { - const currentMorphItems = snapshot - .getLoadable(commandMenuNavigationMorphItemsByPageState) - .getValue(); + recordId, + })); - const newMorphItems = objectRecordIds.map((recordId) => ({ - objectMetadataId, - recordId, - })); - - const newMorphItemsMap = new Map(currentMorphItems); - newMorphItemsMap.set(pageId, newMorphItems); - set(commandMenuNavigationMorphItemsByPageState, newMorphItemsMap); - }, + const newMorphItemsMap = new Map(currentMorphItems); + newMorphItemsMap.set(pageId, newMorphItems); + jotaiStore.set( + commandMenuNavigationMorphItemsByPageState.atom, + newMorphItemsMap, + ); + }, [], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts index d96badef65..a877251dca 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts @@ -7,153 +7,135 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useCopyContextStoreStates = () => { - const copyContextStoreStates = useRecoilCallback( - ({ snapshot, set }) => - ({ - instanceIdToCopyFrom, - instanceIdToCopyTo, - }: { - instanceIdToCopyFrom: string; - instanceIdToCopyTo: string; - }) => { - const contextStoreCurrentObjectMetadataItemId = snapshot - .getLoadable( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const copyContextStoreStates = useCallback( + ({ + instanceIdToCopyFrom, + instanceIdToCopyTo, + }: { + instanceIdToCopyFrom: string; + instanceIdToCopyTo: string; + }) => { + const contextStoreCurrentObjectMetadataItemId = jotaiStore.get( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreCurrentObjectMetadataItemId, - ); + jotaiStore.set( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreCurrentObjectMetadataItemId, + ); - const contextStoreTargetedRecordsRule = snapshot - .getLoadable( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreTargetedRecordsRule = jotaiStore.get( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreTargetedRecordsRule, - ); + jotaiStore.set( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreTargetedRecordsRule, + ); - const contextStoreNumberOfSelectedRecords = snapshot - .getLoadable( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreNumberOfSelectedRecords = jotaiStore.get( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreNumberOfSelectedRecords, - ); + jotaiStore.set( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreNumberOfSelectedRecords, + ); - const contextStoreFilters = snapshot - .getLoadable( - contextStoreFiltersComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreFilters = jotaiStore.get( + contextStoreFiltersComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreFiltersComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreFilters, - ); + jotaiStore.set( + contextStoreFiltersComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreFilters, + ); - const contextStoreFilterGroups = snapshot - .getLoadable( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreFilterGroups = jotaiStore.get( + contextStoreFilterGroupsComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreFilterGroups, - ); + jotaiStore.set( + contextStoreFilterGroupsComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreFilterGroups, + ); - const contextStoreAnyFieldFilterValue = snapshot - .getLoadable( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreAnyFieldFilterValue = jotaiStore.get( + contextStoreAnyFieldFilterValueComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreAnyFieldFilterValue, - ); + jotaiStore.set( + contextStoreAnyFieldFilterValueComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreAnyFieldFilterValue, + ); - const contextStoreCurrentViewId = snapshot - .getLoadable( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreCurrentViewId = jotaiStore.get( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreCurrentViewId, - ); + jotaiStore.set( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreCurrentViewId, + ); - const contextStoreCurrentViewType = snapshot - .getLoadable( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreCurrentViewType = jotaiStore.get( + contextStoreCurrentViewTypeComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreCurrentViewType, - ); + jotaiStore.set( + contextStoreCurrentViewTypeComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreCurrentViewType, + ); - const contextStoreIsFullTabWidgetInEditMode = snapshot - .getLoadable( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ) - .getValue(); + const contextStoreIsFullTabWidgetInEditMode = jotaiStore.get( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ); - set( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreIsFullTabWidgetInEditMode, - ); - }, + jotaiStore.set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreIsFullTabWidgetInEditMode, + ); + }, [], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useNavigateCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useNavigateCommandMenu.ts index e49d738724..1b45daf45f 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useNavigateCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useNavigateCommandMenu.ts @@ -9,13 +9,12 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState import { commandMenuShouldFocusTitleInputComponentState } from '@/command-menu/states/commandMenuShouldFocusTitleInputComponentState'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; import { type CommandMenuPages } from 'twenty-shared/types'; import { type IconComponent } from 'twenty-ui/display'; import { v4 } from 'uuid'; @@ -36,121 +35,110 @@ export const useNavigateCommandMenu = () => { const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); - const store = useStore(); + const openCommandMenu = useCallback(() => { + const isCommandMenuOpened = jotaiStore.get(isCommandMenuOpenedStateV2.atom); - const openCommandMenu = useRecoilCallback( - ({ snapshot, set }) => - () => { - const isCommandMenuOpened = snapshot - .getLoadable(isCommandMenuOpenedState) - .getValue(); + const isCommandMenuClosing = jotaiStore.get(isCommandMenuClosingState.atom); - const isCommandMenuClosing = snapshot - .getLoadable(isCommandMenuClosingState) - .getValue(); + if (isCommandMenuClosing) { + commandMenuCloseAnimationCompleteCleanup(); + } - if (isCommandMenuClosing) { - commandMenuCloseAnimationCompleteCleanup(); - } + if (isCommandMenuOpened) { + return; + } - if (isCommandMenuOpened) { - return; - } - - pushFocusItemToFocusStack({ - focusId: SIDE_PANEL_FOCUS_ID, - component: { - type: FocusComponentType.SIDE_PANEL, - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - - copyContextStoreStates({ - instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID, - instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }); - - set(isCommandMenuOpenedState, true); - store.set(isCommandMenuOpenedStateV2.atom, true); - set(hasUserSelectedCommandState, false); + pushFocusItemToFocusStack({ + focusId: SIDE_PANEL_FOCUS_ID, + component: { + type: FocusComponentType.SIDE_PANEL, + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, }, - [ - copyContextStoreStates, - commandMenuCloseAnimationCompleteCleanup, - pushFocusItemToFocusStack, - store, - ], - ); + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); - const navigateCommandMenu = useRecoilCallback( - ({ snapshot, set }) => { - return ({ - page, - pageTitle, - pageIcon, - pageIconColor, - pageId, - focusTitleInput = false, - resetNavigationStack = false, - }: CommandMenuNavigationStackItem & { - resetNavigationStack?: boolean; - focusTitleInput?: boolean; - }) => { - const computedPageId = pageId || v4(); + copyContextStoreStates({ + instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID, + instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }); - openCommandMenu(); - set(commandMenuPageState, page); - set(commandMenuPageInfoState, { - title: pageTitle, - Icon: pageIcon, - instanceId: computedPageId, - }); + jotaiStore.set(isCommandMenuOpenedStateV2.atom, true); + jotaiStore.set(hasUserSelectedCommandState.atom, false); + }, [ + copyContextStoreStates, + commandMenuCloseAnimationCompleteCleanup, + pushFocusItemToFocusStack, + ]); - if (focusTitleInput) { - set( - commandMenuShouldFocusTitleInputComponentState.atomFamily({ - instanceId: computedPageId, - }), - true, - ); - } + const navigateCommandMenu = useCallback( + ({ + page, + pageTitle, + pageIcon, + pageIconColor, + pageId, + focusTitleInput = false, + resetNavigationStack = false, + }: CommandMenuNavigationStackItem & { + resetNavigationStack?: boolean; + focusTitleInput?: boolean; + }) => { + const computedPageId = pageId || v4(); - const isCommandMenuClosing = snapshot - .getLoadable(isCommandMenuClosingState) - .getValue(); + openCommandMenu(); + jotaiStore.set(commandMenuPageState.atom, page); + jotaiStore.set(commandMenuPageInfoState.atom, { + title: pageTitle, + Icon: pageIcon, + instanceId: computedPageId, + }); - const currentNavigationStack = isCommandMenuClosing - ? [] - : snapshot.getLoadable(commandMenuNavigationStackState).getValue(); + if (focusTitleInput) { + jotaiStore.set( + commandMenuShouldFocusTitleInputComponentState.atomFamily({ + instanceId: computedPageId, + }), + true, + ); + } - if (resetNavigationStack) { - set(commandMenuNavigationStackState, [ - { - page, - pageTitle, - pageIcon, - pageIconColor, - pageId: computedPageId, - }, - ]); + const isCommandMenuClosing = jotaiStore.get( + isCommandMenuClosingState.atom, + ); - set(commandMenuNavigationMorphItemsByPageState, new Map()); - } else { - set(commandMenuNavigationStackState, [ - ...currentNavigationStack, - { - page, - pageTitle, - pageIcon, - pageIconColor, - pageId: computedPageId, - }, - ]); - } - }; + const currentNavigationStack = isCommandMenuClosing + ? [] + : jotaiStore.get(commandMenuNavigationStackState.atom); + + if (resetNavigationStack) { + jotaiStore.set(commandMenuNavigationStackState.atom, [ + { + page, + pageTitle, + pageIcon, + pageIconColor, + pageId: computedPageId, + }, + ]); + + jotaiStore.set( + commandMenuNavigationMorphItemsByPageState.atom, + new Map(), + ); + } else { + jotaiStore.set(commandMenuNavigationStackState.atom, [ + ...currentNavigationStack, + { + page, + pageTitle, + pageIcon, + pageIconColor, + pageId: computedPageId, + }, + ]); + } }, [openCommandMenu], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenCalendarEventInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenCalendarEventInCommandMenu.ts index 184178d19d..5bfbbbcd97 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenCalendarEventInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenCalendarEventInCommandMenu.ts @@ -1,7 +1,8 @@ import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu'; import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconCalendarEvent } from 'twenty-ui/display'; import { v4 } from 'uuid'; @@ -9,50 +10,48 @@ import { v4 } from 'uuid'; export const useOpenCalendarEventInCommandMenu = () => { const { navigateCommandMenu } = useNavigateCommandMenu(); - const openCalendarEventInCommandMenu = useRecoilCallback( - ({ set }) => { - return (calendarEventId: string) => { - const pageComponentInstanceId = v4(); + const openCalendarEventInCommandMenu = useCallback( + (calendarEventId: string) => { + const pageComponentInstanceId = v4(); - set( - viewableRecordIdComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - calendarEventId, - ); + jotaiStore.set( + viewableRecordIdComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + calendarEventId, + ); - // TODO: Uncomment this once we need to calendar event title in the navigation - // const objectMetadataItem = snapshot - // .getLoadable(objectMetadataItemsState) - // .getValue() - // .find( - // ({ nameSingular }) => - // nameSingular === CoreObjectNameSingular.CalendarEvent, - // ); + // TODO: Uncomment this once we need to calendar event title in the navigation + // const objectMetadataItem = snapshot + // .getLoadable(objectMetadataItemsState) + // .getValue() + // .find( + // ({ nameSingular }) => + // nameSingular === CoreObjectNameSingular.CalendarEvent, + // ); - // set( - // commandMenuNavigationMorphItemsState, - // new Map([ - // ...snapshot - // .getLoadable(commandMenuNavigationMorphItemsState) - // .getValue(), - // [ - // pageComponentInstanceId, - // { - // objectMetadataId: objectMetadataItem?.id, - // recordId: calendarEventId, - // }, - // ], - // ]), - // ); + // set( + // commandMenuNavigationMorphItemsState, + // new Map([ + // ...snapshot + // .getLoadable(commandMenuNavigationMorphItemsState) + // .getValue(), + // [ + // pageComponentInstanceId, + // { + // objectMetadataId: objectMetadataItem?.id, + // recordId: calendarEventId, + // }, + // ], + // ]), + // ); - navigateCommandMenu({ - page: CommandMenuPages.ViewCalendarEvent, - pageTitle: t`Calendar Event`, - pageIcon: IconCalendarEvent, - pageId: pageComponentInstanceId, - }); - }; + navigateCommandMenu({ + page: CommandMenuPages.ViewCalendarEvent, + pageTitle: t`Calendar Event`, + pageIcon: IconCalendarEvent, + pageId: pageComponentInstanceId, + }); }, [navigateCommandMenu], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenEmailThreadInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenEmailThreadInCommandMenu.ts index 565415bf08..b76ec54757 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenEmailThreadInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenEmailThreadInCommandMenu.ts @@ -1,7 +1,8 @@ import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu'; import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconMail } from 'twenty-ui/display'; import { v4 } from 'uuid'; @@ -9,50 +10,48 @@ import { v4 } from 'uuid'; export const useOpenEmailThreadInCommandMenu = () => { const { navigateCommandMenu } = useNavigateCommandMenu(); - const openEmailThreadInCommandMenu = useRecoilCallback( - ({ set }) => { - return (emailThreadId: string) => { - const pageComponentInstanceId = v4(); + const openEmailThreadInCommandMenu = useCallback( + (emailThreadId: string) => { + const pageComponentInstanceId = v4(); - set( - viewableRecordIdComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - emailThreadId, - ); + jotaiStore.set( + viewableRecordIdComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + emailThreadId, + ); - // TODO: Uncomment this once we need to show the thread title in the navigation - // const objectMetadataItem = snapshot - // .getLoadable(objectMetadataItemsState) - // .getValue() - // .find( - // ({ nameSingular }) => - // nameSingular === CoreObjectNameSingular.MessageThread, - // ); + // TODO: Uncomment this once we need to show the thread title in the navigation + // const objectMetadataItem = snapshot + // .getLoadable(objectMetadataItemsState) + // .getValue() + // .find( + // ({ nameSingular }) => + // nameSingular === CoreObjectNameSingular.MessageThread, + // ); - // set( - // commandMenuNavigationMorphItemsState, - // new Map([ - // ...snapshot - // .getLoadable(commandMenuNavigationMorphItemsState) - // .getValue(), - // [ - // pageComponentInstanceId, - // { - // objectMetadataId: objectMetadataItem?.id, - // recordId: emailThreadId, - // }, - // ], - // ]), - // ); + // set( + // commandMenuNavigationMorphItemsState, + // new Map([ + // ...snapshot + // .getLoadable(commandMenuNavigationMorphItemsState) + // .getValue(), + // [ + // pageComponentInstanceId, + // { + // objectMetadataId: objectMetadataItem?.id, + // recordId: emailThreadId, + // }, + // ], + // ]), + // ); - navigateCommandMenu({ - page: CommandMenuPages.ViewEmailThread, - pageTitle: t`Email Thread`, - pageIcon: IconMail, - pageId: pageComponentInstanceId, - }); - }; + navigateCommandMenu({ + page: CommandMenuPages.ViewEmailThread, + pageTitle: t`Email Thread`, + pageIcon: IconMail, + pageId: pageComponentInstanceId, + }); }, [navigateCommandMenu], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenFrontComponentInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenFrontComponentInCommandMenu.ts index 22ccc914cf..5fe20b612d 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenFrontComponentInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenFrontComponentInCommandMenu.ts @@ -1,6 +1,6 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { viewableFrontComponentIdComponentState } from '@/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { CommandMenuPages } from 'twenty-shared/types'; import { type IconComponent } from 'twenty-ui/display'; import { v4 } from 'uuid'; @@ -8,38 +8,34 @@ import { v4 } from 'uuid'; export const useOpenFrontComponentInCommandMenu = () => { const { navigateCommandMenu } = useCommandMenu(); - const openFrontComponentInCommandMenu = useRecoilCallback( - ({ set }) => - ({ - frontComponentId, - pageTitle, - pageIcon, - resetNavigationStack = false, - }: { - frontComponentId: string; - pageTitle: string; - pageIcon: IconComponent; - resetNavigationStack?: boolean; - }) => { - const pageComponentInstanceId = v4(); + const openFrontComponentInCommandMenu = ({ + frontComponentId, + pageTitle, + pageIcon, + resetNavigationStack = false, + }: { + frontComponentId: string; + pageTitle: string; + pageIcon: IconComponent; + resetNavigationStack?: boolean; + }) => { + const pageComponentInstanceId = v4(); - set( - viewableFrontComponentIdComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - frontComponentId, - ); + jotaiStore.set( + viewableFrontComponentIdComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + frontComponentId, + ); - navigateCommandMenu({ - page: CommandMenuPages.ViewFrontComponent, - pageTitle, - pageIcon, - pageId: pageComponentInstanceId, - resetNavigationStack, - }); - }, - [navigateCommandMenu], - ); + navigateCommandMenu({ + page: CommandMenuPages.ViewFrontComponent, + pageTitle, + pageIcon, + pageId: pageComponentInstanceId, + resetNavigationStack, + }); + }; return { openFrontComponentInCommandMenu, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenMergeRecordsPageInCommandMenu.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useOpenMergeRecordsPageInCommandMenu.tsx index cf939c86b5..63070f41df 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenMergeRecordsPageInCommandMenu.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenMergeRecordsPageInCommandMenu.tsx @@ -6,8 +6,9 @@ import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRec import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { CommandMenuPages } from 'twenty-shared/types'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { msg, t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { IconArrowMerge } from 'twenty-ui/display'; import { v4 } from 'uuid'; @@ -39,43 +40,38 @@ export const useOpenMergeRecordsPageInCommandMenu = ({ }, }); - const openMergeRecordsPageInCommandMenu = useRecoilCallback( - ({ set }) => { - return async () => { - const pageId = v4(); + const openMergeRecordsPageInCommandMenu = useCallback(async () => { + const pageId = v4(); - set( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: pageId, - }), - objectMetadataItem.id, - ); - - await updateCommandMenuNavigationMorphItemsByPage({ - pageId, - objectMetadataId: objectMetadataItem.id, - objectRecordIds, - }); - const { records } = await findManyRecordsLazy(); - upsertRecordsInStore({ partialRecords: records ?? [] }); - - navigateCommandMenu({ - page: CommandMenuPages.MergeRecords, - pageTitle: t(msg`Merge records`), - pageIcon: IconArrowMerge, - pageId, - }); - }; - }, - [ + jotaiStore.set( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId: pageId, + }), objectMetadataItem.id, + ); + + await updateCommandMenuNavigationMorphItemsByPage({ + pageId, + objectMetadataId: objectMetadataItem.id, objectRecordIds, - findManyRecordsLazy, - upsertRecordsInStore, - navigateCommandMenu, - updateCommandMenuNavigationMorphItemsByPage, - ], - ); + }); + const { records } = await findManyRecordsLazy(); + upsertRecordsInStore({ partialRecords: records ?? [] }); + + navigateCommandMenu({ + page: CommandMenuPages.MergeRecords, + pageTitle: t(msg`Merge records`), + pageIcon: IconArrowMerge, + pageId, + }); + }, [ + objectMetadataItem.id, + objectRecordIds, + findManyRecordsLazy, + upsertRecordsInStore, + navigateCommandMenu, + updateCommandMenuNavigationMorphItemsByPage, + ]); return { openMergeRecordsPageInCommandMenu, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts index c394bc072d..bcd32e808a 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts @@ -15,14 +15,13 @@ import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objec import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { CommandMenuPages } from 'twenty-shared/types'; import { useRunWorkflowRunOpeningInCommandMenuSideEffects } from '@/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects'; import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; import { v4 } from 'uuid'; @@ -35,168 +34,163 @@ export const useOpenRecordInCommandMenu = () => { const { runWorkflowRunOpeningInCommandMenuSideEffects } = useRunWorkflowRunOpeningInCommandMenuSideEffects(); - const openRecordInCommandMenu = useRecoilCallback( - ({ set, snapshot }) => { - return ({ - recordId, - objectNameSingular, - isNewRecord = false, - resetNavigationStack = false, - }: { - recordId: string; - objectNameSingular: string; - isNewRecord?: boolean; - resetNavigationStack?: boolean; - }) => { - const navigationStack = getSnapshotValue( - snapshot, - commandMenuNavigationStackState, - ); + const openRecordInCommandMenu = useCallback( + ({ + recordId, + objectNameSingular, + isNewRecord = false, + resetNavigationStack = false, + }: { + recordId: string; + objectNameSingular: string; + isNewRecord?: boolean; + resetNavigationStack?: boolean; + }) => { + const navigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); - const currentNavigationStackItem = navigationStack.at(-1); + const currentNavigationStackItem = navigationStack.at(-1); - if (isDefined(currentNavigationStackItem)) { - const currentRecordId = getSnapshotValue( - snapshot, - viewableRecordIdComponentState.atomFamily({ - instanceId: currentNavigationStackItem.pageId, - }), - ); - - if (currentRecordId === recordId) { - return; - } - } - - const pageComponentInstanceId = v4(); - - set( - viewableRecordNameSingularComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - objectNameSingular, - ); - set( + if (isDefined(currentNavigationStackItem)) { + const currentRecordId = jotaiStore.get( viewableRecordIdComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - recordId, - ); - set(viewableRecordIdState, recordId); - - const objectMetadataItem = jotaiStore.get( - objectMetadataItemFamilySelector.selectorFamily({ - objectName: objectNameSingular, - objectNameType: 'singular', + instanceId: currentNavigationStackItem.pageId, }), ); - if (!objectMetadataItem) { - throw new Error( - `No object metadata item found for object name ${objectNameSingular}`, - ); + if (currentRecordId === recordId) { + return; } + } - set( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - objectMetadataItem.id, + const pageComponentInstanceId = v4(); + + jotaiStore.set( + viewableRecordNameSingularComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + objectNameSingular, + ); + jotaiStore.set( + viewableRecordIdComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + recordId, + ); + jotaiStore.set(viewableRecordIdState.atom, recordId); + + const objectMetadataItem = jotaiStore.get( + objectMetadataItemFamilySelector.selectorFamily({ + objectName: objectNameSingular, + objectNameType: 'singular', + }), + ); + + if (!objectMetadataItem) { + throw new Error( + `No object metadata item found for object name ${objectNameSingular}`, ); + } - set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - { - mode: 'selection', - selectedRecordIds: [recordId], - }, - ); + jotaiStore.set( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + objectMetadataItem.id, + ); - set( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - 1, - ); + jotaiStore.set( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + { + mode: 'selection', + selectedRecordIds: [recordId], + }, + ); - set( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: pageComponentInstanceId, - }), - ContextStoreViewType.ShowPage, - ); + jotaiStore.set( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + 1, + ); - set( + jotaiStore.set( + contextStoreCurrentViewTypeComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + ContextStoreViewType.ShowPage, + ); + + jotaiStore.set( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + jotaiStore.get( contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: pageComponentInstanceId, + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, }), - snapshot - .getLoadable( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, - }), - ) - .getValue(), - ); + ), + ); - set( + jotaiStore.set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + jotaiStore.get( contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: pageComponentInstanceId, + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, }), - snapshot - .getLoadable( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, - }), - ) - .getValue(), - ); + ), + ); - const currentMorphItems = snapshot - .getLoadable(commandMenuNavigationMorphItemsByPageState) - .getValue(); + const currentMorphItems = jotaiStore.get( + commandMenuNavigationMorphItemsByPageState.atom, + ); - const morphItemToAdd = { - objectMetadataId: objectMetadataItem.id, - recordId, - }; - - const newMorphItemsMap = new Map(currentMorphItems); - newMorphItemsMap.set(pageComponentInstanceId, [morphItemToAdd]); - - set(commandMenuNavigationMorphItemsByPageState, newMorphItemsMap); - - const Icon = objectMetadataItem?.icon - ? getIcon(objectMetadataItem.icon) - : getIcon('IconList'); - - const IconColor = getIconColorForObjectType({ - objectType: objectMetadataItem.nameSingular, - theme, - }); - - const objectLabelSingular = objectMetadataItem.labelSingular; - - navigateCommandMenu({ - page: CommandMenuPages.ViewRecord, - pageTitle: isNewRecord - ? t`New ${objectLabelSingular}` - : objectLabelSingular, - pageIcon: Icon, - pageIconColor: IconColor, - pageId: pageComponentInstanceId, - resetNavigationStack, - }); - - if (objectNameSingular === CoreObjectNameSingular.WorkflowRun) { - runWorkflowRunOpeningInCommandMenuSideEffects({ - objectMetadataItem, - recordId, - }); - } + const morphItemToAdd = { + objectMetadataId: objectMetadataItem.id, + recordId, }; + + const newMorphItemsMap = new Map(currentMorphItems); + newMorphItemsMap.set(pageComponentInstanceId, [morphItemToAdd]); + + jotaiStore.set( + commandMenuNavigationMorphItemsByPageState.atom, + newMorphItemsMap, + ); + + const Icon = objectMetadataItem?.icon + ? getIcon(objectMetadataItem.icon) + : getIcon('IconList'); + + const IconColor = getIconColorForObjectType({ + objectType: objectMetadataItem.nameSingular, + theme, + }); + + const objectLabelSingular = objectMetadataItem.labelSingular; + + navigateCommandMenu({ + page: CommandMenuPages.ViewRecord, + pageTitle: isNewRecord + ? t`New ${objectLabelSingular}` + : objectLabelSingular, + pageIcon: Icon, + pageIconColor: IconColor, + pageId: pageComponentInstanceId, + resetNavigationStack, + }); + + if (objectNameSingular === CoreObjectNameSingular.WorkflowRun) { + runWorkflowRunOpeningInCommandMenuSideEffects({ + objectMetadataItem, + recordId, + }); + } }, [ getIcon, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenUpdateMultipleRecordsPageInCommandMenu.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useOpenUpdateMultipleRecordsPageInCommandMenu.tsx index bfbfaa9a8d..71b998a247 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenUpdateMultipleRecordsPageInCommandMenu.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenUpdateMultipleRecordsPageInCommandMenu.tsx @@ -2,7 +2,7 @@ import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandM import { CommandMenuPages } from 'twenty-shared/types'; import { msg, t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { IconBoxMultiple } from 'twenty-ui/display'; type UseOpenUpdateMultipleRecordsPageInCommandMenuProps = { @@ -14,15 +14,13 @@ export const useOpenUpdateMultipleRecordsPageInCommandMenu = ({ }: UseOpenUpdateMultipleRecordsPageInCommandMenuProps) => { const { navigateCommandMenu } = useNavigateCommandMenu(); - const openUpdateMultipleRecordsPageInCommandMenu = useRecoilCallback(() => { - return async () => { - navigateCommandMenu({ - page: CommandMenuPages.UpdateRecords, - pageTitle: t(msg`Update records`), - pageIcon: IconBoxMultiple, - pageId: contextStoreInstanceId, - }); - }; + const openUpdateMultipleRecordsPageInCommandMenu = useCallback(async () => { + navigateCommandMenu({ + page: CommandMenuPages.UpdateRecords, + pageTitle: t(msg`Update records`), + pageIcon: IconBoxMultiple, + pageId: contextStoreInstanceId, + }); }, [navigateCommandMenu, contextStoreInstanceId]); return { diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts b/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts index d2b550a04e..c2556772fb 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts @@ -5,63 +5,62 @@ import { contextStoreFilterGroupsComponentState } from '@/context-store/states/c import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useResetContextStoreStates = () => { - const resetContextStoreStates = useRecoilCallback(({ set }) => { - return (instanceId: string) => { - set( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId, - }), - undefined, - ); + const resetContextStoreStates = useCallback((instanceId: string) => { + jotaiStore.set( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId, + }), + undefined, + ); - set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId, - }), - { - mode: 'selection', - selectedRecordIds: [], - }, - ); + jotaiStore.set( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId, + }), + { + mode: 'selection', + selectedRecordIds: [], + }, + ); - set( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId, - }), - 0, - ); + jotaiStore.set( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId, + }), + 0, + ); - set( - contextStoreFiltersComponentState.atomFamily({ - instanceId, - }), - [], - ); + jotaiStore.set( + contextStoreFiltersComponentState.atomFamily({ + instanceId, + }), + [], + ); - set( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId, - }), - [], - ); + jotaiStore.set( + contextStoreFilterGroupsComponentState.atomFamily({ + instanceId, + }), + [], + ); - set( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId, - }), - '', - ); + jotaiStore.set( + contextStoreAnyFieldFilterValueComponentState.atomFamily({ + instanceId, + }), + '', + ); - set( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId, - }), - undefined, - ); - }; + jotaiStore.set( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId, + }), + undefined, + ); }, []); return { resetContextStoreStates }; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts b/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts index a405969bf3..cd37a19a80 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts @@ -10,75 +10,71 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useSetGlobalCommandMenuContext = () => { const { copyContextStoreStates } = useCopyContextStoreStates(); - const setGlobalCommandMenuContext = useRecoilCallback( - ({ set }) => { - return () => { - copyContextStoreStates({ - instanceIdToCopyFrom: COMMAND_MENU_COMPONENT_INSTANCE_ID, - instanceIdToCopyTo: COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID, - }); + const setGlobalCommandMenuContext = useCallback(() => { + copyContextStoreStates({ + instanceIdToCopyFrom: COMMAND_MENU_COMPONENT_INSTANCE_ID, + instanceIdToCopyTo: COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID, + }); - set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - { - mode: 'selection', - selectedRecordIds: [], - }, - ); + jotaiStore.set( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + { + mode: 'selection', + selectedRecordIds: [], + }, + ); - set( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - 0, - ); + jotaiStore.set( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + 0, + ); - set( - contextStoreFiltersComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - [], - ); + jotaiStore.set( + contextStoreFiltersComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + [], + ); - set( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - [], - ); + jotaiStore.set( + contextStoreFilterGroupsComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + [], + ); - set( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - '', - ); + jotaiStore.set( + contextStoreAnyFieldFilterValueComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + '', + ); - set( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - ContextStoreViewType.Table, - ); + jotaiStore.set( + contextStoreCurrentViewTypeComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + ContextStoreViewType.Table, + ); - set(commandMenuPageInfoState, { - title: undefined, - Icon: undefined, - instanceId: '', - }); + jotaiStore.set(commandMenuPageInfoState.atom, { + title: undefined, + Icon: undefined, + instanceId: '', + }); - set(hasUserSelectedCommandState, false); - }; - }, - [copyContextStoreStates], - ); + jotaiStore.set(hasUserSelectedCommandState.atom, false); + }, [copyContextStoreStates]); return { setGlobalCommandMenuContext, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts b/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts index 22b9d0cf71..8d0775460b 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts @@ -1,53 +1,54 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; import { type IconComponent, IconDotsVertical } from 'twenty-ui/display'; export const useUpdateCommandMenuPageInfo = () => { - const updateCommandMenuPageInfo = useRecoilCallback( - ({ snapshot, set }) => - ({ - pageTitle, - pageIcon, - }: { - pageTitle?: string; - pageIcon?: IconComponent; - }) => { - const commandMenuPageInfo = snapshot - .getLoadable(commandMenuPageInfoState) - .getValue(); + const updateCommandMenuPageInfo = useCallback( + ({ + pageTitle, + pageIcon, + }: { + pageTitle?: string; + pageIcon?: IconComponent; + }) => { + const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom); - const newCommandMenuPageInfo = { - ...commandMenuPageInfo, - title: pageTitle ?? commandMenuPageInfo.title ?? '', - Icon: pageIcon ?? commandMenuPageInfo.Icon ?? IconDotsVertical, - }; + const newCommandMenuPageInfo = { + ...commandMenuPageInfo, + title: pageTitle ?? commandMenuPageInfo.title ?? '', + Icon: pageIcon ?? commandMenuPageInfo.Icon ?? IconDotsVertical, + }; - set(commandMenuPageInfoState, newCommandMenuPageInfo); + jotaiStore.set(commandMenuPageInfoState.atom, newCommandMenuPageInfo); - const commandMenuNavigationStack = snapshot - .getLoadable(commandMenuNavigationStackState) - .getValue(); + const commandMenuNavigationStack = jotaiStore.get( + commandMenuNavigationStackState.atom, + ); - const lastCommandMenuNavigationStackItem = - commandMenuNavigationStack.at(-1); + const lastCommandMenuNavigationStackItem = + commandMenuNavigationStack.at(-1); - if (!lastCommandMenuNavigationStackItem) { - return; - } + if (!lastCommandMenuNavigationStackItem) { + return; + } - const newCommandMenuNavigationStack = [ - ...commandMenuNavigationStack.slice(0, -1), - { - page: lastCommandMenuNavigationStackItem.page, - pageTitle: newCommandMenuPageInfo.title, - pageIcon: newCommandMenuPageInfo.Icon, - pageId: lastCommandMenuNavigationStackItem.pageId, - }, - ]; + const newCommandMenuNavigationStack = [ + ...commandMenuNavigationStack.slice(0, -1), + { + page: lastCommandMenuNavigationStackItem.page, + pageTitle: newCommandMenuPageInfo.title, + pageIcon: newCommandMenuPageInfo.Icon, + pageId: lastCommandMenuNavigationStackItem.pageId, + }, + ]; - set(commandMenuNavigationStackState, newCommandMenuNavigationStack); - }, + jotaiStore.set( + commandMenuNavigationStackState.atom, + newCommandMenuNavigationStack, + ); + }, [], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts index c3d1f27a24..ef58a0587f 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts @@ -3,11 +3,12 @@ import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workfl import { commandMenuWorkflowRunIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState'; import { commandMenuWorkflowStepIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowStepIdComponentState'; import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type WorkflowRunStepStatus } from '@/workflow/types/Workflow'; import { useSetInitialWorkflowRunRightDrawerTab } from '@/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { @@ -22,233 +23,221 @@ export const useWorkflowCommandMenu = () => { const { setInitialWorkflowRunRightDrawerTab } = useSetInitialWorkflowRunRightDrawerTab(); - const openWorkflowTriggerTypeInCommandMenu = useRecoilCallback( - ({ set }) => { - return (workflowId: string) => { - const pageId = v4(); + const openWorkflowTriggerTypeInCommandMenu = useCallback( + (workflowId: string) => { + const pageId = v4(); - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowId, - ); - - navigateCommandMenu({ - page: CommandMenuPages.WorkflowTriggerSelectType, - pageTitle: t`Trigger Type`, - pageIcon: IconBolt, - pageId, - }); - }; - }, - [navigateCommandMenu], - ); - - const openWorkflowCreateStepInCommandMenu = useRecoilCallback( - ({ set }) => { - return (workflowId: string) => { - const pageId = v4(); - - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowId, - ); - - navigateCommandMenu({ - page: CommandMenuPages.WorkflowStepCreate, - pageTitle: t`Select Action`, - pageIcon: IconSettingsAutomation, - pageId, - }); - }; - }, - [navigateCommandMenu], - ); - - const openWorkflowEditStepInCommandMenu = useRecoilCallback( - ({ set }) => { - return ( - workflowId: string, - title: string, - icon: IconComponent, - stepId?: string, - ) => { - const pageId = v4(); - - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowId, - ); - - if (isDefined(stepId)) { - set( - commandMenuWorkflowStepIdComponentState.atomFamily({ - instanceId: pageId, - }), - stepId, - ); - - set( - workflowSelectedNodeComponentState.atomFamily({ - instanceId: workflowId, - }), - stepId, - ); - } - - navigateCommandMenu({ - page: CommandMenuPages.WorkflowStepEdit, - pageTitle: title, - pageIcon: icon, - pageId, - }); - }; - }, - [navigateCommandMenu], - ); - - const openWorkflowEditStepTypeInCommandMenu = useRecoilCallback( - ({ set }) => { - return (workflowId: string) => { - const pageId = v4(); - - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowId, - ); - - navigateCommandMenu({ - page: CommandMenuPages.WorkflowStepEditType, - pageTitle: t`Select action`, - pageIcon: IconSettingsAutomation, - pageId, - }); - }; - }, - [navigateCommandMenu], - ); - - const openWorkflowViewStepInCommandMenu = useRecoilCallback( - ({ set }) => { - return ({ + jotaiStore.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: pageId, + }), workflowId, - workflowVersionId, - title, - icon, - stepId, - }: { - workflowId: string; - workflowVersionId: string; - title: string; - icon: IconComponent; - stepId?: string; - }) => { - const pageId = v4(); + ); - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowId, - ); - set( - commandMenuWorkflowVersionIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowVersionId, - ); - - if (isDefined(stepId)) { - set( - commandMenuWorkflowStepIdComponentState.atomFamily({ - instanceId: pageId, - }), - stepId, - ); - - set( - workflowSelectedNodeComponentState.atomFamily({ - instanceId: workflowVersionId, - }), - stepId, - ); - } - - navigateCommandMenu({ - page: CommandMenuPages.WorkflowStepView, - pageTitle: title, - pageIcon: icon, - pageId, - }); - }; + navigateCommandMenu({ + page: CommandMenuPages.WorkflowTriggerSelectType, + pageTitle: t`Trigger Type`, + pageIcon: IconBolt, + pageId, + }); }, [navigateCommandMenu], ); - const openWorkflowRunViewStepInCommandMenu = useRecoilCallback( - ({ set }) => { - return ({ - workflowId, - workflowRunId, - title, - icon, - workflowSelectedNode, - stepExecutionStatus, - }: { - workflowId: string; - workflowRunId: string; - title: string; - icon: IconComponent; - workflowSelectedNode: string; - stepExecutionStatus: WorkflowRunStepStatus; - }) => { - const pageId = v4(); + const openWorkflowCreateStepInCommandMenu = useCallback( + (workflowId: string) => { + const pageId = v4(); - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowId, - ); - set( - commandMenuWorkflowRunIdComponentState.atomFamily({ - instanceId: pageId, - }), - workflowRunId, - ); - set( + jotaiStore.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowId, + ); + + navigateCommandMenu({ + page: CommandMenuPages.WorkflowStepCreate, + pageTitle: t`Select Action`, + pageIcon: IconSettingsAutomation, + pageId, + }); + }, + [navigateCommandMenu], + ); + + const openWorkflowEditStepInCommandMenu = useCallback( + ( + workflowId: string, + title: string, + icon: IconComponent, + stepId?: string, + ) => { + const pageId = v4(); + + jotaiStore.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowId, + ); + + if (isDefined(stepId)) { + jotaiStore.set( commandMenuWorkflowStepIdComponentState.atomFamily({ instanceId: pageId, }), - workflowSelectedNode, + stepId, ); - set( + jotaiStore.set( workflowSelectedNodeComponentState.atomFamily({ - instanceId: workflowRunId, + instanceId: workflowId, }), - workflowSelectedNode, + stepId, + ); + } + + navigateCommandMenu({ + page: CommandMenuPages.WorkflowStepEdit, + pageTitle: title, + pageIcon: icon, + pageId, + }); + }, + [navigateCommandMenu], + ); + + const openWorkflowEditStepTypeInCommandMenu = useCallback( + (workflowId: string) => { + const pageId = v4(); + + jotaiStore.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowId, + ); + + navigateCommandMenu({ + page: CommandMenuPages.WorkflowStepEditType, + pageTitle: t`Select action`, + pageIcon: IconSettingsAutomation, + pageId, + }); + }, + [navigateCommandMenu], + ); + + const openWorkflowViewStepInCommandMenu = useCallback( + ({ + workflowId, + workflowVersionId, + title, + icon, + stepId, + }: { + workflowId: string; + workflowVersionId: string; + title: string; + icon: IconComponent; + stepId?: string; + }) => { + const pageId = v4(); + + jotaiStore.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowId, + ); + jotaiStore.set( + commandMenuWorkflowVersionIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowVersionId, + ); + + if (isDefined(stepId)) { + jotaiStore.set( + commandMenuWorkflowStepIdComponentState.atomFamily({ + instanceId: pageId, + }), + stepId, ); - navigateCommandMenu({ - page: CommandMenuPages.WorkflowRunStepView, - pageTitle: title, - pageIcon: icon, - pageId, - }); + jotaiStore.set( + workflowSelectedNodeComponentState.atomFamily({ + instanceId: workflowVersionId, + }), + stepId, + ); + } - setInitialWorkflowRunRightDrawerTab({ - workflowSelectedNode, - stepExecutionStatus, - }); - }; + navigateCommandMenu({ + page: CommandMenuPages.WorkflowStepView, + pageTitle: title, + pageIcon: icon, + pageId, + }); + }, + [navigateCommandMenu], + ); + + const openWorkflowRunViewStepInCommandMenu = useCallback( + ({ + workflowId, + workflowRunId, + title, + icon, + workflowSelectedNode, + stepExecutionStatus, + }: { + workflowId: string; + workflowRunId: string; + title: string; + icon: IconComponent; + workflowSelectedNode: string; + stepExecutionStatus: WorkflowRunStepStatus; + }) => { + const pageId = v4(); + + jotaiStore.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowId, + ); + jotaiStore.set( + commandMenuWorkflowRunIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowRunId, + ); + jotaiStore.set( + commandMenuWorkflowStepIdComponentState.atomFamily({ + instanceId: pageId, + }), + workflowSelectedNode, + ); + + jotaiStore.set( + workflowSelectedNodeComponentState.atomFamily({ + instanceId: workflowRunId, + }), + workflowSelectedNode, + ); + + navigateCommandMenu({ + page: CommandMenuPages.WorkflowRunStepView, + pageTitle: title, + pageIcon: icon, + pageId, + }); + + setInitialWorkflowRunRightDrawerTab({ + workflowSelectedNode, + stepExecutionStatus, + }); }, [navigateCommandMenu, setInitialWorkflowRunRightDrawerTab], ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/calendar-event/components/CommandMenuCalendarEventPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/calendar-event/components/CommandMenuCalendarEventPage.tsx index 0f4f411145..fbe503c137 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/calendar-event/components/CommandMenuCalendarEventPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/calendar-event/components/CommandMenuCalendarEventPage.tsx @@ -7,12 +7,12 @@ import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graph import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { PageLayoutType } from '~/generated-metadata/graphql'; export const CommandMenuCalendarEventPage = () => { const { upsertRecordsInStore } = useUpsertRecordsInStore(); - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/front-component/components/CommandMenuFrontComponentPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/front-component/components/CommandMenuFrontComponentPage.tsx index e24a651ade..ef4dabf8b6 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/front-component/components/CommandMenuFrontComponentPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/front-component/components/CommandMenuFrontComponentPage.tsx @@ -1,7 +1,7 @@ import { Suspense, lazy } from 'react'; import { viewableFrontComponentIdComponentState } from '@/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; const FrontComponentRenderer = lazy(() => @@ -11,7 +11,7 @@ const FrontComponentRenderer = lazy(() => ); export const CommandMenuFrontComponentPage = () => { - const viewableFrontComponentId = useRecoilComponentValue( + const viewableFrontComponentId = useRecoilComponentValueV2( viewableFrontComponentIdComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState.ts index 2cbb88ef3e..5f1b59b1d8 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState.ts @@ -1,7 +1,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const viewableFrontComponentIdComponentState = createComponentState< +export const viewableFrontComponentIdComponentState = createComponentStateV2< string | null >({ key: 'command-menu/viewable-front-component-id', diff --git a/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx index 62f97c0cbd..9f8be75e90 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx @@ -8,7 +8,7 @@ import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMe import { CommandMenuMessageThreadIntermediaryMessages } from '@/command-menu/pages/message-thread/components/CommandMenuMessageThreadIntermediaryMessages'; import { useEmailThreadInCommandMenu } from '@/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu'; import { messageThreadComponentState } from '@/command-menu/pages/message-thread/states/messageThreadComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { t } from '@lingui/core/macro'; import { ConnectedAccountProvider } from 'twenty-shared/types'; import { assertUnreachable, isDefined } from 'twenty-shared/utils'; @@ -47,7 +47,7 @@ const ALLOWED_REPLY_PROVIDERS = [ ]; export const CommandMenuMessageThreadPage = () => { - const setMessageThread = useSetRecoilComponentState( + const setMessageThread = useSetRecoilComponentStateV2( messageThreadComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/__tests__/useEmailThreadInCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/__tests__/useEmailThreadInCommandMenu.test.tsx index 197019a199..568e9b33c2 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/__tests__/useEmailThreadInCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/__tests__/useEmailThreadInCommandMenu.test.tsx @@ -366,8 +366,8 @@ const mocks = [ const Wrapper = ({ children }: { children: React.ReactNode }) => { const MetadataWrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks: mocks, - onInitializeRecoilSnapshot: ({ set }) => { - set( + onInitializeJotaiStore: (store) => { + store.set( viewableRecordIdComponentState.atomFamily({ instanceId: 'test-instance', }), diff --git a/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu.ts index e2bb0d9bab..95ef8e4d0a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu.ts @@ -13,13 +13,13 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { MessageParticipantRole } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; // to improve - https://github.com/twentyhq/twenty/issues/12190 export const useEmailThreadInCommandMenu = () => { - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, ); const { upsertRecordsInStore } = useUpsertRecordsInStore(); diff --git a/packages/twenty-front/src/modules/command-menu/pages/message-thread/states/messageThreadComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/message-thread/states/messageThreadComponentState.ts index c41c8b9f51..357b9a224a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/message-thread/states/messageThreadComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/message-thread/states/messageThreadComponentState.ts @@ -1,9 +1,9 @@ import { type MessageThread } from '@/activities/emails/types/MessageThread'; import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const messageThreadComponentState = - createComponentState({ + createComponentStateV2({ key: 'messageThreadComponentState', defaultValue: null, componentInstanceContext: CommandMenuPageComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx index 9a83ee7132..93dc448c4c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx @@ -14,11 +14,10 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record- import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { InputLabel } from '@/ui/input/components/InputLabel'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; const StyledChartFiltersPageContainer = styled.div` display: flex; @@ -50,49 +49,33 @@ export const ChartFiltersSettings = ({ const { updateCurrentWidgetConfig } = useUpdateCurrentWidgetConfig(pageLayoutId); - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( + const currentRecordFiltersAtom = useRecoilComponentStateCallbackStateV2( currentRecordFiltersComponentState, instanceId, ); - const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState( - currentRecordFilterGroupsComponentState, - instanceId, - ); + const currentRecordFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + instanceId, + ); + const store = useStore(); const chartWidgetConfiguration = widget.configuration; - const handleFiltersUpdate = useRecoilCallback( - ({ snapshot }) => - () => { - const currentRecordFilters = getSnapshotValue( - snapshot, - currentRecordFiltersCallbackState, - ); + const handleFiltersUpdate = () => { + const currentRecordFilters = store.get(currentRecordFiltersAtom); + const currentRecordFilterGroups = store.get(currentRecordFilterGroupsAtom); - const currentRecordFilterGroups = getSnapshotValue( - snapshot, - currentRecordFilterGroupsCallbackState, - ); - - updateCurrentWidgetConfig({ - objectMetadataId: objectMetadataItem.id, - configToUpdate: { - filter: { - recordFilters: currentRecordFilters, - recordFilterGroups: currentRecordFilterGroups, - }, - } satisfies Partial, - }); - }, - [ - currentRecordFiltersCallbackState, - currentRecordFilterGroupsCallbackState, - objectMetadataItem, - updateCurrentWidgetConfig, - ], - ); + updateCurrentWidgetConfig({ + objectMetadataId: objectMetadataItem.id, + configToUpdate: { + filter: { + recordFilters: currentRecordFilters, + recordFilterGroups: currentRecordFilterGroups, + }, + } satisfies Partial, + }); + }; return ( <> diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettingsInitializeStateEffect.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettingsInitializeStateEffect.tsx index 1004fd56f0..daf313f493 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettingsInitializeStateEffect.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettingsInitializeStateEffect.tsx @@ -3,8 +3,8 @@ import { type ChartFilters } from '@/command-menu/pages/page-layout/types/ChartF import { useSetAdvancedFilterDropdownStates } from '@/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -16,13 +16,13 @@ export const ChartFiltersSettingsInitializeStateEffect = ({ initialChartFilters, }: ChartFiltersSettingsInitializeStateEffectProps) => { const [hasInitializedChartFilters, setHasInitializedChartFilters] = - useRecoilComponentState(hasInitializedChartFiltersComponentState); + useRecoilComponentStateV2(hasInitializedChartFiltersComponentState); - const setCurrentRecordFilters = useSetRecoilComponentState( + const setCurrentRecordFilters = useSetRecoilComponentStateV2( currentRecordFiltersComponentState, ); - const setCurrentRecordFilterGroups = useSetRecoilComponentState( + const setCurrentRecordFilterGroups = useSetRecoilComponentStateV2( currentRecordFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx index 9ddf4d5ecd..f463571987 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx @@ -14,7 +14,7 @@ import { CHART_CONFIGURATION_SETTING_IDS } from '@/command-menu/pages/page-layou import { shouldHideChartSetting } from '@/command-menu/pages/page-layout/utils/shouldHideChartSetting'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { hasWidgetTooManyGroupsComponentState } from '@/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { isFieldMetadataDateKind } from 'twenty-shared/utils'; @@ -58,7 +58,7 @@ export const ChartSettings = ({ widget }: { widget: PageLayoutWidget }) => { CHART_CONFIGURATION_SETTING_IDS.GROUP_BY, ); const [hasWidgetTooManyGroups, setHasWidgetTooManyGroups] = - useRecoilComponentState(hasWidgetTooManyGroupsComponentState); + useRecoilComponentStateV2(hasWidgetTooManyGroupsComponentState); const handleGraphTypeChange = (graphType: GraphType) => { const configToUpdate = getConfigToUpdateAfterGraphTypeChange(graphType); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx index 817d9e3626..6cf4703a06 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx @@ -5,7 +5,7 @@ import { isChartWidget } from '@/command-menu/pages/page-layout/utils/isChartWid import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -18,12 +18,12 @@ const StyledContainer = styled.div` export const CommandMenuPageLayoutChartSettings = () => { const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord(); - const draftPageLayout = useRecoilComponentValue( + const draftPageLayout = useRecoilComponentValueV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutEditingWidgetId = useRecoilComponentValue( + const pageLayoutEditingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx index e50bc7a210..b8125f70e0 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx @@ -4,19 +4,19 @@ import { isChartWidget } from '@/command-menu/pages/page-layout/utils/isChartWid import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; export const CommandMenuPageLayoutGraphFilter = () => { const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord(); - const draftPageLayout = useRecoilComponentValue( + const draftPageLayout = useRecoilComponentValueV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutEditingWidgetId = useRecoilComponentValue( + const pageLayoutEditingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutTabSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutTabSettings.tsx index 45ed8d344a..4a6f0d730f 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutTabSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutTabSettings.tsx @@ -11,8 +11,8 @@ import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDr import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { @@ -26,12 +26,12 @@ export const CommandMenuPageLayoutTabSettings = () => { const { closeCommandMenu } = useCommandMenu(); const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord(); - const draft = useRecoilComponentValue( + const draft = useRecoilComponentValueV2( pageLayoutDraftComponentState, pageLayoutId, ); - const [openTabId, setOpenTabId] = useRecoilComponentState( + const [openTabId, setOpenTabId] = useRecoilComponentStateV2( pageLayoutTabSettingsOpenTabIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect.tsx index d47b65d5b7..7b84b11a1e 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect.tsx @@ -16,8 +16,8 @@ import { useRemovePageLayoutWidgetAndPreservePosition } from '@/page-layout/hook import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useQuery } from '@apollo/client'; import { t } from '@lingui/core/macro'; @@ -79,12 +79,12 @@ export const CommandMenuPageLayoutWidgetTypeSelect = () => { ); const [pageLayoutEditingWidgetId, setPageLayoutEditingWidgetId] = - useRecoilComponentState( + useRecoilComponentStateV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); - const draftPageLayout = useRecoilComponentValue( + const draftPageLayout = useRecoilComponentValueV2( pageLayoutDraftComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/WidgetSettingsFooter.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/WidgetSettingsFooter.tsx index 24d254a51b..6f6f52f935 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/WidgetSettingsFooter.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/WidgetSettingsFooter.tsx @@ -6,7 +6,6 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useLingui } from '@lingui/react/macro'; import { useId } from 'react'; @@ -24,7 +23,7 @@ export const WidgetSettingsFooter = ({ const { closeDropdown } = useCloseDropdown(); const { duplicateWidget } = useDuplicatePageLayoutWidget(pageLayoutId); const { deletePageLayoutWidget } = useDeletePageLayoutWidget(pageLayoutId); - const editingWidgetId = useRecoilComponentValue( + const editingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu.ts index 43ca9b0945..9461644602 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu.ts @@ -2,7 +2,7 @@ import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandM import { type PageLayoutCommandMenuPage } from '@/command-menu/pages/page-layout/types/PageLayoutCommandMenuPage'; import { getPageLayoutIcon } from '@/command-menu/pages/page-layout/utils/getPageLayoutIcon'; import { getPageLayoutPageTitle } from '@/command-menu/pages/page-layout/utils/getPageLayoutPageTitle'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type IconComponent } from 'twenty-ui/display'; @@ -17,8 +17,8 @@ type NavigatePageLayoutCommandMenuProps = { export const useNavigatePageLayoutCommandMenu = () => { const { navigateCommandMenu } = useNavigateCommandMenu(); - const navigatePageLayoutCommandMenu = useRecoilCallback(() => { - return ({ + const navigatePageLayoutCommandMenu = useCallback( + ({ commandMenuPage, pageTitle, pageIcon, @@ -36,8 +36,9 @@ export const useNavigatePageLayoutCommandMenu = () => { focusTitleInput, resetNavigationStack, }); - }; - }, [navigateCommandMenu]); + }, + [navigateCommandMenu], + ); return { navigatePageLayoutCommandMenu, diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord.ts index eee8685cb4..557a933d7a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord.ts @@ -1,10 +1,10 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const usePageLayoutIdFromContextStoreTargetedRecord = () => { - const targetedRecordsRule = useRecoilComponentValue( + const targetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, ); @@ -19,7 +19,7 @@ export const usePageLayoutIdFromContextStoreTargetedRecord = () => { const recordId: string = targetedRecordsRule.selectedRecordIds[0]; - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); return { pageLayoutId: record?.pageLayoutId }; }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord.ts index a7b7bae016..1624ad0103 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord.ts @@ -2,16 +2,16 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { useRecordPageLayoutIdFromRecordStoreOrThrow } from '@/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord = () => { - const targetedRecordsRule = useRecoilComponentValue( + const targetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, ); - const objectMetadataId = useRecoilComponentValue( + const objectMetadataId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useResetChartDraftFiltersSettings.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useResetChartDraftFiltersSettings.ts index 5457484401..e1d9cb3ac8 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useResetChartDraftFiltersSettings.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useResetChartDraftFiltersSettings.ts @@ -5,7 +5,8 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record- import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { hasInitializedCurrentRecordFilterGroupsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState'; import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useResetChartDraftFiltersSettings = () => { @@ -13,42 +14,42 @@ export const useResetChartDraftFiltersSettings = () => { const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId); - const resetChartDraftFiltersSettings = useRecoilCallback( - ({ set }) => - (objectMetadataItemId: string) => { - if (!isDefined(widgetInEditMode)) { - return; - } + const resetChartDraftFiltersSettings = useCallback( + (objectMetadataItemId: string) => { + if (!isDefined(widgetInEditMode)) { + return; + } - const { instanceId } = getChartFiltersSettingsInstanceId({ - widgetId: widgetInEditMode.id, - objectMetadataItemId: objectMetadataItemId, - }); + const { instanceId } = getChartFiltersSettingsInstanceId({ + widgetId: widgetInEditMode.id, + objectMetadataItemId: objectMetadataItemId, + }); - set( - hasInitializedCurrentRecordFilterGroupsComponentFamilyState.atomFamily( - { - familyKey: {}, - instanceId, - }, - ), - false, - ); + jotaiStore.set( + hasInitializedCurrentRecordFilterGroupsComponentFamilyState.atomFamily({ + familyKey: {}, + instanceId, + }), + false, + ); - set( - hasInitializedCurrentRecordFiltersComponentFamilyState.atomFamily({ - familyKey: {}, - instanceId, - }), - false, - ); + jotaiStore.set( + hasInitializedCurrentRecordFiltersComponentFamilyState.atomFamily({ + familyKey: {}, + instanceId, + }), + false, + ); - set(currentRecordFiltersComponentState.atomFamily({ instanceId }), []); - set( - currentRecordFilterGroupsComponentState.atomFamily({ instanceId }), - [], - ); - }, + jotaiStore.set( + currentRecordFiltersComponentState.atomFamily({ instanceId }), + [], + ); + jotaiStore.set( + currentRecordFilterGroupsComponentState.atomFamily({ instanceId }), + [], + ); + }, [widgetInEditMode], ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig.ts index 4c20fc28f6..63630dc614 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateCurrentWidgetConfig.ts @@ -1,51 +1,53 @@ import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import type { PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useUpdateCurrentWidgetConfig = (pageLayoutIdFromProps: string) => { - const pageLayoutDraftCallbackState = useRecoilComponentCallbackState( + const pageLayoutDraftAtom = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutIdFromProps, ); - const currentlyEditingWidgetId = useRecoilComponentValue( + const currentlyEditingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, pageLayoutIdFromProps, ); - const updateCurrentWidgetConfig = useRecoilCallback( - ({ set }) => - ({ - objectMetadataId, - configToUpdate, - }: { - objectMetadataId?: string | null; - configToUpdate?: Partial; - }) => { - set(pageLayoutDraftCallbackState, (prev) => ({ - ...prev, - tabs: prev.tabs.map((tab) => ({ - ...tab, - widgets: tab.widgets.map((widget) => - widget.id === currentlyEditingWidgetId - ? { - ...widget, - objectMetadataId: - objectMetadataId ?? widget.objectMetadataId, - configuration: { - ...(widget.configuration ?? {}), - ...configToUpdate, - } as PageLayoutWidget['configuration'], - } - : widget, - ), - })), - })); - }, - [pageLayoutDraftCallbackState, currentlyEditingWidgetId], + const store = useStore(); + + const updateCurrentWidgetConfig = useCallback( + ({ + objectMetadataId, + configToUpdate, + }: { + objectMetadataId?: string | null; + configToUpdate?: Partial; + }) => { + const prev = store.get(pageLayoutDraftAtom); + store.set(pageLayoutDraftAtom, { + ...prev, + tabs: prev.tabs.map((tab) => ({ + ...tab, + widgets: tab.widgets.map((widget) => + widget.id === currentlyEditingWidgetId + ? { + ...widget, + objectMetadataId: objectMetadataId ?? widget.objectMetadataId, + configuration: { + ...(widget.configuration ?? {}), + ...configToUpdate, + } as PageLayoutWidget['configuration'], + } + : widget, + ), + })), + }); + }, + [pageLayoutDraftAtom, currentlyEditingWidgetId, store], ); return { updateCurrentWidgetConfig }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateGraphTypeConfig.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateGraphTypeConfig.ts index f1d50cb1ec..4ab1c91f6a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateGraphTypeConfig.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useUpdateGraphTypeConfig.ts @@ -15,9 +15,9 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { updateWidgetMinimumSizeForGraphType } from '@/page-layout/utils/updateWidgetMinimumSizeForGraphType'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { BarChartLayout } from '~/generated-metadata/graphql'; @@ -32,159 +32,148 @@ export const useGetConfigToUpdateAfterGraphTypeChange = ({ const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId); - const currentlyEditingWidgetIdState = useRecoilComponentCallbackState( + const currentlyEditingWidgetIdState = useRecoilComponentStateCallbackStateV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); const store = useStore(); - const getConfigToUpdateAfterGraphTypeChange = useRecoilCallback( - ({ set, snapshot }) => - (graphType: GraphType) => { - const currentlyEditingWidgetId = snapshot - .getLoadable(currentlyEditingWidgetIdState) - .getValue(); + const getConfigToUpdateAfterGraphTypeChange = useCallback( + (graphType: GraphType) => { + const currentlyEditingWidgetId = store.get(currentlyEditingWidgetIdState); - if (!isDefined(currentlyEditingWidgetId)) { - throw new Error('No widget is currently being edited'); - } + if (!isDefined(currentlyEditingWidgetId)) { + throw new Error('No widget is currently being edited'); + } - const draftPageLayout = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); + const draftPageLayout = store.get(pageLayoutDraftState); - const widgetInDraft = draftPageLayout.tabs - .flatMap((tab) => tab.widgets) - .find((w) => w.id === currentlyEditingWidgetId); + const widgetInDraft = draftPageLayout.tabs + .flatMap((tab) => tab.widgets) + .find((w) => w.id === currentlyEditingWidgetId); - if ( - !isDefined(widgetInDraft) || - !isDefined(widgetInDraft.configuration) - ) { - throw new Error('Widget configuration not found in draft state'); - } + if ( + !isDefined(widgetInDraft) || + !isDefined(widgetInDraft.configuration) + ) { + throw new Error('Widget configuration not found in draft state'); + } - const currentConfiguration = widgetInDraft.configuration; + const currentConfiguration = widgetInDraft.configuration; - if (!isWidgetConfigurationOfTypeGraph(currentConfiguration)) { - throw new Error('Widget configuration is not a chart configuration'); - } + if (!isWidgetConfigurationOfTypeGraph(currentConfiguration)) { + throw new Error('Widget configuration is not a chart configuration'); + } - const newConfigurationType = - getConfigurationTypeFromGraphType(graphType); + const newConfigurationType = getConfigurationTypeFromGraphType(graphType); - let configToUpdate = { - __typename: - GRAPH_CONFIGURATION_TYPE_TO_CONFIG_TYPENAME[newConfigurationType], - configurationType: newConfigurationType, - } as Partial; + let configToUpdate = { + __typename: + GRAPH_CONFIGURATION_TYPE_TO_CONFIG_TYPENAME[newConfigurationType], + configurationType: newConfigurationType, + } as Partial; - if ( - graphType !== GraphType.AGGREGATE && - graphType !== GraphType.GAUGE - ) { - const objectMetadataItem = objectMetadataItems.find( - (item) => item.id === widget.objectMetadataId, + if (graphType !== GraphType.AGGREGATE && graphType !== GraphType.GAUGE) { + const objectMetadataItem = objectMetadataItems.find( + (item) => item.id === widget.objectMetadataId, + ); + + const convertedAggregateOperation = + convertAggregateOperationForDateField( + currentConfiguration, + objectMetadataItem, ); - const convertedAggregateOperation = - convertAggregateOperationForDateField( - currentConfiguration, - objectMetadataItem, - ); - - if (isDefined(convertedAggregateOperation)) { - configToUpdate = { - ...configToUpdate, - aggregateOperation: convertedAggregateOperation, - }; - } + if (isDefined(convertedAggregateOperation)) { + configToUpdate = { + ...configToUpdate, + aggregateOperation: convertedAggregateOperation, + }; } + } - const isPieChart = graphType === GraphType.PIE; - const isVerticalBarChart = graphType === GraphType.VERTICAL_BAR; - const isHorizontalBarChart = graphType === GraphType.HORIZONTAL_BAR; - const isLineChart = graphType === GraphType.LINE; - const isBarOrLineChart = - isVerticalBarChart || isHorizontalBarChart || isLineChart; + const isPieChart = graphType === GraphType.PIE; + const isVerticalBarChart = graphType === GraphType.VERTICAL_BAR; + const isHorizontalBarChart = graphType === GraphType.HORIZONTAL_BAR; + const isLineChart = graphType === GraphType.LINE; + const isBarOrLineChart = + isVerticalBarChart || isHorizontalBarChart || isLineChart; - const wasBarOrLineChart = - isWidgetConfigurationOfType( - currentConfiguration, - 'BarChartConfiguration', - ) || - isWidgetConfigurationOfType( - currentConfiguration, - 'LineChartConfiguration', - ); - - const wasPieChart = isWidgetConfigurationOfType( + const wasBarOrLineChart = + isWidgetConfigurationOfType( currentConfiguration, - 'PieChartConfiguration', + 'BarChartConfiguration', + ) || + isWidgetConfigurationOfType( + currentConfiguration, + 'LineChartConfiguration', ); - if (isPieChart && wasBarOrLineChart) { - configToUpdate = { - ...configToUpdate, - ...convertBarOrLineChartConfigToPieChart(currentConfiguration), - }; - } + const wasPieChart = isWidgetConfigurationOfType( + currentConfiguration, + 'PieChartConfiguration', + ); - if (isBarOrLineChart && wasPieChart) { - configToUpdate = { - ...configToUpdate, - ...convertPieChartConfigToBarOrLineChart(currentConfiguration), - }; - } + if (isPieChart && wasBarOrLineChart) { + configToUpdate = { + ...configToUpdate, + ...convertBarOrLineChartConfigToPieChart(currentConfiguration), + }; + } - if (isHorizontalBarChart) { - configToUpdate = { - ...configToUpdate, - layout: BarChartLayout.HORIZONTAL, - }; - } + if (isBarOrLineChart && wasPieChart) { + configToUpdate = { + ...configToUpdate, + ...convertPieChartConfigToBarOrLineChart(currentConfiguration), + }; + } - if (isVerticalBarChart) { - configToUpdate = { - ...configToUpdate, - layout: BarChartLayout.VERTICAL, - }; - } + if (isHorizontalBarChart) { + configToUpdate = { + ...configToUpdate, + layout: BarChartLayout.HORIZONTAL, + }; + } - const activeTabId = store.get( - activeTabIdComponentState.atomFamily({ - instanceId: tabListInstanceId, - }), - ); + if (isVerticalBarChart) { + configToUpdate = { + ...configToUpdate, + layout: BarChartLayout.VERTICAL, + }; + } - if (isDefined(activeTabId) && isDefined(currentlyEditingWidgetId)) { - const currentLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const activeTabId = store.get( + activeTabIdComponentState.atomFamily({ + instanceId: tabListInstanceId, + }), + ); - const updatedLayouts = updateWidgetMinimumSizeForGraphType({ - configurationType: newConfigurationType, - widgetId: currentlyEditingWidgetId, - tabId: activeTabId, - currentLayouts, - }); + if (isDefined(activeTabId) && isDefined(currentlyEditingWidgetId)) { + const currentLayouts = store.get(pageLayoutCurrentLayoutsState); - set(pageLayoutCurrentLayoutsState, updatedLayouts); - } + const updatedLayouts = updateWidgetMinimumSizeForGraphType({ + configurationType: newConfigurationType, + widgetId: currentlyEditingWidgetId, + tabId: activeTabId, + currentLayouts, + }); - return configToUpdate; - }, + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); + } + + return configToUpdate; + }, [ currentlyEditingWidgetIdState, objectMetadataItems, diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useWidgetInEditMode.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useWidgetInEditMode.ts index 614de08460..19640398d9 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useWidgetInEditMode.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/hooks/useWidgetInEditMode.ts @@ -1,14 +1,14 @@ import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useWidgetInEditMode = (pageLayoutId: string) => { - const draftPageLayout = useRecoilComponentValue( + const draftPageLayout = useRecoilComponentValueV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutEditingWidgetId = useRecoilComponentValue( + const pageLayoutEditingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/states/hasInitializedChartFiltersComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/page-layout/states/hasInitializedChartFiltersComponentState.ts index 05ece29100..85705dc8e4 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/states/hasInitializedChartFiltersComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/states/hasInitializedChartFiltersComponentState.ts @@ -1,8 +1,8 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const hasInitializedChartFiltersComponentState = - createComponentState({ + createComponentStateV2({ key: 'hasInitializedCurrentRecordFiltersComponentFamilyState', defaultValue: false, componentInstanceContext: RecordFiltersComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx index c70182eecd..05ea50758c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx @@ -8,11 +8,11 @@ import { INFORMATION_BANNER_HEIGHT } from '@/information-banner/constants/Inform import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { PageLayoutRecordPageRenderer } from '@/object-record/record-show/components/PageLayoutRecordPageRenderer'; import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; const StyledRightDrawerRecord = styled.div<{ hasDeletedRecordBanner: boolean; @@ -26,11 +26,11 @@ const StyledRightDrawerRecord = styled.div<{ `; export const CommandMenuRecordPage = () => { - const viewableRecordNameSingular = useRecoilComponentValue( + const viewableRecordNameSingular = useRecoilComponentValueV2( viewableRecordNameSingularComponentState, ); - const viewableRecordId = useRecoilComponentValue( + const viewableRecordId = useRecoilComponentValueV2( viewableRecordIdComponentState, ); @@ -47,11 +47,9 @@ export const CommandMenuRecordPage = () => { viewableRecordId, ); - const recordDeletedAt = useRecoilValue( - recordStoreFamilySelector({ - recordId: objectRecordId, - fieldName: 'deletedAt', - }), + const recordDeletedAt = useFamilySelectorValueV2( + recordStoreFamilySelectorV2, + { recordId: objectRecordId, fieldName: 'deletedAt' }, ); const commandMenuPageInstanceId = useComponentInstanceStateContext( diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordIdComponentState.ts index 6df54415c6..2e1fafb98b 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordIdComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordIdComponentState.ts @@ -1,7 +1,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const viewableRecordIdComponentState = createComponentState< +export const viewableRecordIdComponentState = createComponentStateV2< string | null >({ key: 'command-menu/viewable-record-id', diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState.ts index 7b1bc3769e..151091594d 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState.ts @@ -1,7 +1,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const viewableRecordNameSingularComponentState = createComponentState< +export const viewableRecordNameSingularComponentState = createComponentStateV2< string | null >({ key: 'command-menu/viewable-record-name-singular', diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx index e0fbb35754..94a78ca891 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx @@ -11,8 +11,8 @@ import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/const import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useTheme } from '@emotion/react'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { IconFunction } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -35,7 +35,7 @@ export const CommandMenuWorkflowSelectAction = ({ const { t } = useLingui(); - const logicFunctions = useRecoilValue(logicFunctionsState); + const logicFunctions = useRecoilValueV2(logicFunctionsState); const toolFunctions = logicFunctions.filter((fn) => fn.isTool === true); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts index 6c5132afd6..2db0dc02b3 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts @@ -1,9 +1,9 @@ import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useCommandMenuWorkflowIdOrThrow = () => { - const workflowId = useRecoilComponentValue( + const workflowId = useRecoilComponentValueV2( commandMenuWorkflowIdComponentState, ); if (!isDefined(workflowId)) { diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts index 61a49868f3..4cc0b79bf6 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts @@ -1,7 +1,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const commandMenuWorkflowIdComponentState = createComponentState< +export const commandMenuWorkflowIdComponentState = createComponentStateV2< string | undefined >({ key: 'command-menu/workflow-id', diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts index 28f36e828a..5355920fc1 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts @@ -1,7 +1,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const commandMenuWorkflowRunIdComponentState = createComponentState< +export const commandMenuWorkflowRunIdComponentState = createComponentStateV2< string | undefined >({ key: 'command-menu/workflow-run-id', diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowStepIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowStepIdComponentState.ts index 58f7e520f2..356813c82c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowStepIdComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowStepIdComponentState.ts @@ -1,7 +1,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const commandMenuWorkflowStepIdComponentState = createComponentState< +export const commandMenuWorkflowStepIdComponentState = createComponentStateV2< string | undefined >({ key: 'command-menu/workflow-step-id', diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts index c70a9c830a..398e8bb585 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts @@ -1,10 +1,9 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const commandMenuWorkflowVersionIdComponentState = createComponentState< - string | undefined ->({ - key: 'command-menu/workflow-version-id', - defaultValue: undefined, - componentInstanceContext: CommandMenuPageComponentInstanceContext, -}); +export const commandMenuWorkflowVersionIdComponentState = + createComponentStateV2({ + key: 'command-menu/workflow-version-id', + defaultValue: undefined, + componentInstanceContext: CommandMenuPageComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/create/components/CommandMenuWorkflowCreateStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/create/components/CommandMenuWorkflowCreateStepContent.tsx index 7b53697131..7cd2e543ce 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/create/components/CommandMenuWorkflowCreateStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/create/components/CommandMenuWorkflowCreateStepContent.tsx @@ -4,8 +4,8 @@ import { type WorkflowActionSelection, } from '@/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { @@ -18,13 +18,13 @@ import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep'; import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; import { prepareIfElseStepWithNewBranch } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/prepareIfElseStepWithNewBranch'; import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; export const CommandMenuWorkflowCreateStepContent = () => { const { getIcon } = useIcons(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); @@ -36,12 +36,12 @@ export const CommandMenuWorkflowCreateStepContent = () => { const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu(); const { closeRightClickMenu } = useCloseRightClickMenu(); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); const [workflowInsertStepIds, setWorkflowInsertStepIds] = - useRecoilComponentState(workflowInsertStepIdsComponentState); + useRecoilComponentStateV2(workflowInsertStepIdsComponentState); const handleIfElseParentStep = async ({ parentStep, diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx index 7590731958..eb8fc8c59b 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; @@ -15,7 +15,7 @@ const StyledContainer = styled.div` export const CommandMenuWorkflowEditStepContent = () => { const flow = useFlowOrThrow(); - const workflowSelectedNode = useRecoilComponentValue( + const workflowSelectedNode = useRecoilComponentValueV2( workflowSelectedNodeComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepTypeContent.tsx index 19c80b3208..7c3b89c62c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepTypeContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepTypeContent.tsx @@ -4,7 +4,7 @@ import { type WorkflowActionSelection, } from '@/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { @@ -15,16 +15,16 @@ import { useCloseRightClickMenu } from '@/workflow/workflow-diagram/hooks/useClo import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep'; import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; export const CommandMenuWorkflowEditStepTypeContent = () => { const { getIcon } = useIcons(); - const workflowSelectedNode = useRecoilComponentValue( + const workflowSelectedNode = useRecoilComponentValueV2( workflowSelectedNodeComponentState, ); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const flow = useFlowOrThrow(); @@ -33,7 +33,7 @@ export const CommandMenuWorkflowEditStepTypeContent = () => { const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu(); const { closeRightClickMenu } = useCloseRightClickMenu(); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx index b79850ea11..181384fe2d 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx @@ -7,7 +7,6 @@ import { TabList } from '@/ui/layout/tab-list/components/TabList'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; @@ -44,7 +43,7 @@ type TabId = WorkflowRunTabIdType; export const CommandMenuWorkflowRunViewStepContent = () => { const flow = useFlowOrThrow(); - const workflowSelectedNode = useRecoilComponentValue( + const workflowSelectedNode = useRecoilComponentValueV2( workflowSelectedNodeComponentState, ); const workflowRunId = useWorkflowRunIdOrThrow(); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts index 17a0f346b0..ec64640c89 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts @@ -1,9 +1,9 @@ import { commandMenuWorkflowRunIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useCommandMenuWorkflowRunIdOrThrow = () => { - const workflowRunId = useRecoilComponentValue( + const workflowRunId = useRecoilComponentValueV2( commandMenuWorkflowRunIdComponentState, ); if (!isDefined(workflowRunId)) { diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState.ts index a65db1293e..0f7211715e 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState.ts @@ -1,8 +1,8 @@ import { CommandMenuWorkflowRunStepContentComponentInstanceContext } from '@/command-menu/pages/workflow/step/view-run/states/contexts/CommandMenuWorkflowRunStepContentComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const workflowRunIteratorSubStepIterationIndexComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowRunIteratorSubStepIterationIndexComponentState', defaultValue: 0, componentInstanceContext: diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx index ac0f9e8fed..987e678692 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; @@ -13,7 +13,7 @@ const StyledContainer = styled.div` export const CommandMenuWorkflowViewStepContent = () => { const flow = useFlowOrThrow(); - const workflowSelectedNode = useRecoilComponentValue( + const workflowSelectedNode = useRecoilComponentValueV2( workflowSelectedNodeComponentState, ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts index 5ad0c58ee6..aef20b6c59 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts @@ -1,9 +1,9 @@ import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useCommandMenuWorkflowVersionIdOrThrow = () => { - const workflowVersionId = useRecoilComponentValue( + const workflowVersionId = useRecoilComponentValueV2( commandMenuWorkflowVersionIdComponentState, ); if (!isDefined(workflowVersionId)) { diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx index 3e2239e5db..da4b8c1de7 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx @@ -1,7 +1,7 @@ import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { type WorkflowTrigger, @@ -29,7 +29,7 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = () => { const { activeNonSystemObjectMetadataItems } = useFilteredObjectMetadataItems(); - const setWorkflowSelectedNode = useSetRecoilComponentState( + const setWorkflowSelectedNode = useSetRecoilComponentStateV2( workflowSelectedNodeComponentState, ); const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu(); diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationMorphItemsByPageState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationMorphItemsByPageState.ts index fec81d2501..099ac2c2ae 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationMorphItemsByPageState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationMorphItemsByPageState.ts @@ -1,7 +1,7 @@ import { type MorphItem } from '@/object-record/multiple-objects/types/MorphItem'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const commandMenuNavigationMorphItemsByPageState = createState< +export const commandMenuNavigationMorphItemsByPageState = createStateV2< Map >({ key: 'command-menu/commandMenuNavigationMorphItemsByPageState', diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts index 312e979e29..f55b5a6c1f 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts @@ -1,4 +1,4 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type CommandMenuPages } from 'twenty-shared/types'; import { type IconComponent } from 'twenty-ui/display'; @@ -10,7 +10,7 @@ export type CommandMenuNavigationStackItem = { pageId: string; }; -export const commandMenuNavigationStackState = createState< +export const commandMenuNavigationStackState = createStateV2< CommandMenuNavigationStackItem[] >({ key: 'command-menu/commandMenuNavigationStackState', diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuPageInfoState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuPageInfoState.ts index d8cbcd9332..58fd8558bf 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuPageInfoState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuPageInfoState.ts @@ -1,7 +1,7 @@ import { type IconComponent } from 'twenty-ui/display'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const commandMenuPageInfoState = createState<{ +export const commandMenuPageInfoState = createStateV2<{ title?: string; Icon?: IconComponent; instanceId: string; diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuPageState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuPageState.ts index bdf20a5a69..7a50b29e11 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuPageState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuPageState.ts @@ -1,7 +1,7 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { CommandMenuPages } from 'twenty-shared/types'; -export const commandMenuPageState = createState({ +export const commandMenuPageState = createStateV2({ key: 'command-menu/commandMenuPageState', defaultValue: CommandMenuPages.Root, }); diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuSearchState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuSearchState.ts index df6a5d6a19..8b615199f8 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuSearchState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuSearchState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const commandMenuSearchState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const commandMenuSearchState = createStateV2({ key: 'command-menu/commandMenuSearchState', defaultValue: '', }); diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuShouldFocusTitleInputComponentState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuShouldFocusTitleInputComponentState.ts index b880a166c1..8a2718d5c0 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuShouldFocusTitleInputComponentState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuShouldFocusTitleInputComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { CommandMenuPageComponentInstanceContext } from './contexts/CommandMenuPageComponentInstanceContext'; export const commandMenuShouldFocusTitleInputComponentState = - createComponentState({ + createComponentStateV2({ key: 'commandMenuShouldFocusTitleInputComponentState', defaultValue: false, componentInstanceContext: CommandMenuPageComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuWidthState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuWidthState.ts index 241aec46bd..7566b9618b 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuWidthState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuWidthState.ts @@ -1,12 +1,10 @@ -import { atom } from 'recoil'; - import { COMMAND_MENU_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/CommandMenuConstraints'; -import { localStorageEffect } from '~/utils/recoil/localStorageEffect'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; export const COMMAND_MENU_WIDTH_VAR = '--command-menu-width'; -export const commandMenuWidthState = atom({ +export const commandMenuWidthState = createStateV2({ key: 'commandMenuWidth', - default: COMMAND_MENU_CONSTRAINTS.default, - effects: [localStorageEffect()], + defaultValue: COMMAND_MENU_CONSTRAINTS.default, + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/command-menu/states/hasUserSelectedCommandState.ts b/packages/twenty-front/src/modules/command-menu/states/hasUserSelectedCommandState.ts index 1888a972cd..63e080fd26 100644 --- a/packages/twenty-front/src/modules/command-menu/states/hasUserSelectedCommandState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/hasUserSelectedCommandState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const hasUserSelectedCommandState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const hasUserSelectedCommandState = createStateV2({ key: 'hasUserSelectedCommandState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts b/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts index 1bbe8fd4db..2cf41e8b88 100644 --- a/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/isCommandMenuClosingState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const isCommandMenuClosingState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const isCommandMenuClosingState = createStateV2({ key: 'command-menu/isCommandMenuClosingState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/command-menu/states/isCommandMenuOpenedState.ts b/packages/twenty-front/src/modules/command-menu/states/isCommandMenuOpenedState.ts deleted file mode 100644 index 0077d54df9..0000000000 --- a/packages/twenty-front/src/modules/command-menu/states/isCommandMenuOpenedState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { atom } from 'recoil'; - -export const isCommandMenuOpenedState = atom({ - key: 'command-menu/isCommandMenuOpenedState', - default: false, -}); diff --git a/packages/twenty-front/src/modules/context-store/components/MainContextStoreProviderEffect.tsx b/packages/twenty-front/src/modules/context-store/components/MainContextStoreProviderEffect.tsx index 48afd4b430..18c9057824 100644 --- a/packages/twenty-front/src/modules/context-store/components/MainContextStoreProviderEffect.tsx +++ b/packages/twenty-front/src/modules/context-store/components/MainContextStoreProviderEffect.tsx @@ -6,7 +6,7 @@ import { getViewType } from '@/context-store/utils/getViewType'; import { useSetLastVisitedObjectMetadataId } from '@/navigation/hooks/useSetLastVisitedObjectMetadataId'; import { useSetLastVisitedViewForObjectMetadataNamePlural } from '@/navigation/hooks/useSetLastVisitedViewForObjectMetadataNamePlural'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { useEffect } from 'react'; @@ -33,13 +33,13 @@ export const MainContextStoreProviderEffect = ({ useSetLastVisitedObjectMetadataId(); const [contextStoreCurrentViewId, setContextStoreCurrentViewId] = - useRecoilComponentState( + useRecoilComponentStateV2( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); const [contextStoreCurrentViewType, setContextStoreCurrentViewType] = - useRecoilComponentState( + useRecoilComponentStateV2( contextStoreCurrentViewTypeComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); @@ -47,7 +47,7 @@ export const MainContextStoreProviderEffect = ({ const [ contextStoreCurrentObjectMetadataItemId, setContextStoreCurrentObjectMetadataItemId, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( contextStoreCurrentObjectMetadataItemIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts b/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts index 8a79f68290..0316779c7d 100644 --- a/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts @@ -1,12 +1,12 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; export const useContextStoreObjectMetadataItem = ( contextStoreInstanceId?: string, ) => { - const objectMetadataItemId = useRecoilComponentValue( + const objectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, contextStoreInstanceId, ); diff --git a/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItemOrThrow.ts b/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItemOrThrow.ts index baab22ef6f..feeddff4cc 100644 --- a/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItemOrThrow.ts +++ b/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItemOrThrow.ts @@ -1,11 +1,11 @@ import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useContextStoreObjectMetadataItemOrThrow = ( contextStoreInstanceId?: string, ) => { - const objectMetadataItemId = useRecoilComponentValue( + const objectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, contextStoreInstanceId, ); diff --git a/packages/twenty-front/src/modules/context-store/hooks/useFindManyRecordsSelectedInContextStore.ts b/packages/twenty-front/src/modules/context-store/hooks/useFindManyRecordsSelectedInContextStore.ts index 8c0e3426f3..c5e6b4cbd9 100644 --- a/packages/twenty-front/src/modules/context-store/hooks/useFindManyRecordsSelectedInContextStore.ts +++ b/packages/twenty-front/src/modules/context-store/hooks/useFindManyRecordsSelectedInContextStore.ts @@ -9,7 +9,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; export const useFindManyRecordsSelectedInContextStore = ({ @@ -19,7 +19,7 @@ export const useFindManyRecordsSelectedInContextStore = ({ instanceId?: string; limit?: number; }) => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, instanceId, ); @@ -28,22 +28,22 @@ export const useFindManyRecordsSelectedInContextStore = ({ objectId: contextStoreCurrentObjectMetadataItemId ?? '', }); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, instanceId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, instanceId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, instanceId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, instanceId, ); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreAnyFieldFilterValueComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreAnyFieldFilterValueComponentState.ts index 8668e3b1ac..711998f67b 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreAnyFieldFilterValueComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreAnyFieldFilterValueComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const contextStoreAnyFieldFilterValueComponentState = - createComponentState({ + createComponentStateV2({ key: 'contextStoreAnyFieldFilterValueComponentState', defaultValue: '', componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState.ts index dab731c864..e614b5592e 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const contextStoreCurrentObjectMetadataItemIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'contextStoreCurrentObjectMetadataItemIdComponentState', defaultValue: undefined, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts index 348a1e3f59..8466e91f5d 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts @@ -1,7 +1,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const contextStoreCurrentViewIdComponentState = createComponentState< +export const contextStoreCurrentViewIdComponentState = createComponentStateV2< string | undefined >({ key: 'contextStoreCurrentViewIdComponentState', diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewTypeComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewTypeComponentState.ts index a512a8c9b2..c06c256303 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewTypeComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewTypeComponentState.ts @@ -1,9 +1,9 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const contextStoreCurrentViewTypeComponentState = - createComponentState({ + createComponentStateV2({ key: 'contextStoreCurrentViewTypeComponentState', defaultValue: null, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreFilterGroupsComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreFilterGroupsComponentState.ts index 713dbd5b56..e60830a3ed 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreFilterGroupsComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreFilterGroupsComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const contextStoreFilterGroupsComponentState = createComponentState< +export const contextStoreFilterGroupsComponentState = createComponentStateV2< RecordFilterGroup[] >({ key: 'contextStoreFilterGroupsComponentState', diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreFiltersComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreFiltersComponentState.ts index 19ad274fbe..08872c066d 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreFiltersComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreFiltersComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const contextStoreFiltersComponentState = createComponentState< +export const contextStoreFiltersComponentState = createComponentStateV2< RecordFilter[] >({ key: 'contextStoreFiltersComponentState', diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts index 2a9b86c817..a778b074ce 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const contextStoreIsPageInEditModeComponentState = - createComponentState({ + createComponentStateV2({ key: 'contextStoreIsPageInEditModeComponentState', defaultValue: false, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts index fbf2f80e51..fdb0607ddb 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const contextStoreNumberOfSelectedRecordsComponentState = - createComponentState({ + createComponentStateV2({ key: 'contextStoreNumberOfSelectedRecordsComponentState', defaultValue: 0, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreRecordShowParentViewComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreRecordShowParentViewComponentState.ts index 8a3e4978d1..1678372551 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreRecordShowParentViewComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreRecordShowParentViewComponentState.ts @@ -2,7 +2,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; type RecordShowParentViewComponentState = { parentViewComponentId: string; @@ -13,8 +13,10 @@ type RecordShowParentViewComponentState = { }; export const contextStoreRecordShowParentViewComponentState = - createComponentState({ - key: 'contextStoreRecordShowParentViewComponentState', - defaultValue: undefined, - componentInstanceContext: ContextStoreComponentInstanceContext, - }); + createComponentStateV2( + { + key: 'contextStoreRecordShowParentViewComponentState', + defaultValue: undefined, + componentInstanceContext: ContextStoreComponentInstanceContext, + }, + ); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts index a10e2f3fea..c893b240ba 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts @@ -1,5 +1,5 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; type ContextStoreTargetedRecordsRuleSelectionMode = { mode: 'selection'; @@ -16,7 +16,7 @@ export type ContextStoreTargetedRecordsRule = | ContextStoreTargetedRecordsRuleExclusionMode; export const contextStoreTargetedRecordsRuleComponentState = - createComponentState({ + createComponentStateV2({ key: 'contextStoreTargetedRecordsRuleComponentState', defaultValue: { mode: 'selection', diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPicker.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPicker.tsx index a36bf223a4..950f86e1ee 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPicker.tsx +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPicker.tsx @@ -12,8 +12,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; - +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { Key } from 'ts-key-enum'; type FavoriteFolderPickerProps = { @@ -43,7 +42,7 @@ export const FavoriteFolderPicker = ({ objectNameSingular, }); - const [favoriteFoldersSearchFilter] = useRecoilComponentState( + const [favoriteFoldersSearchFilter] = useRecoilComponentStateV2( favoriteFolderSearchFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx index 044b2b9cf7..d5b92cef54 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx @@ -1,5 +1,4 @@ -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useEffect } from 'react'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { favoriteFolderIdsPickerComponentState } from '@/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState'; @@ -9,9 +8,10 @@ import { useFavorites } from '@/favorites/hooks/useFavorites'; import { usePrefetchedFavoritesFoldersData } from '@/favorites/hooks/usePrefetchedFavoritesFoldersData'; import { type FavoriteFolder } from '@/favorites/types/FavoriteFolder'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isDefined } from 'twenty-shared/utils'; type FavoriteFolderPickerEffectProps = { @@ -22,33 +22,32 @@ export const FavoriteFolderPickerEffect = ({ record, }: FavoriteFolderPickerEffectProps) => { const [favoriteFolderIdsPicker, setFavoriteFolderIdsPicker] = - useRecoilComponentState(favoriteFolderIdsPickerComponentState); + useRecoilComponentStateV2(favoriteFolderIdsPickerComponentState); - const favoriteFolderPickerFamilyState = useRecoilComponentCallbackState( - favoriteFolderPickerComponentFamilyState, - ); + const favoriteFolderPickerFamilyAtom = + useRecoilComponentFamilyStateCallbackStateV2( + favoriteFolderPickerComponentFamilyState, + ); const { favoriteFolders } = usePrefetchedFavoritesFoldersData(); const { sortedFavorites: favorites } = useFavorites(); - const setCheckedState = useSetRecoilComponentState( + const setCheckedState = useSetRecoilComponentStateV2( favoriteFolderPickerCheckedComponentState, ); - const updateFolders = useRecoilCallback( - ({ snapshot, set }) => - (folders: FavoriteFolder[]) => { - folders.forEach((folder) => { - const currentFolder = snapshot - .getLoadable(favoriteFolderPickerFamilyState(folder.id)) - .getValue(); + const updateFolders = useCallback( + (folders: FavoriteFolder[]) => { + folders.forEach((folder) => { + const atom = favoriteFolderPickerFamilyAtom(folder.id); + const currentFolder = jotaiStore.get(atom); - if (!isDeeplyEqual(folder, currentFolder)) { - set(favoriteFolderPickerFamilyState(folder.id), folder); - } - }); - }, - [favoriteFolderPickerFamilyState], + if (!isDeeplyEqual(folder, currentFolder)) { + jotaiStore.set(atom, folder); + } + }); + }, + [favoriteFolderPickerFamilyAtom], ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx index 4cf86d3d11..9aa2318aa7 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx @@ -2,7 +2,7 @@ import { favoriteFolderPickerCheckedComponentState } from '@/favorites/favorite- import { favoriteFolderSearchFilterComponentState } from '@/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState'; import { type FavoriteFolder } from '@/favorites/types/FavoriteFolder'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { MenuItem, MenuItemMultiSelect } from 'twenty-ui/navigation'; @@ -28,11 +28,11 @@ export const FavoriteFolderPickerList = ({ toggleFolderSelection, }: FavoriteFolderPickerListProps) => { const { t } = useLingui(); - const [favoriteFoldersSearchFilter] = useRecoilComponentState( + const [favoriteFoldersSearchFilter] = useRecoilComponentStateV2( favoriteFolderSearchFilterComponentState, ); - const [favoriteFolderPickerChecked] = useRecoilComponentState( + const [favoriteFolderPickerChecked] = useRecoilComponentStateV2( favoriteFolderPickerCheckedComponentState, ); diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerSearchInput.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerSearchInput.tsx index 9f35f47992..7bc850bb89 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerSearchInput.tsx +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerSearchInput.tsx @@ -1,12 +1,12 @@ import { favoriteFolderSearchFilterComponentState } from '@/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useCallback } from 'react'; import { useDebouncedCallback } from 'use-debounce'; export const FavoriteFolderPickerSearchInput = () => { const [favoriteFoldersSearchFilter, setFavoriteFoldersSearchFilter] = - useRecoilComponentState(favoriteFolderSearchFilterComponentState); + useRecoilComponentStateV2(favoriteFolderSearchFilterComponentState); const debouncedSetSearchFilter = useDebouncedCallback( setFavoriteFoldersSearchFilter, diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/hooks/useFavoriteFolderPicker.ts b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/hooks/useFavoriteFolderPicker.ts index afa4a59b26..939ece2b61 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/hooks/useFavoriteFolderPicker.ts +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/hooks/useFavoriteFolderPicker.ts @@ -6,9 +6,10 @@ import { useFavorites } from '@/favorites/hooks/useFavorites'; import { type FavoriteFolder } from '@/favorites/types/FavoriteFolder'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; type useFavoriteFolderPickerProps = { @@ -25,77 +26,79 @@ export const useFavoriteFolderPicker = ({ record, objectNameSingular, }: useFavoriteFolderPickerProps): useFavoriteFolderPickerReturnType => { - const favoriteFoldersMultiSelectCheckedState = - useRecoilComponentCallbackState(favoriteFolderPickerCheckedComponentState); + const favoriteFoldersMultiSelectCheckedAtom = + useRecoilComponentStateCallbackStateV2( + favoriteFolderPickerCheckedComponentState, + ); const { sortedFavorites: favorites } = useFavorites(); const { createFavorite } = useCreateFavorite(); const { deleteFavorite } = useDeleteFavorite(); - const favoriteFolders = useRecoilComponentValue( + const favoriteFolders = useRecoilComponentSelectorValueV2( favoriteFoldersComponentSelector, ); - const toggleFolderSelection = useRecoilCallback( - ({ snapshot, set }) => - async (folderId: string) => { - const targetId = record?.id; - const targetObject = record; + const store = useStore(); - if (!isDefined(targetObject) || !isDefined(targetId)) { - throw new Error( - `Cannot toggle folder selection: record ${ - !isDefined(targetObject) ? 'object' : 'id' - } is not defined`, - ); - } + const toggleFolderSelection = useCallback( + async (folderId: string) => { + const targetId = record?.id; + const targetObject = record; - const deleteFavoriteForRecord = async (isUnorganized: boolean) => { - const favoriteToDelete = favorites.find( - (favorite) => - favorite.recordId === targetId && - (isUnorganized - ? !favorite.favoriteFolderId - : favorite.favoriteFolderId === folderId), - ); + if (!isDefined(targetObject) || !isDefined(targetId)) { + throw new Error( + `Cannot toggle folder selection: record ${ + !isDefined(targetObject) ? 'object' : 'id' + } is not defined`, + ); + } - if (!isDefined(favoriteToDelete)) { - return; - } + const deleteFavoriteForRecord = async (isUnorganized: boolean) => { + const favoriteToDelete = favorites.find( + (favorite) => + favorite.recordId === targetId && + (isUnorganized + ? !favorite.favoriteFolderId + : favorite.favoriteFolderId === folderId), + ); - await deleteFavorite(favoriteToDelete.id); - }; - - const checkedIds = snapshot - .getLoadable(favoriteFoldersMultiSelectCheckedState) - .getValue(); - - const isAlreadyChecked = checkedIds.includes(folderId); - - if (isAlreadyChecked) { - await deleteFavoriteForRecord(folderId === 'no-folder'); - - const newCheckedIds = checkedIds.filter((id) => id !== folderId); - set(favoriteFoldersMultiSelectCheckedState, newCheckedIds); + if (!isDefined(favoriteToDelete)) { return; } - const folderIdToUse = folderId === 'no-folder' ? undefined : folderId; + await deleteFavorite(favoriteToDelete.id); + }; - if (isDefined(record)) { - await createFavorite(record, objectNameSingular, folderIdToUse); - } + const checkedIds = store.get(favoriteFoldersMultiSelectCheckedAtom); - const newCheckedIds = [...checkedIds, folderId]; - set(favoriteFoldersMultiSelectCheckedState, newCheckedIds); - }, + const isAlreadyChecked = checkedIds.includes(folderId); + + if (isAlreadyChecked) { + await deleteFavoriteForRecord(folderId === 'no-folder'); + + const newCheckedIds = checkedIds.filter((id) => id !== folderId); + store.set(favoriteFoldersMultiSelectCheckedAtom, newCheckedIds); + return; + } + + const folderIdToUse = folderId === 'no-folder' ? undefined : folderId; + + if (isDefined(record)) { + await createFavorite(record, objectNameSingular, folderIdToUse); + } + + const newCheckedIds = [...checkedIds, folderId]; + store.set(favoriteFoldersMultiSelectCheckedAtom, newCheckedIds); + }, [ - favoriteFoldersMultiSelectCheckedState, + favoriteFoldersMultiSelectCheckedAtom, createFavorite, deleteFavorite, favorites, record, objectNameSingular, + store, ], ); diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState.ts b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState.ts index 2a52ea254c..c4fc1fd6c8 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState.ts +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState.ts @@ -1,7 +1,7 @@ import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const favoriteFolderIdsPickerComponentState = createComponentState< +export const favoriteFolderIdsPickerComponentState = createComponentStateV2< string[] >({ key: 'favoriteFolderIdsPickerComponentState', diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerCheckedComponentState.ts b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerCheckedComponentState.ts index 14bb431021..551cc776f5 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerCheckedComponentState.ts +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerCheckedComponentState.ts @@ -1,7 +1,7 @@ import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const favoriteFolderPickerCheckedComponentState = createComponentState< +export const favoriteFolderPickerCheckedComponentState = createComponentStateV2< string[] >({ key: 'favoriteFolderPickerCheckedComponentState', diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerComponentFamilyState.ts b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerComponentFamilyState.ts index 82355c7b48..c4c49ac641 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerComponentFamilyState.ts @@ -1,9 +1,9 @@ import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext'; import { type FavoriteFolder } from '@/favorites/types/FavoriteFolder'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const favoriteFolderPickerComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'favoriteFolderPickerComponentFamilyState', defaultValue: undefined, componentInstanceContext: FavoriteFolderPickerInstanceContext, diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState.ts b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState.ts index 9e079da31d..c3e9417d0e 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState.ts +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState.ts @@ -1,8 +1,8 @@ import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const favoriteFolderSearchFilterComponentState = - createComponentState({ + createComponentStateV2({ key: 'favoriteFolderSearchFilterComponentState', defaultValue: '', componentInstanceContext: FavoriteFolderPickerInstanceContext, diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/selectors/favoriteFoldersComponentSelector.ts b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/selectors/favoriteFoldersComponentSelector.ts index 791cc601e2..b3b1e008f3 100644 --- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/selectors/favoriteFoldersComponentSelector.ts +++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/selectors/favoriteFoldersComponentSelector.ts @@ -2,29 +2,28 @@ import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder import { favoriteFolderIdsPickerComponentState } from '@/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState'; import { favoriteFolderPickerComponentFamilyState } from '@/favorites/favorite-folder-picker/states/favoriteFolderPickerComponentFamilyState'; import { type FavoriteFolder } from '@/favorites/types/FavoriteFolder'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { isDefined } from 'twenty-shared/utils'; -export const favoriteFoldersComponentSelector = createComponentSelector< +export const favoriteFoldersComponentSelector = createComponentSelectorV2< FavoriteFolder[] >({ key: 'favoriteFoldersComponentSelector', componentInstanceContext: FavoriteFolderPickerInstanceContext, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { const folderIds = get( - favoriteFolderIdsPickerComponentState.atomFamily({ instanceId }), - ); + favoriteFolderIdsPickerComponentState, + componentStateKey, + ) as string[]; return folderIds .map((folderId: string) => - get( - favoriteFolderPickerComponentFamilyState.atomFamily({ - instanceId, - familyKey: folderId, - }), - ), + get(favoriteFolderPickerComponentFamilyState, { + instanceId: componentStateKey.instanceId, + familyKey: folderId, + }), ) .filter((folder): folder is FavoriteFolder => isDefined(folder)); }, diff --git a/packages/twenty-front/src/modules/front-components/components/HeadlessFrontComponentMountRoot.tsx b/packages/twenty-front/src/modules/front-components/components/HeadlessFrontComponentMountRoot.tsx index 211e3ef4fb..3324015238 100644 --- a/packages/twenty-front/src/modules/front-components/components/HeadlessFrontComponentMountRoot.tsx +++ b/packages/twenty-front/src/modules/front-components/components/HeadlessFrontComponentMountRoot.tsx @@ -1,8 +1,7 @@ import { Suspense, lazy } from 'react'; -import { useRecoilValue } from 'recoil'; - import { mountedHeadlessFrontComponentIdsState } from '@/front-components/states/mountedHeadlessFrontComponentIdsState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; const FrontComponentRenderer = lazy(() => import('@/front-components/components/FrontComponentRenderer').then( @@ -11,7 +10,7 @@ const FrontComponentRenderer = lazy(() => ); export const HeadlessFrontComponentMountRoot = () => { - const mountedHeadlessFrontComponentIds = useRecoilValue( + const mountedHeadlessFrontComponentIds = useRecoilValueV2( mountedHeadlessFrontComponentIdsState, ); diff --git a/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts b/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts index 783729c9be..9ead49d165 100644 --- a/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts +++ b/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts @@ -1,4 +1,4 @@ -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type FrontComponentExecutionContext, type FrontComponentHostCommunicationApi, @@ -27,7 +27,7 @@ export const useFrontComponentExecutionContext = ({ const currentUser = useRecoilValueV2(currentUserState); const navigateApp = useNavigateApp(); const { navigateCommandMenu } = useNavigateCommandMenu(); - const setCommandMenuSearchState = useSetRecoilState(commandMenuSearchState); + const setCommandMenuSearchState = useSetRecoilStateV2(commandMenuSearchState); const { getIcon } = useIcons(); const unmountHeadlessFrontComponent = useUnmountHeadlessFrontComponent(); const { diff --git a/packages/twenty-front/src/modules/front-components/hooks/useMountHeadlessFrontComponent.ts b/packages/twenty-front/src/modules/front-components/hooks/useMountHeadlessFrontComponent.ts index 6f419afac7..2b2dfc5a02 100644 --- a/packages/twenty-front/src/modules/front-components/hooks/useMountHeadlessFrontComponent.ts +++ b/packages/twenty-front/src/modules/front-components/hooks/useMountHeadlessFrontComponent.ts @@ -1,15 +1,16 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { mountedHeadlessFrontComponentIdsState } from '@/front-components/states/mountedHeadlessFrontComponentIdsState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; export const useMountHeadlessFrontComponent = () => { - const mountHeadlessFrontComponent = useRecoilCallback( - ({ set }) => - (frontComponentId: string) => { - set(mountedHeadlessFrontComponentIdsState, (previousIds) => - new Set(previousIds).add(frontComponentId), - ); - }, + const mountHeadlessFrontComponent = useCallback( + (frontComponentId: string) => { + jotaiStore.set( + mountedHeadlessFrontComponentIdsState.atom, + (previousIds) => new Set(previousIds).add(frontComponentId), + ); + }, [], ); diff --git a/packages/twenty-front/src/modules/front-components/hooks/useUnmountHeadlessFrontComponent.ts b/packages/twenty-front/src/modules/front-components/hooks/useUnmountHeadlessFrontComponent.ts index 121909f012..166d4eb9e4 100644 --- a/packages/twenty-front/src/modules/front-components/hooks/useUnmountHeadlessFrontComponent.ts +++ b/packages/twenty-front/src/modules/front-components/hooks/useUnmountHeadlessFrontComponent.ts @@ -1,17 +1,20 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { mountedHeadlessFrontComponentIdsState } from '@/front-components/states/mountedHeadlessFrontComponentIdsState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; export const useUnmountHeadlessFrontComponent = () => { - const unmountHeadlessFrontComponent = useRecoilCallback( - ({ set }) => - (frontComponentId: string) => { - set(mountedHeadlessFrontComponentIdsState, (previousIds) => { + const unmountHeadlessFrontComponent = useCallback( + (frontComponentId: string) => { + jotaiStore.set( + mountedHeadlessFrontComponentIdsState.atom, + (previousIds) => { const next = new Set(previousIds); next.delete(frontComponentId); return next; - }); - }, + }, + ); + }, [], ); diff --git a/packages/twenty-front/src/modules/front-components/selectors/isHeadlessFrontComponentMountedFamilySelector.ts b/packages/twenty-front/src/modules/front-components/selectors/isHeadlessFrontComponentMountedFamilySelector.ts index b55c4f8062..46d45c141d 100644 --- a/packages/twenty-front/src/modules/front-components/selectors/isHeadlessFrontComponentMountedFamilySelector.ts +++ b/packages/twenty-front/src/modules/front-components/selectors/isHeadlessFrontComponentMountedFamilySelector.ts @@ -1,17 +1,14 @@ -import { selectorFamily } from 'recoil'; - import { mountedHeadlessFrontComponentIdsState } from '@/front-components/states/mountedHeadlessFrontComponentIdsState'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; -export const isHeadlessFrontComponentMountedFamilySelector = selectorFamily< - boolean, - string ->({ - key: 'isHeadlessFrontComponentMountedFamilySelector', - get: - (frontComponentId: string) => - ({ get }) => { - const mountedIds = get(mountedHeadlessFrontComponentIdsState); +export const isHeadlessFrontComponentMountedFamilySelector = + createFamilySelectorV2({ + key: 'isHeadlessFrontComponentMountedFamilySelector', + get: + (frontComponentId: string) => + ({ get }) => { + const mountedIds = get(mountedHeadlessFrontComponentIdsState); - return mountedIds.has(frontComponentId); - }, -}); + return mountedIds.has(frontComponentId); + }, + }); diff --git a/packages/twenty-front/src/modules/front-components/states/mountedHeadlessFrontComponentIdsState.ts b/packages/twenty-front/src/modules/front-components/states/mountedHeadlessFrontComponentIdsState.ts index 4b7604afd6..ecf074bfac 100644 --- a/packages/twenty-front/src/modules/front-components/states/mountedHeadlessFrontComponentIdsState.ts +++ b/packages/twenty-front/src/modules/front-components/states/mountedHeadlessFrontComponentIdsState.ts @@ -1,6 +1,8 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const mountedHeadlessFrontComponentIdsState = atom>({ - key: 'mountedHeadlessFrontComponentIdsState', - default: new Set(), -}); +export const mountedHeadlessFrontComponentIdsState = createStateV2>( + { + key: 'mountedHeadlessFrontComponentIdsState', + defaultValue: new Set(), + }, +); diff --git a/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx b/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx index 78e43abb31..f6105b193b 100644 --- a/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx +++ b/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx @@ -1,6 +1,6 @@ import { InformationBannerComponentInstanceContext } from '@/information-banner/states/contexts/InformationBannerComponentInstanceContext'; import { informationBannerIsOpenComponentState } from '@/information-banner/states/informationBannerIsOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { @@ -51,7 +51,7 @@ export const InformationBanner = ({ onClose?: () => void; componentInstanceId: string; }) => { - const informationBannerIsOpenComponent = useRecoilComponentValue( + const informationBannerIsOpenComponent = useRecoilComponentValueV2( informationBannerIsOpenComponentState, componentInstanceId, ); diff --git a/packages/twenty-front/src/modules/information-banner/hooks/useDismissReconnectAccountBanner.ts b/packages/twenty-front/src/modules/information-banner/hooks/useDismissReconnectAccountBanner.ts index dae11ef0ed..a9eeb46660 100644 --- a/packages/twenty-front/src/modules/information-banner/hooks/useDismissReconnectAccountBanner.ts +++ b/packages/twenty-front/src/modules/information-banner/hooks/useDismissReconnectAccountBanner.ts @@ -3,7 +3,7 @@ import { useMutation } from '@apollo/client'; import { DISMISS_RECONNECT_ACCOUNT_BANNER } from '@/information-banner/graphql/mutations/dismissReconnectAccountBanner'; import { informationBannerIsOpenComponentState } from '@/information-banner/states/informationBannerIsOpenComponentState'; import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; type DismissReconnectAccountBannerMutationVariables = { connectedAccountId: string; @@ -25,7 +25,7 @@ export const useDismissReconnectAccountBanner = ( client: apolloCoreClient, }); - const setInformationBannerIsOpenComponent = useSetRecoilComponentState( + const setInformationBannerIsOpenComponent = useSetRecoilComponentStateV2( informationBannerIsOpenComponentState, componentInstanceId, ); diff --git a/packages/twenty-front/src/modules/information-banner/states/informationBannerIsOpenComponentState.ts b/packages/twenty-front/src/modules/information-banner/states/informationBannerIsOpenComponentState.ts index 7f35131932..bd7a2bd7bc 100644 --- a/packages/twenty-front/src/modules/information-banner/states/informationBannerIsOpenComponentState.ts +++ b/packages/twenty-front/src/modules/information-banner/states/informationBannerIsOpenComponentState.ts @@ -1,8 +1,8 @@ import { InformationBannerComponentInstanceContext } from '@/information-banner/states/contexts/InformationBannerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const informationBannerIsOpenComponentState = - createComponentState({ + createComponentStateV2({ key: 'informationBannerIsOpenComponentState', defaultValue: true, componentInstanceContext: InformationBannerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/logic-functions/hooks/useExecuteLogicFunction.ts b/packages/twenty-front/src/modules/logic-functions/hooks/useExecuteLogicFunction.ts index 52ac8c56d5..bb788d4ac1 100644 --- a/packages/twenty-front/src/modules/logic-functions/hooks/useExecuteLogicFunction.ts +++ b/packages/twenty-front/src/modules/logic-functions/hooks/useExecuteLogicFunction.ts @@ -1,8 +1,9 @@ import { EXECUTE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/executeOneLogicFunction'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState'; import { useMutation } from '@apollo/client'; import { useState } from 'react'; -import { useRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { LogicFunctionExecutionStatus } from '~/generated-metadata/graphql'; import { sleep } from '~/utils/sleep'; @@ -37,8 +38,13 @@ export const useExecuteLogicFunction = ({ { input: ExecuteOneLogicFunctionInput } >(EXECUTE_ONE_LOGIC_FUNCTION); - const [logicFunctionTestData, setLogicFunctionTestData] = useRecoilState( - logicFunctionTestDataFamilyState(logicFunctionId), + const logicFunctionTestData = useFamilyRecoilValueV2( + logicFunctionTestDataFamilyState, + logicFunctionId, + ); + const setLogicFunctionTestData = useSetFamilyRecoilStateV2( + logicFunctionTestDataFamilyState, + logicFunctionId, ); const executeLogicFunction = async () => { diff --git a/packages/twenty-front/src/modules/metadata-store/effect-components/UserMetadataProviderInitialEffect.tsx b/packages/twenty-front/src/modules/metadata-store/effect-components/UserMetadataProviderInitialEffect.tsx index d25b3e2cd1..6882dee2e7 100644 --- a/packages/twenty-front/src/modules/metadata-store/effect-components/UserMetadataProviderInitialEffect.tsx +++ b/packages/twenty-front/src/modules/metadata-store/effect-components/UserMetadataProviderInitialEffect.tsx @@ -14,8 +14,7 @@ import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetReco import { type ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { enUS } from 'date-fns/locale'; import { useStore } from 'jotai'; -import { useEffect, useState } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations'; import { AppPath, type ObjectPermissions } from 'twenty-shared/types'; @@ -24,7 +23,6 @@ import { useGetCurrentUserQuery, type WorkspaceMember, } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { dynamicActivate } from '~/utils/i18n/dynamicActivate'; import { isMatchingLocation } from '~/utils/isMatchingLocation'; @@ -59,21 +57,19 @@ export const UserMetadataProviderInitialEffect = () => { isMatchingLocation(location, AppPath.Verify) || isMatchingLocation(location, AppPath.VerifyEmail); - const updateLocaleCatalog = useRecoilCallback( - ({ snapshot, set }) => - async (newLocale: keyof typeof APP_LOCALES) => { - const localeValue = snapshot.getLoadable(dateLocaleState).getValue(); - if (localeValue.locale !== newLocale) { - getDateFnsLocale(newLocale).then((localeCatalog) => { - const newValue = { - locale: newLocale, - localeCatalog: localeCatalog || enUS, - }; - set(dateLocaleState, newValue); - store.set(dateLocaleStateV2.atom, newValue); - }); - } - }, + const updateLocaleCatalog = useCallback( + async (newLocale: keyof typeof APP_LOCALES) => { + const localeValue = store.get(dateLocaleStateV2.atom); + if (localeValue.locale !== newLocale) { + getDateFnsLocale(newLocale).then((localeCatalog) => { + const newValue = { + locale: newLocale, + localeCatalog: localeCatalog || enUS, + }; + store.set(dateLocaleStateV2.atom, newValue); + }); + } + }, [store], ); diff --git a/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuEditModeBar.tsx b/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuEditModeBar.tsx index b388c13d46..7affa185d3 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuEditModeBar.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuEditModeBar.tsx @@ -14,7 +14,6 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconCheck, useIcons } from 'twenty-ui/display'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -42,7 +41,7 @@ export const NavigationMenuEditModeBar = () => { const { getIcon } = useIcons(); const [isSaving, setIsSaving] = useState(false); const { closeCommandMenu } = useCommandMenu(); - const commandMenuPage = useRecoilValue(commandMenuPageState); + const commandMenuPage = useRecoilValueV2(commandMenuPageState); const { enqueueErrorSnackBar } = useSnackBar(); const setNavigationMenuItemsDraft = useSetRecoilStateV2( navigationMenuItemsDraftStateV2, diff --git a/packages/twenty-front/src/modules/navigation-menu-item/hooks/useHandleAddToNavigationDrop.ts b/packages/twenty-front/src/modules/navigation-menu-item/hooks/useHandleAddToNavigationDrop.ts index 82268046cd..cad85afaa3 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/hooks/useHandleAddToNavigationDrop.ts +++ b/packages/twenty-front/src/modules/navigation-menu-item/hooks/useHandleAddToNavigationDrop.ts @@ -1,6 +1,6 @@ import type { DropResult, ResponderProvided } from '@hello-pangea/dnd'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconFolder, IconLink, useIcons } from 'twenty-ui/display'; @@ -20,7 +20,7 @@ import { openNavigationMenuItemFolderIdsStateV2 } from '@/navigation-menu-item/s import { selectedNavigationMenuItemInEditModeStateV2 } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; -import { useStore } from 'jotai'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { isWorkspaceDroppableId } from '@/navigation-menu-item/utils/isWorkspaceDroppableId'; import { validateAndExtractWorkspaceFolderId } from '@/navigation-menu-item/utils/validateAndExtractWorkspaceFolderId'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; @@ -52,10 +52,8 @@ export const useHandleAddToNavigationDrop = () => { openNavigationMenuItemFolderIdsStateV2, ); - const store = useStore(); - - const handleAddToNavigationDrop = useRecoilCallback( - () => (result: DropResult, _provided: ResponderProvided) => { + const handleAddToNavigationDrop = useCallback( + (result: DropResult, _provided: ResponderProvided) => { const { source, destination, draggableId } = result; if ( source.droppableId !== ADD_TO_NAV_SOURCE_DROPPABLE_ID || @@ -66,7 +64,8 @@ export const useHandleAddToNavigationDrop = () => { } const payload = - store.get(addToNavPayloadRegistryStateV2.atom).get(draggableId) ?? null; + jotaiStore.get(addToNavPayloadRegistryStateV2.atom).get(draggableId) ?? + null; if (!payload) { return; } @@ -203,7 +202,6 @@ export const useHandleAddToNavigationDrop = () => { setOpenNavigationMenuItemFolderIds, setIsNavigationMenuInEditMode, setSelectedNavigationMenuItemInEditMode, - store, workspaceNavigationMenuItems, ], ); diff --git a/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx b/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx index 6870514065..2629b7e50d 100644 --- a/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx +++ b/packages/twenty-front/src/modules/navigation/components/MobileNavigationBar.tsx @@ -9,7 +9,7 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte 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 { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useNavigate } from 'react-router-dom'; import { type IconComponent, @@ -39,7 +39,7 @@ export const MobileNavigationBar = () => { useFilteredObjectMetadataItems(); const [, setContextStoreCurrentObjectMetadataItemId] = - useRecoilComponentState( + useRecoilComponentStateV2( contextStoreCurrentObjectMetadataItemIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/navigation/components/PageDragDropProvider.tsx b/packages/twenty-front/src/modules/navigation/components/PageDragDropProvider.tsx index 345e061d1f..e23d1a610b 100644 --- a/packages/twenty-front/src/modules/navigation/components/PageDragDropProvider.tsx +++ b/packages/twenty-front/src/modules/navigation/components/PageDragDropProvider.tsx @@ -5,8 +5,7 @@ import { type OnDragUpdateResponder, type ResponderProvided, } from '@hello-pangea/dnd'; -import { type ReactNode, useState } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { type ReactNode, useCallback, useState } from 'react'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { FavoritesDragContext } from '@/favorites/contexts/FavoritesDragContext'; @@ -80,39 +79,38 @@ export const PageDragDropProvider = ({ } }; - const handleDragUpdate = useRecoilCallback( - () => - ((update: Parameters[0]) => { - const { source, destination } = update; - if (source.droppableId !== ADD_TO_NAV_SOURCE_DROPPABLE_ID) { - return; - } - if ( - destination !== null && - isWorkspaceDroppableId(destination.droppableId) - ) { - setAddToNavigationFallbackDestination(destination); - const dropTargetId = getDropTargetIdFromDestination(destination); - setActiveDropTargetId(dropTargetId); + const handleDragUpdate = useCallback( + ((update: Parameters[0]) => { + const { source, destination } = update; + if (source.droppableId !== ADD_TO_NAV_SOURCE_DROPPABLE_ID) { + return; + } + if ( + destination !== null && + isWorkspaceDroppableId(destination.droppableId) + ) { + setAddToNavigationFallbackDestination(destination); + const dropTargetId = getDropTargetIdFromDestination(destination); + setActiveDropTargetId(dropTargetId); - const payload = - store - .get(addToNavPayloadRegistryStateV2.atom) - .get(update.draggableId) ?? null; - const folderId = validateAndExtractWorkspaceFolderId( - destination.droppableId, - ); - const isFolderOverFolder = - payload?.type === 'folder' && folderId !== null; - setForbiddenDropTargetId(isFolderOverFolder ? dropTargetId : null); - } else { - setForbiddenDropTargetId(null); - const fallback = addToNavigationFallbackDestination; - setActiveDropTargetId( - fallback ? getDropTargetIdFromDestination(fallback) : null, - ); - } - }) as OnDragUpdateResponder, + const payload = + store + .get(addToNavPayloadRegistryStateV2.atom) + .get(update.draggableId) ?? null; + const folderId = validateAndExtractWorkspaceFolderId( + destination.droppableId, + ); + const isFolderOverFolder = + payload?.type === 'folder' && folderId !== null; + setForbiddenDropTargetId(isFolderOverFolder ? dropTargetId : null); + } else { + setForbiddenDropTargetId(null); + const fallback = addToNavigationFallbackDestination; + setActiveDropTargetId( + fallback ? getDropTargetIdFromDestination(fallback) : null, + ); + } + }) as OnDragUpdateResponder, [addToNavigationFallbackDestination, store], ); diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx index 52a3d5f720..1faed4126f 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx @@ -11,7 +11,7 @@ import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/componen import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer'; import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem'; import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewsFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreViewsFromObjectMetadataItemFamilySelector'; import { ViewKey } from '@/views/types/ViewKey'; @@ -59,7 +59,7 @@ export const NavigationDrawerItemForObjectMetadataItem = ({ { objectMetadataItemId: objectMetadataItem.id }, ); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useDeleteOneFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useDeleteOneFieldMetadataItem.ts index 2b35b0128e..894c7758ce 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useDeleteOneFieldMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useDeleteOneFieldMetadataItem.ts @@ -8,8 +8,8 @@ import { recordIndexGroupAggregateFieldMetadataItemComponentState } from '@/obje import { recordIndexGroupAggregateOperationComponentState } from '@/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { ApolloError } from '@apollo/client'; import { t } from '@lingui/core/macro'; @@ -27,19 +27,22 @@ export const useDeleteOneFieldMetadataItem = () => { const { handleMetadataError } = useMetadataErrorHandler(); const { enqueueErrorSnackBar } = useSnackBar(); - const setRecordIndexGroupAggregateOperation = useSetRecoilComponentState( + const setRecordIndexGroupAggregateOperation = useSetRecoilComponentStateV2( recordIndexGroupAggregateOperationComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const [ - recordIndexGroupAggregateFieldMetadataItem, - setRecordIndexGroupAggregateFieldMetadataItem, - ] = useRecoilComponentState( + const recordIndexGroupAggregateFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupAggregateFieldMetadataItemComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); + const setRecordIndexGroupAggregateFieldMetadataItem = + useSetRecoilComponentStateV2( + recordIndexGroupAggregateFieldMetadataItemComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, + ); + const resetRecordIndexKanbanAggregateOperation = async ( idToDelete: string, ) => { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useGetFieldMetadataItemById.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useGetFieldMetadataItemById.ts index 789b44c3cd..3f39899f25 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useGetFieldMetadataItemById.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useGetFieldMetadataItemById.ts @@ -1,9 +1,10 @@ +import { useCallback } from 'react'; + import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getFieldMetadataItemByIdOrThrow } from '@/object-metadata/utils/getFieldMetadataItemByIdOrThrow'; -import { useRecoilCallback } from 'recoil'; type GetFieldMetadataItemByIdOrThrowResult = { fieldMetadataItem: FieldMetadataItem; @@ -11,20 +12,19 @@ type GetFieldMetadataItemByIdOrThrowResult = { }; export const useGetFieldMetadataItemByIdOrThrow = () => { - const getFieldMetadataItemById = useRecoilCallback( - () => - (fieldMetadataId: string): GetFieldMetadataItemByIdOrThrowResult => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + const getFieldMetadataItemByIdOrThrowCallback = useCallback( + (fieldMetadataId: string): GetFieldMetadataItemByIdOrThrowResult => { + const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); - return getFieldMetadataItemByIdOrThrow({ - fieldMetadataId, - objectMetadataItems, - }); - }, + return getFieldMetadataItemByIdOrThrow({ + fieldMetadataId, + objectMetadataItems, + }); + }, [], ); - return { getFieldMetadataItemByIdOrThrow: getFieldMetadataItemById }; + return { + getFieldMetadataItemByIdOrThrow: getFieldMetadataItemByIdOrThrowCallback, + }; }; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuContainer.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuContainer.tsx index ca985ddcbd..3b41c4beea 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuContainer.tsx @@ -8,7 +8,7 @@ import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/co import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup'; import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -41,7 +41,7 @@ export const AdvancedFilterCommandMenuContainer = ({ VariablePicker, isWorkflowFindRecords, }: AdvancedFilterCommandMenuContainerProps) => { - const rootRecordFilterGroup = useRecoilComponentValue( + const rootRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuCreateRootFilterButton.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuCreateRootFilterButton.tsx index 13216747ba..97452879f9 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuCreateRootFilterButton.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuCreateRootFilterButton.tsx @@ -5,8 +5,8 @@ import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/adv import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup'; import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem'; import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentFamilyStateV2'; import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { t } from '@lingui/core/macro'; @@ -23,7 +23,7 @@ export const AdvancedFilterCommandMenuCreateRootFilterButton = ({ objectMetadataItem: ObjectMetadataItem; }) => { const { readonly } = useContext(AdvancedFilterContext); - const rootRecordFilterGroup = useRecoilComponentValue( + const rootRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); @@ -49,7 +49,7 @@ export const AdvancedFilterCommandMenuCreateRootFilterButton = ({ useCreateEmptyRecordFilterFromFieldMetadataItem(); const setHasInitializedCurrentRecordFilters = - useSetRecoilComponentFamilyState( + useSetRecoilComponentFamilyStateV2( hasInitializedCurrentRecordFiltersComponentFamilyState, {}, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuRecordFilterOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuRecordFilterOperandSelect.tsx index 948597fb2e..246ec36ded 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuRecordFilterOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuRecordFilterOperandSelect.tsx @@ -4,7 +4,7 @@ import { getOperandLabel } from '@/object-record/object-filter-dropdown/utils/ge import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { SelectControl } from '@/ui/input/components/SelectControl'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -17,7 +17,7 @@ export const AdvancedFilterCommandMenuRecordFilterOperandSelect = ({ recordFilterId, }: AdvancedFilterCommandMenuRecordFilterOperandSelectProps) => { const { readonly, isWorkflowFindRecords } = useContext(AdvancedFilterContext); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx index 435771aa41..800739a94a 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx @@ -9,7 +9,7 @@ import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/c import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { CURRENCIES } from '@/settings/data-model/constants/Currencies'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { FieldActorSource } from 'twenty-shared/types'; import { type SelectOption } from 'twenty-ui/input'; @@ -33,7 +33,7 @@ export const AdvancedFilterCommandMenuValueFormCompositeFieldInput = ({ }) => { const { VariablePicker } = useContext(AdvancedFilterContext); - const subFieldNameUsedInDropdown = useRecoilComponentValue( + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormInput.tsx index f4c2bee3f8..de4d02fe54 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormInput.tsx @@ -1,6 +1,7 @@ import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; import { AdvancedFilterCommandMenuValueFormCompositeFieldInput } from '@/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput'; import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; +import { getAdvancedFilterObjectFilterDropdownComponentInstanceId } from '@/object-record/advanced-filter/utils/getAdvancedFilterObjectFilterDropdownComponentInstanceId'; import { shouldShowFilterTextInput } from '@/object-record/advanced-filter/utils/shouldShowFilterTextInput'; import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; @@ -18,7 +19,8 @@ import { } from '@/object-record/record-field/ui/types/FieldMetadata'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { stringifyRelativeDateFilter } from '@/views/view-filter-value/utils/stringifyRelativeDateFilter'; import { WORKFLOW_TIMEZONE } from '@/workflow/constants/WorkflowTimeZone'; import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap'; @@ -41,12 +43,16 @@ export const AdvancedFilterCommandMenuValueFormInput = ({ isWorkflowFindRecords, } = useContext(AdvancedFilterContext); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const subFieldNameUsedInDropdown = useRecoilComponentValue( + const dropdownInstanceId = + getAdvancedFilterObjectFilterDropdownComponentInstanceId(recordFilterId); + + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, + dropdownInstanceId, ); const recordFilter = currentRecordFilters.find( @@ -85,8 +91,9 @@ export const AdvancedFilterCommandMenuValueFormInput = ({ applyObjectFilterDropdownFilterValue(stringifyRelativeDateFilter(newValue)); }; - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, + dropdownInstanceId, ); const fieldDefinition = fieldMetadataItemUsedInDropdown diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx index a539ee8116..8a7fbd1831 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx @@ -19,7 +19,7 @@ import { isFilterOnActorWorkspaceMemberSubField } from '@/object-record/object-f import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { isExpectedSubFieldName } from 'twenty-shared/utils'; @@ -32,7 +32,7 @@ export const AdvancedFilterDropdownFilterInput = ({ filterDropdownId, recordFilter, }: AdvancedFilterDropdownFilterInputProps) => { - const subFieldNameUsedInDropdown = useRecoilComponentValue( + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownNumberInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownNumberInput.tsx index 4c0ef76565..f5d5ed916a 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownNumberInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownNumberInput.tsx @@ -3,15 +3,16 @@ import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filte import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { TextInput } from '@/ui/input/components/TextInput'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; export const AdvancedFilterDropdownNumberInput = () => { - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownContent.tsx index d6d8577d44..d47e7abd46 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownContent.tsx @@ -1,7 +1,7 @@ import { AdvancedFilterFieldSelectMenu } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu'; import { AdvancedFilterSubFieldSelectMenu } from '@/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu'; import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; type AdvancedFilterFieldSelectDropdownContentProps = { recordFilterId: string; @@ -11,7 +11,7 @@ export const AdvancedFilterFieldSelectDropdownContent = ({ recordFilterId, }: AdvancedFilterFieldSelectDropdownContentProps) => { const [objectFilterDropdownIsSelectingCompositeField] = - useRecoilComponentState( + useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx index c6de0d424d..d03e9295ea 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx @@ -6,7 +6,7 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { AdvancedFilterFieldSelectSearchInput } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput'; @@ -23,8 +23,8 @@ import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/h import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useLingui } from '@lingui/react/macro'; import { useContext } from 'react'; import { getFilterTypeFromFieldType } from 'twenty-shared/utils'; @@ -41,8 +41,9 @@ export const AdvancedFilterFieldSelectMenu = ({ advancedFilterFieldSelectDropdownId, } = useAdvancedFilterFieldSelectDropdown(recordFilterId); - const [objectFilterDropdownSearchInput] = useRecoilComponentState( + const [objectFilterDropdownSearchInput] = useRecoilComponentStateV2( objectFilterDropdownSearchInputComponentState, + advancedFilterFieldSelectDropdownId, ); const { objectMetadataItem } = useContext(AdvancedFilterContext); @@ -50,7 +51,7 @@ export const AdvancedFilterFieldSelectMenu = ({ const { filterableFieldMetadataItems: filterableFieldMetadataItems } = useFilterableFieldMetadataItems(objectMetadataItem.id); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); @@ -90,17 +91,20 @@ export const AdvancedFilterFieldSelectMenu = ({ const { selectFieldUsedInAdvancedFilterDropdown } = useSelectFieldUsedInAdvancedFilterDropdown(); - const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentState( + const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentStateV2( objectFilterDropdownSubMenuFieldTypeComponentState, + advancedFilterFieldSelectDropdownId, ); const [, setObjectFilterDropdownIsSelectingCompositeField] = - useRecoilComponentState( + useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, + advancedFilterFieldSelectDropdownId, ); - const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentState( + const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2( fieldMetadataItemIdUsedInDropdownComponentState, + advancedFilterFieldSelectDropdownId, ); const handleFieldMetadataItemSelect = ( diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx index 9e4c1f9758..769701cb9f 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx @@ -1,5 +1,5 @@ import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -31,7 +31,7 @@ export const StyledInput = styled.input` export const AdvancedFilterFieldSelectSearchInput = () => { const [objectFilterDropdownSearchInput, setObjectFilterDropdownSearchInput] = - useRecoilComponentState(objectFilterDropdownSearchInputComponentState); + useRecoilComponentStateV2(objectFilterDropdownSearchInputComponentState); return ( { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown.tsx index 2dbe7d9dd2..66dbba4a85 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown.tsx @@ -10,7 +10,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { IconDotsVertical, IconTrash } from 'twenty-ui/display'; @@ -31,7 +31,7 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({ const { removeRecordFilter } = useRemoveRecordFilter(); const { removeRecordFilterGroup } = useRemoveRecordFilterGroup(); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx index 4798d2479f..2e36b02975 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx @@ -10,7 +10,7 @@ import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/adv import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -24,7 +24,7 @@ const StyledContainer = styled.div` `; export const AdvancedFilterRootRecordFilterGroup = () => { - const rootRecordFilterGroup = useRecoilComponentValue( + const rootRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx index 921506743d..3393d12fc9 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx @@ -1,6 +1,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; @@ -23,7 +24,6 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; import { t } from '@lingui/core/macro'; import { IconChevronLeft, useIcons } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; @@ -37,19 +37,19 @@ export const AdvancedFilterSubFieldSelectMenu = ({ }: AdvancedFilterSubFieldSelectMenuProps) => { const { getIcon } = useIcons(); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); const [, setObjectFilterDropdownIsSelectingCompositeField] = - useRecoilComponentState( + useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, ); const [ objectFilterDropdownSubMenuFieldType, setObjectFilterDropdownSubMenuFieldType, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( objectFilterDropdownSubMenuFieldTypeComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInput.tsx index d86129e64d..58020ece0b 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInput.tsx @@ -11,8 +11,8 @@ import { configurableViewFilterOperands } from '@/object-record/object-filter-dr import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -30,12 +30,13 @@ export const AdvancedFilterValueInput = ({ }: AdvancedFilterValueInputProps) => { const dropdownId = `advanced-filter-view-filter-value-input-${recordFilterId}`; - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const subFieldNameUsedInDropdown = useRecoilComponentValue( + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, + dropdownId, ); const recordFilter = currentRecordFilters.find( @@ -44,17 +45,21 @@ export const AdvancedFilterValueInput = ({ const isDisabled = !recordFilter?.fieldMetadataId || !recordFilter.operand; - const setObjectFilterDropdownSearchInput = useSetRecoilComponentState( + const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2( objectFilterDropdownSearchInputComponentState, + dropdownId, ); - const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentState( + const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2( fieldMetadataItemIdUsedInDropdownComponentState, + dropdownId, ); - const setObjectFilterDropdownCurrentRecordFilter = useSetRecoilComponentState( - objectFilterDropdownCurrentRecordFilterComponentState, - ); + const setObjectFilterDropdownCurrentRecordFilter = + useSetRecoilComponentStateV2( + objectFilterDropdownCurrentRecordFilterComponentState, + dropdownId, + ); const operandHasNoInput = recordFilter && !configurableViewFilterOperands.has(recordFilter.operand); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx index 311a588b5b..c29b0179df 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect.tsx @@ -1,7 +1,7 @@ import { getAdvancedFilterInputPlaceholderText } from '@/object-record/advanced-filter/utils/getAdvancedFilterInputPlacedholderText'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { SelectControl } from '@/ui/input/components/SelectControl'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isNonEmptyString } from '@sniptt/guards'; @@ -36,7 +36,7 @@ type AdvancedFilterValueInputDropdownButtonClickableSelectProps = { export const AdvancedFilterValueInputDropdownButtonClickableSelect = ({ recordFilterId, }: AdvancedFilterValueInputDropdownButtonClickableSelectProps) => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups.ts index d71a59d93e..c7d69c6ef2 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups.ts @@ -2,7 +2,7 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record- import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useChildRecordFiltersAndRecordFilterGroups = ({ @@ -10,11 +10,11 @@ export const useChildRecordFiltersAndRecordFilterGroups = ({ }: { recordFilterGroupId?: string; }) => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useRecordFilterField.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useRecordFilterField.ts index 4c05056f63..a3a5b1fc21 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useRecordFilterField.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useRecordFilterField.ts @@ -3,13 +3,13 @@ import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdow import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { isValidSubFieldName } from '@/settings/data-model/utils/isValidSubFieldName'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isNonEmptyString } from '@sniptt/guards'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; export const useRecordFilterField = (recordFilterId: string) => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts index 2e0bfd96fb..62b62e36df 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts @@ -15,8 +15,8 @@ import { isCompositeTypeNonFilterableByAnySubField } from '@/object-record/recor import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; type SelectFilterParams = { @@ -26,19 +26,19 @@ type SelectFilterParams = { }; export const useSelectFieldUsedInAdvancedFilterDropdown = () => { - const setSelectedOperandInDropdown = useSetRecoilComponentState( + const setSelectedOperandInDropdown = useSetRecoilComponentStateV2( selectedOperandInDropdownComponentState, ); - const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentState( + const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2( fieldMetadataItemIdUsedInDropdownComponentState, ); - const setObjectFilterDropdownSearchInput = useSetRecoilComponentState( + const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2( objectFilterDropdownSearchInputComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -47,13 +47,14 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => { const { getFieldMetadataItemByIdOrThrow } = useGetFieldMetadataItemByIdOrThrow(); - const setSubFieldNameUsedInDropdown = useSetRecoilComponentState( + const setSubFieldNameUsedInDropdown = useSetRecoilComponentStateV2( subFieldNameUsedInDropdownComponentState, ); - const setObjectFilterDropdownCurrentRecordFilter = useSetRecoilComponentState( - objectFilterDropdownCurrentRecordFilterComponentState, - ); + const setObjectFilterDropdownCurrentRecordFilter = + useSetRecoilComponentStateV2( + objectFilterDropdownCurrentRecordFilterComponentState, + ); const { upsertRecordFilter } = useUpsertRecordFilter(); const { getInitialFilterValue } = useGetInitialFilterValue(); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates.ts index ef5ec2369f..3a16831725 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates.ts @@ -6,91 +6,85 @@ import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useCallback } from 'react'; export const useSetAdvancedFilterDropdownStates = () => { - const rootLevelRecordFilterGroup = useRecoilComponentValue( + const rootLevelRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const setAdvancedFilterDropdownStates = useRecoilCallback( - ({ set }) => - () => { - const rootLevelRecordFilters = currentRecordFilters.filter( - (recordFilter) => - recordFilter.recordFilterGroupId === rootLevelRecordFilterGroup?.id, + const setAdvancedFilterDropdownStates = useCallback(() => { + const rootLevelRecordFilters = currentRecordFilters.filter( + (recordFilter) => + recordFilter.recordFilterGroupId === rootLevelRecordFilterGroup?.id, + ); + + const setAdvancedFilterStatesForRecordFilter = ( + recordFilter: RecordFilter, + ) => { + const instanceId = + getAdvancedFilterObjectFilterDropdownComponentInstanceId( + recordFilter.id, ); - const setAdvancedFilterStatesForRecordFilter = ( - recordFilter: RecordFilter, - ) => { - set( - objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({ - instanceId: - getAdvancedFilterObjectFilterDropdownComponentInstanceId( - recordFilter.id, - ), - }), - recordFilter, - ); + jotaiStore.set( + objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({ + instanceId, + }), + recordFilter, + ); - set( - fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ - instanceId: - getAdvancedFilterObjectFilterDropdownComponentInstanceId( - recordFilter.id, - ), - }), - recordFilter.fieldMetadataId, - ); + jotaiStore.set( + fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ + instanceId, + }), + recordFilter.fieldMetadataId, + ); - set( - subFieldNameUsedInDropdownComponentState.atomFamily({ - instanceId: - getAdvancedFilterObjectFilterDropdownComponentInstanceId( - recordFilter.id, - ), - }), - recordFilter.subFieldName, - ); - }; + jotaiStore.set( + subFieldNameUsedInDropdownComponentState.atomFamily({ + instanceId, + }), + recordFilter.subFieldName, + ); + }; - for (const rootLevelRecordFilter of rootLevelRecordFilters) { - setAdvancedFilterStatesForRecordFilter(rootLevelRecordFilter); - } + for (const rootLevelRecordFilter of rootLevelRecordFilters) { + setAdvancedFilterStatesForRecordFilter(rootLevelRecordFilter); + } - const childRecordFilterGroups = currentRecordFilterGroups.filter( - (currentRecordGroupToFilter) => - currentRecordGroupToFilter.parentRecordFilterGroupId === - rootLevelRecordFilterGroup?.id, - ); + const childRecordFilterGroups = currentRecordFilterGroups.filter( + (currentRecordGroupToFilter) => + currentRecordGroupToFilter.parentRecordFilterGroupId === + rootLevelRecordFilterGroup?.id, + ); - for (const childRecordFilterGroup of childRecordFilterGroups) { - const recordFiltersInThisGroup = currentRecordFilters.filter( - (recordFilter) => - recordFilter.recordFilterGroupId === childRecordFilterGroup.id, - ); + for (const childRecordFilterGroup of childRecordFilterGroups) { + const recordFiltersInThisGroup = currentRecordFilters.filter( + (recordFilter) => + recordFilter.recordFilterGroupId === childRecordFilterGroup.id, + ); - for (const recordFilterInThisGroup of recordFiltersInThisGroup) { - setAdvancedFilterStatesForRecordFilter(recordFilterInThisGroup); - } - } - }, - [ - currentRecordFilterGroups, - currentRecordFilters, - rootLevelRecordFilterGroup, - ], - ); + for (const recordFilterInThisGroup of recordFiltersInThisGroup) { + setAdvancedFilterStatesForRecordFilter(recordFilterInThisGroup); + } + } + }, [ + currentRecordFilterGroups, + currentRecordFilters, + rootLevelRecordFilterGroup, + ]); return { setAdvancedFilterDropdownStates, diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow.ts index 52ad5d962d..a666169d3b 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow.ts @@ -3,41 +3,38 @@ import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useSetRecordFilterUsedInAdvancedFilterDropdownRow = () => { - const setRecordFilterUsedInAdvancedFilterDropdownRow = useRecoilCallback( - ({ set }) => - (recordFilter: RecordFilter) => { - const advancedFilterRowObjectFilterDropdownComponentInstanceId = - getAdvancedFilterObjectFilterDropdownComponentInstanceId( - recordFilter.id, - ); - - set( - fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ - instanceId: - advancedFilterRowObjectFilterDropdownComponentInstanceId, - }), - recordFilter.fieldMetadataId, + const setRecordFilterUsedInAdvancedFilterDropdownRow = useCallback( + (recordFilter: RecordFilter) => { + const advancedFilterRowObjectFilterDropdownComponentInstanceId = + getAdvancedFilterObjectFilterDropdownComponentInstanceId( + recordFilter.id, ); - set( - selectedOperandInDropdownComponentState.atomFamily({ - instanceId: - advancedFilterRowObjectFilterDropdownComponentInstanceId, - }), - recordFilter.operand, - ); + jotaiStore.set( + fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ + instanceId: advancedFilterRowObjectFilterDropdownComponentInstanceId, + }), + recordFilter.fieldMetadataId, + ); - set( - objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({ - instanceId: - advancedFilterRowObjectFilterDropdownComponentInstanceId, - }), - recordFilter, - ); - }, + jotaiStore.set( + selectedOperandInDropdownComponentState.atomFamily({ + instanceId: advancedFilterRowObjectFilterDropdownComponentInstanceId, + }), + recordFilter.operand, + ); + + jotaiStore.set( + objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({ + instanceId: advancedFilterRowObjectFilterDropdownComponentInstanceId, + }), + recordFilter, + ); + }, [], ); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector.ts index d5e2711bcc..8e6627c70e 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector.ts @@ -1,17 +1,20 @@ +import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { isDefined } from 'twenty-shared/utils'; export const rootLevelRecordFilterGroupComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'rootLevelRecordFilterGroupComponentSelector', + componentInstanceContext: RecordFilterGroupsComponentInstanceContext, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { const currentRecordFilterGroups = get( - currentRecordFilterGroupsComponentState.atomFamily({ instanceId }), - ); + currentRecordFilterGroupsComponentState, + componentStateKey, + ) as RecordFilterGroup[]; const rootLevelRecordFilterGroup = currentRecordFilterGroups.find( (recordFilterGroup) => @@ -20,5 +23,4 @@ export const rootLevelRecordFilterGroupComponentSelector = return rootLevelRecordFilterGroup; }, - componentInstanceContext: RecordFilterGroupsComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts index 5840efe0f1..e547b08ed0 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts @@ -8,8 +8,7 @@ import { import { type Unmasked } from '@apollo/client/masking'; import { isNonEmptyArray } from '@apollo/client/utilities'; import { isNonEmptyString } from '@sniptt/guards'; -import { useMemo } from 'react'; -import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; +import { useCallback, useMemo } from 'react'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; @@ -30,6 +29,9 @@ import { import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { capitalize, isDefined } from 'twenty-shared/utils'; export type UseFindManyRecordsParams = ObjectMetadataItemIdentifier & @@ -86,10 +88,14 @@ export const useFetchMoreRecordsWithPagination = < orderBy, }); - const [hasNextPage] = useRecoilState(hasNextPageFamilyState(queryIdentifier)); + const hasNextPage = useFamilyRecoilValueV2( + hasNextPageFamilyState, + queryIdentifier, + ); - const setIsFetchingMoreObjects = useSetRecoilState( - isFetchingMoreRecordsFamilyState(queryIdentifier), + const setIsFetchingMoreObjects = useSetFamilyRecoilStateV2( + isFetchingMoreRecordsFamilyState, + queryIdentifier, ); const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ @@ -98,115 +104,108 @@ export const useFetchMoreRecordsWithPagination = < // TODO: put this into a util inspired from https://github.com/apollographql/apollo-client/blob/master/src/utilities/policies/pagination.ts // This function is equivalent to merge function + read function in field policy - const fetchMoreRecords = useRecoilCallback( - ({ snapshot, set }) => - async () => { - const hasNextPageLocal = snapshot - .getLoadable(hasNextPageFamilyState(queryIdentifier)) - .getValue(); + const fetchMoreRecords = useCallback(async () => { + const hasNextPageLocal = jotaiStore.get( + hasNextPageFamilyState.atomFamily(queryIdentifier), + ); - const lastCursorLocal = snapshot - .getLoadable(cursorFamilyState(queryIdentifier)) - .getValue(); + const lastCursorLocal = jotaiStore.get( + cursorFamilyState.atomFamily(queryIdentifier), + ); - // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. - if ( - hasNextPageLocal || - (!isAggregationEnabled(objectMetadataItem) && !error) - ) { - setIsFetchingMoreObjects(true); + // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. + if ( + hasNextPageLocal || + (!isAggregationEnabled(objectMetadataItem) && !error) + ) { + setIsFetchingMoreObjects(true); - try { - const { data: fetchMoreDataResult } = await fetchMore({ - variables: { - filter, - orderBy, - lastCursor: isNonEmptyString(lastCursorLocal) - ? lastCursorLocal - : undefined, + try { + const { data: fetchMoreDataResult } = await fetchMore({ + variables: { + filter, + orderBy, + lastCursor: isNonEmptyString(lastCursorLocal) + ? lastCursorLocal + : undefined, + }, + updateQuery: (prev, { fetchMoreResult }) => { + const previousEdges = prev?.[objectMetadataItem.namePlural]?.edges; + const nextEdges = + fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; + let newEdges: RecordGqlEdge[] = previousEdges ?? []; + + if (isNonEmptyArray(nextEdges)) { + newEdges = filterUniqueRecordEdgesByCursor([ + ...newEdges, + ...(fetchMoreResult?.[objectMetadataItem.namePlural]?.edges ?? + []), + ]); + } + + const pageInfo = + fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; + + if (isDefined(pageInfo)) { + jotaiStore.set( + cursorFamilyState.atomFamily(queryIdentifier), + pageInfo.endCursor ?? '', + ); + jotaiStore.set( + hasNextPageFamilyState.atomFamily(queryIdentifier), + pageInfo.hasNextPage ?? false, + ); + } + + const records = getRecordsFromRecordConnection({ + recordConnection: { + edges: newEdges, + pageInfo, }, - updateQuery: (prev, { fetchMoreResult }) => { - const previousEdges = - prev?.[objectMetadataItem.namePlural]?.edges; - const nextEdges = - fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; - let newEdges: RecordGqlEdge[] = previousEdges ?? []; + }) as T[]; - if (isNonEmptyArray(nextEdges)) { - newEdges = filterUniqueRecordEdgesByCursor([ - ...newEdges, - ...(fetchMoreResult?.[objectMetadataItem.namePlural] - ?.edges ?? []), - ]); - } - - const pageInfo = - fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; - - if (isDefined(pageInfo)) { - set( - cursorFamilyState(queryIdentifier), - pageInfo.endCursor ?? '', - ); - set( - hasNextPageFamilyState(queryIdentifier), - pageInfo.hasNextPage ?? false, - ); - } - - const records = getRecordsFromRecordConnection({ - recordConnection: { - edges: newEdges, - pageInfo, - }, - }) as T[]; - - onCompleted?.(records, { - pageInfo, - totalCount: - fetchMoreResult?.[objectMetadataItem.namePlural] - ?.totalCount, - }); - - return Object.assign({}, prev, { - [objectMetadataItem.namePlural]: { - __typename: `${capitalize( - objectMetadataItem.nameSingular, - )}Connection`, - edges: newEdges, - pageInfo: - fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, - totalCount: - fetchMoreResult?.[objectMetadataItem.namePlural] - .totalCount, - }, - } as RecordGqlOperationFindManyResult); - }, + onCompleted?.(records, { + pageInfo, + totalCount: + fetchMoreResult?.[objectMetadataItem.namePlural]?.totalCount, }); - return { - data: fetchMoreDataResult?.[objectMetadataItem.namePlural], - }; - } catch (error) { - handleFindManyRecordsError(error as ApolloError); - return { error: error as ApolloError }; - } finally { - setIsFetchingMoreObjects(false); - } - } - }, - [ - objectMetadataItem, - error, - setIsFetchingMoreObjects, - fetchMore, - filter, - orderBy, - onCompleted, - handleFindManyRecordsError, - queryIdentifier, - ], - ); + return Object.assign({}, prev, { + [objectMetadataItem.namePlural]: { + __typename: `${capitalize( + objectMetadataItem.nameSingular, + )}Connection`, + edges: newEdges, + pageInfo: + fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, + totalCount: + fetchMoreResult?.[objectMetadataItem.namePlural].totalCount, + }, + } as RecordGqlOperationFindManyResult); + }, + }); + + return { + data: fetchMoreDataResult?.[objectMetadataItem.namePlural], + }; + } catch (error) { + handleFindManyRecordsError(error as ApolloError); + return { error: error as ApolloError }; + } finally { + setIsFetchingMoreObjects(false); + } + } + }, [ + objectMetadataItem, + error, + setIsFetchingMoreObjects, + fetchMore, + filter, + orderBy, + onCompleted, + handleFindManyRecordsError, + queryIdentifier, + ]); const totalCount = data?.[objectMetadataItem.namePlural]?.totalCount; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts index 0028e5816f..87cce36186 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts @@ -4,7 +4,8 @@ import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/t import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useHandleFindManyRecordsCompleted = ({ @@ -16,28 +17,30 @@ export const useHandleFindManyRecordsCompleted = ({ objectMetadataItem: ObjectMetadataItem; onCompleted?: OnFindManyRecordsCompleted; }) => { - const handleFindManyRecordsCompleted = useRecoilCallback( - ({ set }) => - (data: RecordGqlOperationFindManyResult) => { - const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; + const handleFindManyRecordsCompleted = useCallback( + (data: RecordGqlOperationFindManyResult) => { + const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; - const records = getRecordsFromRecordConnection({ - recordConnection: data?.[objectMetadataItem.namePlural], - }) as T[]; + const records = getRecordsFromRecordConnection({ + recordConnection: data?.[objectMetadataItem.namePlural], + }) as T[]; - onCompleted?.(records, { - pageInfo, - totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, - }); + onCompleted?.(records, { + pageInfo, + totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, + }); - if (isDefined(data?.[objectMetadataItem.namePlural])) { - set(cursorFamilyState(queryIdentifier), pageInfo.endCursor ?? ''); - set( - hasNextPageFamilyState(queryIdentifier), - pageInfo.hasNextPage ?? false, - ); - } - }, + if (isDefined(data?.[objectMetadataItem.namePlural])) { + jotaiStore.set( + cursorFamilyState.atomFamily(queryIdentifier), + pageInfo.endCursor ?? '', + ); + jotaiStore.set( + hasNextPageFamilyState.atomFamily(queryIdentifier), + pageInfo.hasNextPage ?? false, + ); + } + }, [objectMetadataItem.namePlural, onCompleted, queryIdentifier], ); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts index c8ad297cbb..f7d60cfc46 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts @@ -8,7 +8,7 @@ import { import { type Unmasked } from '@apollo/client/masking'; import { isNonEmptyArray } from '@apollo/client/utilities'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; @@ -29,6 +29,7 @@ import { import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit'; import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { capitalize, isDefined } from 'twenty-shared/utils'; export type UseFindManyRecordsParams = ObjectMetadataItemIdentifier & @@ -89,99 +90,96 @@ export const useLazyFetchMoreRecordsWithPagination = < // TODO: put this into a util inspired from https://github.com/apollographql/apollo-client/blob/master/src/utilities/policies/pagination.ts // This function is equivalent to merge function + read function in field policy - const fetchMoreRecordsLazy = useRecoilCallback( - ({ snapshot, set }) => - async (limit = DEFAULT_SEARCH_REQUEST_LIMIT) => { - const hasNextPageLocal = snapshot - .getLoadable(hasNextPageFamilyState(queryIdentifier)) - .getValue(); + const fetchMoreRecordsLazy = useCallback( + async (limit = DEFAULT_SEARCH_REQUEST_LIMIT) => { + const hasNextPageLocal = jotaiStore.get( + hasNextPageFamilyState.atomFamily(queryIdentifier), + ); - const lastCursorLocal = snapshot - .getLoadable(cursorFamilyState(queryIdentifier)) - .getValue(); + const lastCursorLocal = jotaiStore.get( + cursorFamilyState.atomFamily(queryIdentifier), + ); - // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. - if ( - hasNextPageLocal || - (!isAggregationEnabled(objectMetadataItem) && !error) - ) { - try { - const { data: fetchMoreDataResult } = await fetchMore({ - variables: { - limit, - filter, - orderBy, - lastCursor: isNonEmptyString(lastCursorLocal) - ? lastCursorLocal - : undefined, - }, - updateQuery: (prev, { fetchMoreResult }) => { - const previousEdges = - prev?.[objectMetadataItem.namePlural]?.edges; - const nextEdges = - fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; + // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. + if ( + hasNextPageLocal || + (!isAggregationEnabled(objectMetadataItem) && !error) + ) { + try { + const { data: fetchMoreDataResult } = await fetchMore({ + variables: { + limit, + filter, + orderBy, + lastCursor: isNonEmptyString(lastCursorLocal) + ? lastCursorLocal + : undefined, + }, + updateQuery: (prev, { fetchMoreResult }) => { + const previousEdges = + prev?.[objectMetadataItem.namePlural]?.edges; + const nextEdges = + fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; - let newEdges: RecordGqlEdge[] = previousEdges ?? []; + let newEdges: RecordGqlEdge[] = previousEdges ?? []; - if (isNonEmptyArray(nextEdges)) { - newEdges = filterUniqueRecordEdgesByCursor([ - ...newEdges, - ...(fetchMoreResult?.[objectMetadataItem.namePlural] - ?.edges ?? []), - ]); - } + if (isNonEmptyArray(nextEdges)) { + newEdges = filterUniqueRecordEdgesByCursor([ + ...newEdges, + ...(fetchMoreResult?.[objectMetadataItem.namePlural]?.edges ?? + []), + ]); + } - const pageInfo = - fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; + const pageInfo = + fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; - if (isDefined(pageInfo)) { - set( - cursorFamilyState(queryIdentifier), - pageInfo.endCursor ?? '', - ); - set( - hasNextPageFamilyState(queryIdentifier), - pageInfo.hasNextPage ?? false, - ); - } + if (isDefined(pageInfo)) { + jotaiStore.set( + cursorFamilyState.atomFamily(queryIdentifier), + pageInfo.endCursor ?? '', + ); + jotaiStore.set( + hasNextPageFamilyState.atomFamily(queryIdentifier), + pageInfo.hasNextPage ?? false, + ); + } - return Object.assign({}, prev, { - [objectMetadataItem.namePlural]: { - __typename: `${capitalize( - objectMetadataItem.nameSingular, - )}Connection`, - edges: newEdges, - pageInfo: - fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, - totalCount: - fetchMoreResult?.[objectMetadataItem.namePlural] - .totalCount, - }, - } as RecordGqlOperationFindManyResult); - }, - }); - - return { - data: fetchMoreDataResult?.[objectMetadataItem.namePlural], - totalCount: - fetchMoreDataResult?.[objectMetadataItem.namePlural] - ?.totalCount, - records: getRecordsFromRecordConnection({ - recordConnection: { - edges: - fetchMoreDataResult?.[objectMetadataItem.namePlural]?.edges, + return Object.assign({}, prev, { + [objectMetadataItem.namePlural]: { + __typename: `${capitalize( + objectMetadataItem.nameSingular, + )}Connection`, + edges: newEdges, pageInfo: - fetchMoreDataResult?.[objectMetadataItem.namePlural] - ?.pageInfo, + fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, + totalCount: + fetchMoreResult?.[objectMetadataItem.namePlural].totalCount, }, - }) as T[], - }; - } catch (error) { - handleFindManyRecordsError(error as ApolloError); - return { error: error as ApolloError }; - } + } as RecordGqlOperationFindManyResult); + }, + }); + + return { + data: fetchMoreDataResult?.[objectMetadataItem.namePlural], + totalCount: + fetchMoreDataResult?.[objectMetadataItem.namePlural]?.totalCount, + records: getRecordsFromRecordConnection({ + recordConnection: { + edges: + fetchMoreDataResult?.[objectMetadataItem.namePlural]?.edges, + pageInfo: + fetchMoreDataResult?.[objectMetadataItem.namePlural] + ?.pageInfo, + }, + }) as T[], + }; + } catch (error) { + handleFindManyRecordsError(error as ApolloError); + return { error: error as ApolloError }; } - }, + } + }, [ queryIdentifier, objectMetadataItem, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts index d11fafad71..0a96c21687 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts @@ -1,5 +1,5 @@ import { useLazyQuery } from '@apollo/client'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -13,6 +13,7 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPe import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; import { QUERY_DEFAULT_LIMIT_RECORDS } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; @@ -80,70 +81,67 @@ export const useLazyFindManyRecords = ({ objectMetadataItem, }); - const findManyRecordsLazy = useRecoilCallback( - ({ set }) => - async () => { - if (!hasReadPermission) { - set(hasNextPageFamilyState(queryIdentifier), false); - set(cursorFamilyState(queryIdentifier), ''); + const findManyRecordsLazy = useCallback(async () => { + if (!hasReadPermission) { + jotaiStore.set(hasNextPageFamilyState.atomFamily(queryIdentifier), false); + jotaiStore.set(cursorFamilyState.atomFamily(queryIdentifier), ''); - return { - data: null, - records: null, - totalCount: 0, - hasNextPage: false, - error: undefined, - }; - } + return { + data: null, + records: null, + totalCount: 0, + hasNextPage: false, + error: undefined, + }; + } - const result = await findManyRecords(); - if (isDefined(result?.error)) { - handleFindManyRecordsError(result.error); - } + const result = await findManyRecords(); + if (isDefined(result?.error)) { + handleFindManyRecordsError(result.error); + } - const hasNextPage = - result?.data?.[objectMetadataItem.namePlural]?.pageInfo.hasNextPage ?? - false; + const hasNextPage = + result?.data?.[objectMetadataItem.namePlural]?.pageInfo.hasNextPage ?? + false; - const lastCursor = - result?.data?.[objectMetadataItem.namePlural]?.pageInfo.endCursor ?? - ''; + const lastCursor = + result?.data?.[objectMetadataItem.namePlural]?.pageInfo.endCursor ?? ''; - set(hasNextPageFamilyState(queryIdentifier), hasNextPage); - set(cursorFamilyState(queryIdentifier), lastCursor); + jotaiStore.set( + hasNextPageFamilyState.atomFamily(queryIdentifier), + hasNextPage, + ); + jotaiStore.set(cursorFamilyState.atomFamily(queryIdentifier), lastCursor); - const records = getRecordsFromRecordConnection({ - recordConnection: { - edges: result?.data?.[objectMetadataItem.namePlural]?.edges ?? [], - pageInfo: result?.data?.[objectMetadataItem.namePlural] - ?.pageInfo ?? { - hasNextPage: false, - hasPreviousPage: false, - startCursor: '', - endCursor: '', - }, - }, - }); - - const totalCount = - result?.data?.[objectMetadataItem.namePlural]?.totalCount ?? 0; - - return { - data: result?.data, - records, - totalCount, - hasNextPage, - error: result?.error, - }; + const records = getRecordsFromRecordConnection({ + recordConnection: { + edges: result?.data?.[objectMetadataItem.namePlural]?.edges ?? [], + pageInfo: result?.data?.[objectMetadataItem.namePlural]?.pageInfo ?? { + hasNextPage: false, + hasPreviousPage: false, + startCursor: '', + endCursor: '', + }, }, - [ - hasReadPermission, - findManyRecords, - objectMetadataItem.namePlural, - queryIdentifier, - handleFindManyRecordsError, - ], - ); + }); + + const totalCount = + result?.data?.[objectMetadataItem.namePlural]?.totalCount ?? 0; + + return { + data: result?.data, + records, + totalCount, + hasNextPage, + error: result?.error, + }; + }, [ + hasReadPermission, + findManyRecords, + objectMetadataItem.namePlural, + queryIdentifier, + handleFindManyRecordsError, + ]); return { findManyRecordsLazy, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecordsWithOffset.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecordsWithOffset.ts index 6267e2377d..13f365b521 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecordsWithOffset.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecordsWithOffset.ts @@ -1,5 +1,5 @@ import { useLazyQuery } from '@apollo/client'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -60,8 +60,8 @@ export const useLazyFindManyRecordsWithOffset = ({ }, ); - const findManyRecordsLazyWithOffset = useRecoilCallback( - () => async (limit: number, offset: number) => { + const findManyRecordsLazyWithOffset = useCallback( + async (limit: number, offset: number) => { if (!hasReadPermission) { return { data: null, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownActorSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownActorSelect.tsx index d1d5803d76..a57f6704c0 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownActorSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownActorSelect.tsx @@ -8,7 +8,7 @@ import { MultipleSelectDropdown } from '@/object-record/select/components/Multip import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { type SelectableItem } from '@/object-record/select/types/SelectableItem'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type RelationFilterValue } from '@/views/view-filter-value/types/RelationFilterValue'; import { t } from '@lingui/core/macro'; import { @@ -37,7 +37,7 @@ export const ObjectFilterDropdownActorSelect = ({ const { applyObjectFilterDropdownFilterValue } = useApplyObjectFilterDropdownFilterValue(); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownAnyFieldSearchInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownAnyFieldSearchInput.tsx index 81034600ba..f226bba443 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownAnyFieldSearchInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownAnyFieldSearchInput.tsx @@ -1,13 +1,13 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useLingui } from '@lingui/react/macro'; export const ObjectFilterDropdownAnyFieldSearchInput = () => { const { t } = useLingui(); const [anyFieldFilterSearchValue, setAnyFieldFilterSearchValue] = - useRecoilComponentState(anyFieldFilterValueComponentState); + useRecoilComponentStateV2(anyFieldFilterValueComponentState); const handleSearchChange = (event: React.ChangeEvent) => { const inputValue = event.target.value; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx index d410fbb69a..f083bd5106 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx @@ -3,13 +3,13 @@ import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filte import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; export const ObjectFilterDropdownContentWrapper = ({ children, }: React.PropsWithChildren) => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCountrySelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCountrySelect.tsx index 7521ee2817..cc1bbfad50 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCountrySelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCountrySelect.tsx @@ -10,7 +10,8 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { type ChangeEvent, useState } from 'react'; @@ -23,16 +24,17 @@ export const MAX_ITEMS_TO_DISPLAY = 5; export const ObjectFilterDropdownCountrySelect = () => { const [searchText, setSearchText] = useState(''); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); const { applyObjectFilterDropdownFilterValue } = useApplyObjectFilterDropdownFilterValue(); - const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); + const fieldMetadataItemUsedInFilterDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); const countries = useCountries(); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect.tsx index 9860653ba9..60cdc93634 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect.tsx @@ -9,7 +9,8 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { type ChangeEvent, useState } from 'react'; @@ -22,16 +23,17 @@ export const MAX_ITEMS_TO_DISPLAY = 3; export const ObjectFilterDropdownCurrencySelect = () => { const [searchText, setSearchText] = useState(''); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); const { applyObjectFilterDropdownFilterValue } = useApplyObjectFilterDropdownFilterValue(); - const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); + const fieldMetadataItemUsedInFilterDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); const currenciesAsSelectableItems = CURRENCIES.map( turnCurrencyIntoSelectableItem, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index 530d806283..05ae600f86 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -7,31 +7,30 @@ import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object- import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue'; import { DatePicker } from '@/ui/input/components/internal/date/components/DatePicker'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { UserContext } from '@/users/contexts/UserContext'; import { stringifyRelativeDateFilter } from '@/views/view-filter-value/utils/stringifyRelativeDateFilter'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { type FirstDayOfTheWeek, ViewFilterOperand } from 'twenty-shared/types'; import { isDefined, type RelativeDateFilter, resolveDateFilter, } from 'twenty-shared/utils'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { formatDateString } from '~/utils/string/formatDateString'; export const ObjectFilterDropdownDateInput = () => { const { dateFormat, timeZone } = useContext(UserContext); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateTimeInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateTimeInput.tsx index 947a144d15..20411b0555 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateTimeInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateTimeInput.tsx @@ -6,12 +6,11 @@ import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object- import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue'; import { DateTimePicker } from '@/ui/input/components/internal/date/components/DateTimePicker'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { UserContext } from '@/users/contexts/UserContext'; import { stringifyRelativeDateFilter } from '@/views/view-filter-value/utils/stringifyRelativeDateFilter'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { ViewFilterOperand, type FirstDayOfTheWeek } from 'twenty-shared/types'; import { isDefined, @@ -22,17 +21,17 @@ import { import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; import { isNonEmptyString } from '@sniptt/guards'; import { Temporal } from 'temporal-polyfill'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { formatDateTimeString } from '~/utils/string/formatDateTimeString'; export const ObjectFilterDropdownDateTimeInput = () => { const { dateFormat, timeFormat, timeZone } = useContext(UserContext); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState); const { userTimezone } = useUserTimezone(); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx index 906f14155b..63540799ce 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx @@ -17,7 +17,8 @@ import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/cons import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; type ObjectFilterDropdownFilterInputProps = { @@ -33,11 +34,11 @@ export const ObjectFilterDropdownFilterInput = ({ const isWholeDayFilterEnabled = featureFlags.IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED ?? false; - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx index b51ac789b8..4340c8bf75 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx @@ -3,7 +3,7 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { useContext } from 'react'; @@ -11,7 +11,7 @@ import { IconX } from 'twenty-ui/display'; // TODO: we shouldn't guess in which parent we are, this should be splitted in two components, one for each case export const ObjectFilterDropdownFilterInputHeader = () => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx index 2e65da73dc..f8b59b6a6a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx @@ -11,7 +11,8 @@ import { getRecordFilterOperands } from '@/object-record/record-filter/utils/get import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; import { DropdownMenuInnerSelect } from '@/ui/layout/dropdown/components/DropdownMenuInnerSelect'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { type SelectOption } from 'twenty-ui/input'; @@ -19,15 +20,15 @@ const OBJECT_FILTER_DROPDOWN_INNER_SELECT_OPERAND_DROPDOWN_ID = 'object-filter-dropdown-inner-select-operand-dropdown'; export const ObjectFilterDropdownInnerSelectOperandDropdown = () => { - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); - const subFieldNameUsedInDropdown = useRecoilComponentValue( + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx index 51ecc51633..a851a75340 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx @@ -6,7 +6,7 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; type ObjectFilterDropdownNumberInputProps = { filterDropdownId: string; @@ -15,7 +15,7 @@ type ObjectFilterDropdownNumberInputProps = { export const ObjectFilterDropdownNumberInput = ({ filterDropdownId, }: ObjectFilterDropdownNumberInputProps) => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx index cac7e9dd57..b170940733 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx @@ -17,7 +17,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { isNonEmptyString } from '@sniptt/guards'; @@ -36,11 +36,11 @@ export const ObjectFilterDropdownOptionSelect = ({ }: { focusId: string; }) => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); @@ -48,7 +48,7 @@ export const ObjectFilterDropdownOptionSelect = ({ ObjectFilterDropdownComponentInstanceContext, ); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 667ab80e94..ba181deaa0 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -12,7 +12,8 @@ import { MultipleSelectDropdown } from '@/object-record/select/components/Multip import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { type SelectableItem } from '@/object-record/select/types/SelectableItem'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type RelationFilterValue } from '@/views/view-filter-value/types/RelationFilterValue'; import { arrayOfUuidOrVariableSchema, @@ -39,9 +40,10 @@ export const ObjectFilterDropdownRecordSelect = ({ recordFilterId, dropdownId, }: ObjectFilterDropdownRecordSelectProps) => { - const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); + const fieldMetadataItemUsedInFilterDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); const allowRequestsToTwentyIcons = useRecoilValueV2( allowRequestsToTwentyIconsState, @@ -53,15 +55,15 @@ export const ObjectFilterDropdownRecordSelect = ({ const { applyObjectFilterDropdownFilterValue } = useApplyObjectFilterDropdownFilterValue(); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput.tsx index 856abdb66e..327cbbbe09 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput.tsx @@ -4,23 +4,24 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const ObjectFilterDropdownSearchInput = () => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); - const setObjectFilterDropdownSearchInput = useSetRecoilComponentState( + const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2( objectFilterDropdownSearchInputComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx index 68681b9f4d..4b48567a78 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx @@ -7,7 +7,8 @@ import { MultipleSelectDropdown } from '@/object-record/select/components/Multip import { type SelectableItem } from '@/object-record/select/types/SelectableItem'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { isDefined } from 'twenty-shared/utils'; @@ -20,15 +21,16 @@ export const ObjectFilterDropdownSourceSelect = ({ }: { dropdownId: string; }) => { - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); - const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); + const fieldMetadataItemUsedInFilterDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx index 522d188413..ee5360d9f3 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx @@ -6,7 +6,7 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; type ObjectFilterDropdownTextInputProps = { filterDropdownId: string; @@ -15,7 +15,7 @@ type ObjectFilterDropdownTextInputProps = { export const ObjectFilterDropdownTextInput = ({ filterDropdownId, }: ObjectFilterDropdownTextInputProps) => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue.ts index b65edc495f..a08b199323 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue.ts @@ -1,20 +1,23 @@ +import { useCallback } from 'react'; + import { useUpsertObjectFilterDropdownCurrentFilter } from '@/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; import { useCreateRecordFilterFromObjectFilterDropdownCurrentStates } from '@/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useApplyObjectFilterDropdownFilterValue = () => { - const objectFilterDropdownCurrentRecordFilterCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownCurrentRecordFilterAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownCurrentRecordFilterComponentState, ); - const fieldMetadataItemUsedInDropdownCallbackState = - useRecoilComponentCallbackState( + const fieldMetadataItemUsedInDropdownAtom = + useRecoilComponentSelectorCallbackStateV2( fieldMetadataItemUsedInDropdownComponentSelector, ); @@ -24,51 +27,50 @@ export const useApplyObjectFilterDropdownFilterValue = () => { const { upsertObjectFilterDropdownCurrentFilter } = useUpsertObjectFilterDropdownCurrentFilter(); - const applyObjectFilterDropdownFilterValue = useRecoilCallback( - ({ snapshot }) => - (newFilterValue: string, newDisplayValue?: string) => { - const objectFilterDropdownCurrentRecordFilter = snapshot - .getLoadable(objectFilterDropdownCurrentRecordFilterCallbackState) - .getValue(); + const applyObjectFilterDropdownFilterValue = useCallback( + (newFilterValue: string, newDisplayValue?: string) => { + const objectFilterDropdownCurrentRecordFilter = jotaiStore.get( + objectFilterDropdownCurrentRecordFilterAtom, + ) as RecordFilter | undefined | null; - const fieldMetadataItemUsedInDropdown = snapshot - .getLoadable(fieldMetadataItemUsedInDropdownCallbackState) - .getValue(); + const fieldMetadataItemUsedInDropdown = jotaiStore.get( + fieldMetadataItemUsedInDropdownAtom, + ); - const objectFilterDropdownFilterNotYetCreated = !isDefined( - objectFilterDropdownCurrentRecordFilter, - ); + const objectFilterDropdownFilterNotYetCreated = !isDefined( + objectFilterDropdownCurrentRecordFilter, + ); - if (objectFilterDropdownFilterNotYetCreated) { - if (!isDefined(fieldMetadataItemUsedInDropdown)) { - throw new Error( - `Field metadata item is not defined in object filter dropdown when setting a filter value to create it, this should not happen.`, - ); - } - - const { newRecordFilterFromObjectFilterDropdownStates } = - createRecordFilterFromObjectFilterDropdownCurrentStates(); - - const newCurrentRecordFilter = { - ...newRecordFilterFromObjectFilterDropdownStates, - value: newFilterValue, - displayValue: newDisplayValue ?? newFilterValue, - } satisfies RecordFilter; - - upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter); - } else { - const newCurrentRecordFilter = { - ...objectFilterDropdownCurrentRecordFilter, - value: newFilterValue, - displayValue: newDisplayValue ?? newFilterValue, - } satisfies RecordFilter; - - upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter); + if (objectFilterDropdownFilterNotYetCreated) { + if (!isDefined(fieldMetadataItemUsedInDropdown)) { + throw new Error( + `Field metadata item is not defined in object filter dropdown when setting a filter value to create it, this should not happen.`, + ); } - }, + + const { newRecordFilterFromObjectFilterDropdownStates } = + createRecordFilterFromObjectFilterDropdownCurrentStates(); + + const newCurrentRecordFilter = { + ...newRecordFilterFromObjectFilterDropdownStates, + value: newFilterValue, + displayValue: newDisplayValue ?? newFilterValue, + } satisfies RecordFilter; + + upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter); + } else { + const newCurrentRecordFilter = { + ...objectFilterDropdownCurrentRecordFilter, + value: newFilterValue, + displayValue: newDisplayValue ?? newFilterValue, + } satisfies RecordFilter; + + upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter); + } + }, [ - objectFilterDropdownCurrentRecordFilterCallbackState, - fieldMetadataItemUsedInDropdownCallbackState, + objectFilterDropdownCurrentRecordFilterAtom, + fieldMetadataItemUsedInDropdownAtom, createRecordFilterFromObjectFilterDropdownCurrentStates, upsertObjectFilterDropdownCurrentFilter, ], diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand.ts index e46c6c7a09..1eec3866a5 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand.ts @@ -10,8 +10,9 @@ import { useGetRelativeDateFilterWithUserTimezone } from '@/object-record/record import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { stringifyRelativeDateFilter } from '@/views/view-filter-value/utils/stringifyRelativeDateFilter'; import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap'; @@ -23,11 +24,11 @@ import { export const useApplyObjectFilterDropdownOperand = () => { const { userTimezone } = useUserTimezone(); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); - const setSelectedOperandInDropdown = useSetRecoilComponentState( + const setSelectedOperandInDropdown = useSetRecoilComponentStateV2( selectedOperandInDropdownComponentState, ); @@ -35,7 +36,7 @@ export const useApplyObjectFilterDropdownOperand = () => { objectFilterDropdownCurrentRecordFilter, ); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter.ts index 8e733f1b20..3df3c2be67 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter.ts @@ -1,32 +1,30 @@ +import { useCallback } from 'react'; + import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useEmptyRecordFilter = (componentInstanceId?: string) => { - const objectFilterDropdownSearchInputCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownSearchInputAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownSearchInputComponentState, componentInstanceId, ); - const objectFilterDropdownCurrentRecordFilter = - useRecoilComponentCallbackState( + const objectFilterDropdownCurrentRecordFilterAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownCurrentRecordFilterComponentState, componentInstanceId, ); - const emptyRecordFilter = useRecoilCallback( - ({ set }) => - () => { - set(objectFilterDropdownSearchInputCallbackState, ''); - set(objectFilterDropdownCurrentRecordFilter, undefined); - }, - [ - objectFilterDropdownSearchInputCallbackState, - objectFilterDropdownCurrentRecordFilter, - ], - ); + const emptyRecordFilter = useCallback(() => { + jotaiStore.set(objectFilterDropdownSearchInputAtom, ''); + jotaiStore.set(objectFilterDropdownCurrentRecordFilterAtom, undefined); + }, [ + objectFilterDropdownSearchInputAtom, + objectFilterDropdownCurrentRecordFilterAtom, + ]); return { emptyRecordFilter, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems.ts index d5d79768de..fb04fef001 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems.ts @@ -2,19 +2,20 @@ import { objectFilterDropdownSearchInputComponentState } from '@/object-record/o import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useFilterDropdownSelectableFieldMetadataItems = () => { const { recordIndexId } = useRecordIndexContextOrThrow(); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); const { filterableFieldMetadataItems } = useFilterableFieldMetadataItemsInRecordIndexContext(); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue.ts index 7a228f12a2..aba751ac22 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue.ts @@ -1,8 +1,8 @@ import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useObjectFilterDropdownFilterValue = () => { - const currentRecordFilter = useRecoilComponentValue( + const currentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useResetFilterDropdown.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useResetFilterDropdown.ts index 452086dd7d..2981ca981d 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useResetFilterDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useResetFilterDropdown.ts @@ -1,3 +1,5 @@ +import { useCallback } from 'react'; + import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; import { objectFilterDropdownAnyFieldSearchIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState'; import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; @@ -5,73 +7,68 @@ import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-rec import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useResetFilterDropdown = (componentInstanceId?: string) => { - const objectFilterDropdownSearchInputCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownSearchInputAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownSearchInputComponentState, componentInstanceId, ); - const fieldMetadataItemIdUsedInDropdownCallbackState = - useRecoilComponentCallbackState( + const fieldMetadataItemIdUsedInDropdownAtom = + useRecoilComponentStateCallbackStateV2( fieldMetadataItemIdUsedInDropdownComponentState, componentInstanceId, ); - const selectedOperandInDropdownCallbackState = - useRecoilComponentCallbackState( - selectedOperandInDropdownComponentState, - componentInstanceId, - ); + const selectedOperandInDropdownAtom = useRecoilComponentStateCallbackStateV2( + selectedOperandInDropdownComponentState, + componentInstanceId, + ); - const objectFilterDropdownFilterIsSelectedCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownFilterIsSelectedAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownFilterIsSelectedComponentState, componentInstanceId, ); - const objectFilterDropdownAnyFieldSearchIsSelectedCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownAnyFieldSearchIsSelectedAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownAnyFieldSearchIsSelectedComponentState, componentInstanceId, ); - const objectFilterDropdownIsSelectingCompositeFieldCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownIsSelectingCompositeFieldAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, componentInstanceId, ); - const objectFilterDropdownCurrentRecordFilterCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownCurrentRecordFilterAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownCurrentRecordFilterComponentState, componentInstanceId, ); - const resetFilterDropdown = useRecoilCallback( - ({ set }) => - () => { - set(objectFilterDropdownSearchInputCallbackState, ''); - set(selectedOperandInDropdownCallbackState, null); - set(objectFilterDropdownFilterIsSelectedCallbackState, false); - set(objectFilterDropdownIsSelectingCompositeFieldCallbackState, false); - set(fieldMetadataItemIdUsedInDropdownCallbackState, null); - set(objectFilterDropdownCurrentRecordFilterCallbackState, null); - set(objectFilterDropdownAnyFieldSearchIsSelectedCallbackState, false); - }, - [ - objectFilterDropdownSearchInputCallbackState, - selectedOperandInDropdownCallbackState, - objectFilterDropdownFilterIsSelectedCallbackState, - objectFilterDropdownIsSelectingCompositeFieldCallbackState, - fieldMetadataItemIdUsedInDropdownCallbackState, - objectFilterDropdownCurrentRecordFilterCallbackState, - objectFilterDropdownAnyFieldSearchIsSelectedCallbackState, - ], - ); + const resetFilterDropdown = useCallback(() => { + jotaiStore.set(objectFilterDropdownSearchInputAtom, ''); + jotaiStore.set(selectedOperandInDropdownAtom, null); + jotaiStore.set(objectFilterDropdownFilterIsSelectedAtom, false); + jotaiStore.set(objectFilterDropdownIsSelectingCompositeFieldAtom, false); + jotaiStore.set(fieldMetadataItemIdUsedInDropdownAtom, null); + jotaiStore.set(objectFilterDropdownCurrentRecordFilterAtom, null); + jotaiStore.set(objectFilterDropdownAnyFieldSearchIsSelectedAtom, false); + }, [ + objectFilterDropdownSearchInputAtom, + selectedOperandInDropdownAtom, + objectFilterDropdownFilterIsSelectedAtom, + objectFilterDropdownIsSelectingCompositeFieldAtom, + fieldMetadataItemIdUsedInDropdownAtom, + objectFilterDropdownCurrentRecordFilterAtom, + objectFilterDropdownAnyFieldSearchIsSelectedAtom, + ]); return { resetFilterDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter.ts index 8e07fa2d26..fae16e7e73 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter.ts @@ -1,28 +1,29 @@ +import { useCallback } from 'react'; + import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useUpsertObjectFilterDropdownCurrentFilter = () => { - const objectFilterDropdownCurrentRecordFilterCallbackState = - useRecoilComponentCallbackState( + const objectFilterDropdownCurrentRecordFilterAtom = + useRecoilComponentStateCallbackStateV2( objectFilterDropdownCurrentRecordFilterComponentState, ); const { upsertRecordFilter } = useUpsertRecordFilter(); - const upsertObjectFilterDropdownCurrentFilter = useRecoilCallback( - ({ set }) => - (recordFilterToUpsert: RecordFilter) => { - upsertRecordFilter(recordFilterToUpsert); + const upsertObjectFilterDropdownCurrentFilter = useCallback( + (recordFilterToUpsert: RecordFilter) => { + upsertRecordFilter(recordFilterToUpsert); - set( - objectFilterDropdownCurrentRecordFilterCallbackState, - recordFilterToUpsert, - ); - }, - [objectFilterDropdownCurrentRecordFilterCallbackState, upsertRecordFilter], + jotaiStore.set( + objectFilterDropdownCurrentRecordFilterAtom, + recordFilterToUpsert, + ); + }, + [objectFilterDropdownCurrentRecordFilterAtom, upsertRecordFilter], ); return { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState.ts index a750726365..685c3b3126 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const fieldMetadataItemIdUsedInDropdownComponentState = - createComponentState({ + createComponentStateV2({ key: 'fieldMetadataItemIdUsedInDropdownComponentState', defaultValue: null, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector.ts index 9d3f214103..2050099e29 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector.ts @@ -1,25 +1,22 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const fieldMetadataItemUsedInDropdownComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'fieldMetadataItemUsedInDropdownComponentSelector', + componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { const fieldMetadataItemIdUsedInDropdown = get( - fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ - instanceId, - }), + fieldMetadataItemIdUsedInDropdownComponentState, + componentStateKey, ); - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + const objectMetadataItems = get(objectMetadataItemsState); const correspondingFieldMetadataItem = objectMetadataItems .flatMap((objectMetadataItem) => objectMetadataItem.fields) @@ -30,5 +27,4 @@ export const fieldMetadataItemUsedInDropdownComponentSelector = return correspondingFieldMetadataItem; }, - componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownOperandSelectUnfoldedComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownOperandSelectUnfoldedComponentState.ts index 9fd17b10c1..574077dc6f 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownOperandSelectUnfoldedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownOperandSelectUnfoldedComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isObjectFilterDropdownOperandSelectUnfoldedComponentState = - createComponentState({ + createComponentStateV2({ key: 'isObjectFilterDropdownOperandSelectUnfoldedComponentState', defaultValue: false, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownUnfoldedComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownUnfoldedComponentState.ts index 2303169912..1db4eb618e 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownUnfoldedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/isObjectFilterDropdownUnfoldedComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isObjectFilterDropdownUnfoldedComponentState = - createComponentState({ + createComponentStateV2({ key: 'isObjectFilterDropdownUnfoldedComponentState', defaultValue: false, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState.ts index bc3c965449..b9eb3a55da 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectFilterDropdownAnyFieldSearchIsSelectedComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownAnyFieldSearchIsSelectedComponentState', defaultValue: false, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState.ts index d5e8fede37..9d213144ba 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState.ts @@ -1,9 +1,9 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; export const objectFilterDropdownCurrentRecordFilterComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownCurrentRecordFilterComponentState', defaultValue: undefined, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState.ts index 142c17e625..f7cdd9eaff 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectFilterDropdownFilterIsSelectedComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownFilterIsSelectedComponentState', defaultValue: false, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState.ts index 7dc4668545..146b87944a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectFilterDropdownIsSelectingCompositeFieldComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownIsSelectingCompositeFieldComponentState', defaultValue: false, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState.ts index 24565e244b..20cd234e38 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectFilterDropdownSearchInputComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownSearchInputComponentState', defaultValue: '', componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState.ts index 10c54a86c9..4018cdc34e 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectFilterDropdownSelectedOptionValuesComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownSelectedOptionValuesComponentState', defaultValue: [], componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState.ts index e850d5bd74..4a0715ba6b 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState.ts @@ -1,9 +1,9 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { type CompositeFilterableFieldType } from '@/object-record/record-filter/types/CompositeFilterableFieldType'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectFilterDropdownSubMenuFieldTypeComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectFilterDropdownSubMenuFieldTypeComponentState', defaultValue: null, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState.ts index aa3d5235d3..10514dafc3 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState.ts @@ -1,9 +1,9 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type ViewFilterOperand } from 'twenty-shared/types'; export const selectedOperandInDropdownComponentState = - createComponentState({ + createComponentStateV2({ key: 'selectedOperandInDropdownComponentState', defaultValue: null, componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState.ts index fb93d64dd9..db83c217ad 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState.ts @@ -1,8 +1,8 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const subFieldNameUsedInDropdownComponentState = createComponentState< +export const subFieldNameUsedInDropdownComponentState = createComponentStateV2< CompositeFieldSubFieldName | null | undefined >({ key: 'subFieldNameUsedInDropdownComponentState', diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx index 167117840b..86e5083579 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx @@ -10,9 +10,9 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isFieldMetadataDateKind } from 'twenty-shared/utils'; import { IconChevronLeft, IconSettings, useIcons } from 'twenty-ui/display'; import { MenuItem, MenuItemSelect } from 'twenty-ui/navigation'; @@ -29,7 +29,7 @@ export const ObjectOptionsDropdownCalendarFieldsContent = () => { const { updateCurrentView } = useUpdateCurrentView(); const { navigateToDateFieldSettings } = useGetAvailableFieldsForCalendar(); - const setRecordIndexCalendarFieldMetadataId = useSetRecoilState( + const setRecordIndexCalendarFieldMetadataId = useSetRecoilStateV2( recordIndexCalendarFieldMetadataIdState, ); const availableFieldsForCalendar = objectMetadataItem.fields.filter((field) => diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarViewContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarViewContent.tsx index bcb26ce773..67f3d88a9c 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarViewContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarViewContent.tsx @@ -9,9 +9,10 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { t } from '@lingui/core/macro'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; import { Pill } from 'twenty-ui/components'; import { IconCalendarMonth, @@ -24,10 +25,10 @@ import { ViewCalendarLayout } from '~/generated-metadata/graphql'; export const ObjectOptionsDropdownCalendarViewContent = () => { const { resetContent } = useObjectOptionsDropdown(); - const recordIndexCalendarLayout = useRecoilValue( + const recordIndexCalendarLayout = useRecoilValueV2( recordIndexCalendarLayoutState, ); - const setRecordIndexCalendarLayout = useSetRecoilState( + const setRecordIndexCalendarLayout = useSetRecoilStateV2( recordIndexCalendarLayoutState, ); const { updateCurrentView } = useUpdateCurrentView(); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCustomView.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCustomView.tsx index 63c5cb3b43..7afd1d4069 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCustomView.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCustomView.tsx @@ -11,16 +11,15 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { ViewKey } from '@/views/types/ViewKey'; import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType'; import { useDestroyViewFromCurrentState } from '@/views/view-picker/hooks/useDestroyViewFromCurrentState'; import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { AppTooltip, @@ -55,7 +54,7 @@ export const ObjectOptionsDropdownCustomView = ({ } : null; - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); @@ -67,7 +66,7 @@ export const ObjectOptionsDropdownCustomView = ({ const isDefaultView = currentView?.key === ViewKey.Index; - const recordIndexCalendarLayout = useRecoilValue( + const recordIndexCalendarLayout = useRecoilValueV2( recordIndexCalendarLayoutState, ); @@ -80,8 +79,9 @@ export const ObjectOptionsDropdownCustomView = ({ const visibleFieldsCount = visibleBoardFields.length; const { destroyViewFromCurrentState } = useDestroyViewFromCurrentState(); - const setViewPickerReferenceViewId = useSetRecoilComponentState( + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, + recordIndexId, ); const handleDelete = () => { diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownDefaultView.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownDefaultView.tsx index d2dd83cda2..314feb9a23 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownDefaultView.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownDefaultView.tsx @@ -8,7 +8,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { useOpenCreateViewDropdown } from '@/views/hooks/useOpenCreateViewDropown'; @@ -29,7 +29,7 @@ export const ObjectOptionsDropdownDefaultView = () => { const { currentView } = useGetCurrentViewOnly(); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, recordIndexId, ); 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 1905dcafd9..fbeb06ddc7 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 @@ -14,9 +14,10 @@ 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 { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; 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 { VIEW_GROUP_VISIBLE_OPTIONS_MAX } from 'twenty-shared/constants'; @@ -35,15 +36,15 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => { viewType, } = useObjectOptionsDropdown(); - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); - const hiddenRecordGroupIds = useRecoilComponentValue( + const hiddenRecordGroupIds = useRecoilComponentSelectorValueV2( hiddenRecordGroupIdsComponentSelector, ); - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, viewType, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx index a349b08eae..e97c572387 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx @@ -13,7 +13,6 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; @@ -22,9 +21,9 @@ import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType'; import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar'; import { useGetAvailableFieldsToGroupRecordsBy } from '@/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; import { useCallback } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { IconBaselineDensitySmall, @@ -61,11 +60,13 @@ export const ObjectOptionsDropdownLayoutContent = () => { [updateCurrentView], ); - const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); - const recordIndexCalendarLayout = useRecoilValue( + const recordIndexOpenRecordIn = useRecoilValueV2( + recordIndexOpenRecordInState, + ); + const recordIndexCalendarLayout = useRecoilValueV2( recordIndexCalendarLayoutState, ); - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx index 46c415a04b..fd4a455e25 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx @@ -12,10 +12,10 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { IconChevronLeft, IconLayoutNavbar, @@ -25,7 +25,9 @@ import { MenuItemSelect } from 'twenty-ui/navigation'; export const ObjectOptionsDropdownLayoutOpenInContent = () => { const { onContentChange } = useObjectOptionsDropdown(); - const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); + const recordIndexOpenRecordIn = useRecoilValueV2( + recordIndexOpenRecordInState, + ); const { currentView } = useGetCurrentViewOnly(); const { setAndPersistOpenRecordIn } = useUpdateObjectViewOptions(); const { objectMetadataItem } = useRecordIndexContextOrThrow(); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName.tsx index 3e08c6f04d..b49f92bcbb 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName.tsx @@ -3,9 +3,9 @@ import { IconPicker } from '@/ui/input/components/IconPicker'; import { TextInput } from '@/ui/input/components/TextInput'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { type View } from '@/views/types/View'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { useUpdateViewFromCurrentState } from '@/views/view-picker/hooks/useUpdateViewFromCurrentState'; @@ -60,12 +60,12 @@ export const ObjectOptionsDropdownMenuViewName = ({ currentView, }: ObjectOptionsDropdownMenuViewNameProps) => { const [viewPickerSelectedIcon, setViewPickerSelectedIcon] = - useRecoilComponentState(viewPickerSelectedIconComponentState); + useRecoilComponentStateV2(viewPickerSelectedIconComponentState); - const viewPickerIsPersisting = useRecoilComponentValue( + const viewPickerIsPersisting = useRecoilComponentValueV2( viewPickerIsPersistingComponentState, ); - const setViewPickerIsDirty = useSetRecoilComponentState( + const setViewPickerIsDirty = useSetRecoilComponentStateV2( viewPickerIsDirtyComponentState, ); 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 505e145659..c4b85d901e 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 @@ -15,7 +15,8 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; 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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { ViewType } from '@/views/types/ViewType'; import { useLingui } from '@lingui/react/macro'; @@ -47,11 +48,11 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => { objectNameSingular: objectMetadataItem.nameSingular, }); - const hiddenRecordGroupIds = useRecoilComponentValue( + const hiddenRecordGroupIds = useRecoilComponentSelectorValueV2( hiddenRecordGroupIdsComponentSelector, ); - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx index 507b1e5773..bca986d1d3 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx @@ -12,8 +12,8 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { @@ -27,11 +27,11 @@ import { MenuItemSelect } from 'twenty-ui/navigation'; export const ObjectOptionsDropdownRecordGroupSortContent = () => { const { currentContentId, onContentChange } = useObjectOptionsDropdown(); - const hiddenRecordGroupIds = useRecoilComponentValue( + const hiddenRecordGroupIds = useRecoilComponentSelectorValueV2( hiddenRecordGroupIdsComponentSelector, ); - const [recordGroupSort, setRecordGroupSort] = useRecoilComponentState( + const [recordGroupSort, setRecordGroupSort] = useRecoilComponentStateV2( recordIndexRecordGroupSortComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx index 2726910957..c566b56bd9 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx @@ -17,9 +17,9 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { useGetAvailableFieldsToGroupRecordsBy } from '@/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy'; import { useLingui } from '@lingui/react/macro'; @@ -48,27 +48,27 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => { const { currentView } = useGetCurrentViewOnly(); - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, viewType, ); - const hiddenRecordGroupIds = useRecoilComponentValue( + const hiddenRecordGroupIds = useRecoilComponentSelectorValueV2( hiddenRecordGroupIdsComponentSelector, ); - const hideEmptyRecordGroup = useRecoilComponentValue( + const hideEmptyRecordGroup = useRecoilComponentValueV2( recordIndexShouldHideEmptyRecordGroupsComponentState, ); const shouldHideEmptyGroups = hideEmptyRecordGroup ?? currentView?.shouldHideEmptyGroups ?? false; - const recordGroupSort = useRecoilComponentValue( + const recordGroupSort = useRecoilComponentValueV2( recordIndexRecordGroupSortComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard.ts index 025ac6397d..d6294d7e73 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard.ts @@ -1,6 +1,5 @@ import { type OnDragEndResponder } from '@hello-pangea/dnd'; import { useCallback, useMemo } from 'react'; -import { useRecoilState } from 'recoil'; import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -12,7 +11,8 @@ import { type RecordField } from '@/object-record/record-field/types/RecordField import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState'; import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields'; import { mapRecordFieldToViewField } from '@/views/utils/mapRecordFieldToViewField'; import { produce } from 'immer'; @@ -32,7 +32,7 @@ export const useObjectOptionsForBoard = ({ recordBoardId, }: useObjectOptionsForBoardParams) => { const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] = - useRecoilState(recordIndexFieldDefinitionsState); + useRecoilStateV2(recordIndexFieldDefinitionsState); const { saveViewFields } = useSaveCurrentViewFields(); @@ -130,7 +130,7 @@ export const useObjectOptionsForBoard = ({ ], ); - const currentRecordFields = useRecoilComponentValue( + const currentRecordFields = useRecoilComponentValueV2( currentRecordFieldsComponentState, recordBoardId, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useProcessOptionDropdownDragEnd.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useProcessOptionDropdownDragEnd.ts index 23e85e0ec7..d6bfe17ac0 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useProcessOptionDropdownDragEnd.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useProcessOptionDropdownDragEnd.ts @@ -4,7 +4,7 @@ import { useReorderVisibleRecordFields } from '@/object-record/record-field/hook import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields'; import { mapRecordFieldToViewField } from '@/views/utils/mapRecordFieldToViewField'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; export const useProcessOptionDropdownDragEnd = (recordTableId: string) => { const { reorderVisibleRecordFields } = @@ -12,8 +12,8 @@ export const useProcessOptionDropdownDragEnd = (recordTableId: string) => { const { saveViewFields } = useSaveCurrentViewFields(); - const processOptionDropdownDragEnd: OnDragEndResponder = useRecoilCallback( - () => async (result) => { + const processOptionDropdownDragEnd: OnDragEndResponder = useCallback( + async (result) => { if ( !result.destination || result.destination.index === 1 || diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSearchRecordGroupField.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSearchRecordGroupField.ts index 5dbc25ddcf..96e99a2ad2 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSearchRecordGroupField.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSearchRecordGroupField.ts @@ -1,6 +1,6 @@ import { objectOptionsDropdownSearchInputComponentState } from '@/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useMemo } from 'react'; import { FieldMetadataType } from '~/generated-metadata/graphql'; @@ -8,7 +8,7 @@ export const useSearchRecordGroupField = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); const [recordGroupFieldSearchInput, setRecordGroupFieldSearchInput] = - useRecoilComponentState(objectOptionsDropdownSearchInputComponentState); + useRecoilComponentStateV2(objectOptionsDropdownSearchInputComponentState); const filteredRecordGroupFieldMetadataItems = useMemo(() => { const searchInputLowerCase = diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts index cb02c3ac58..0d181a3840 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts @@ -13,13 +13,15 @@ import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; import { convertViewTypeToCore } from '@/views/utils/convertViewTypeToCore'; import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar'; import { useGetAvailableFieldsToGroupRecordsBy } from '@/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { assertUnreachable, isDefined } from 'twenty-shared/utils'; import { ViewCalendarLayout } from '~/generated-metadata/graphql'; export const useSetViewTypeFromLayoutOptionsMenu = () => { const { updateCurrentView } = useUpdateCurrentView(); - const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState); + const setRecordIndexViewType = useSetRecoilStateV2(recordIndexViewTypeState); const { availableFieldsForGrouping } = useGetAvailableFieldsToGroupRecordsBy(); const { objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -28,137 +30,137 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => { const { availableFieldsForCalendar } = useGetAvailableFieldsForCalendar(); - const setAndPersistViewType = useRecoilCallback( - ({ snapshot }) => - async (viewType: ViewType) => { - const currentViewId = snapshot - .getLoadable( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, - }), - ) - .getValue(); + const store = useStore(); - const existingCoreViews = jotaiStore.get(coreViewsState.atom); + const setAndPersistViewType = useCallback( + async (viewType: ViewType) => { + const currentViewId = store.get( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + ); - if (!isDefined(currentViewId)) { - throw new Error('No view id found'); + const existingCoreViews = jotaiStore.get(coreViewsState.atom); + + if (!isDefined(currentViewId)) { + throw new Error('No view id found'); + } + + const currentCoreView = existingCoreViews.find( + (coreView) => coreView.id === currentViewId, + ); + + if (!isDefined(currentCoreView)) { + throw new Error('No current view found'); + } + + const currentView = convertCoreViewToView(currentCoreView); + + const updateCurrentViewParams: Partial = {}; + updateCurrentViewParams.type = viewType; + + switch (viewType) { + case ViewType.Kanban: { + if (availableFieldsForGrouping.length === 0) { + throw new Error('No fields for kanban - should not happen'); + } + + const mainGroupByFieldMetadataId = availableFieldsForGrouping[0].id; + updateCurrentViewParams.mainGroupByFieldMetadataId = + mainGroupByFieldMetadataId; + + if (shouldChangeIcon(currentView.icon, currentView.type)) { + updateCurrentViewParams.icon = + viewTypeIconMapping(viewType).displayName; + } + + setRecordIndexViewType(viewType); + jotaiStore.set(coreViewsState.atom, [ + ...existingCoreViews.filter( + (coreView) => coreView.id !== currentView.id, + ), + { + ...currentCoreView, + type: convertViewTypeToCore(viewType), + mainGroupByFieldMetadataId, + }, + ]); + await updateCurrentView(updateCurrentViewParams); + return; } - - const currentCoreView = existingCoreViews.find( - (coreView) => coreView.id === currentViewId, - ); - - if (!isDefined(currentCoreView)) { - throw new Error('No current view found'); + case ViewType.Table: { + if (shouldChangeIcon(currentView.icon, currentView.type)) { + updateCurrentViewParams.icon = + viewTypeIconMapping(viewType).displayName; + } + updateCurrentViewParams.mainGroupByFieldMetadataId = null; + await updateCurrentView(updateCurrentViewParams); + setRecordIndexViewType(viewType); + jotaiStore.set(coreViewsState.atom, [ + ...existingCoreViews.filter( + (coreView) => coreView.id !== currentView.id, + ), + { + ...currentCoreView, + mainGroupByFieldMetadataId: null, + type: convertViewTypeToCore(viewType), + }, + ]); + return; } - - const currentView = convertCoreViewToView(currentCoreView); - - const updateCurrentViewParams: Partial = {}; - updateCurrentViewParams.type = viewType; - - switch (viewType) { - case ViewType.Kanban: { - if (availableFieldsForGrouping.length === 0) { - throw new Error('No fields for kanban - should not happen'); - } - - const mainGroupByFieldMetadataId = availableFieldsForGrouping[0].id; - updateCurrentViewParams.mainGroupByFieldMetadataId = - mainGroupByFieldMetadataId; - - if (shouldChangeIcon(currentView.icon, currentView.type)) { - updateCurrentViewParams.icon = - viewTypeIconMapping(viewType).displayName; - } - - setRecordIndexViewType(viewType); - jotaiStore.set(coreViewsState.atom, [ - ...existingCoreViews.filter( - (coreView) => coreView.id !== currentView.id, - ), - { - ...currentCoreView, - type: convertViewTypeToCore(viewType), - mainGroupByFieldMetadataId, - }, - ]); - await updateCurrentView(updateCurrentViewParams); - return; + case ViewType.Calendar: { + if (availableFieldsForCalendar.length === 0) { + throw new Error('No date fields for calendar'); } - case ViewType.Table: { - if (shouldChangeIcon(currentView.icon, currentView.type)) { - updateCurrentViewParams.icon = - viewTypeIconMapping(viewType).displayName; - } - updateCurrentViewParams.mainGroupByFieldMetadataId = null; - await updateCurrentView(updateCurrentViewParams); - setRecordIndexViewType(viewType); - jotaiStore.set(coreViewsState.atom, [ - ...existingCoreViews.filter( - (coreView) => coreView.id !== currentView.id, - ), - { - ...currentCoreView, - mainGroupByFieldMetadataId: null, - type: convertViewTypeToCore(viewType), - }, - ]); - return; - } - case ViewType.Calendar: { - if (availableFieldsForCalendar.length === 0) { - throw new Error('No date fields for calendar'); - } - const calendarFieldMetadataId = availableFieldsForCalendar[0].id; + const calendarFieldMetadataId = availableFieldsForCalendar[0].id; - setRecordIndexViewType(viewType); - jotaiStore.set(coreViewsState.atom, [ - ...existingCoreViews.filter( - (coreView) => coreView.id !== currentView.id, - ), - { - ...currentCoreView, - mainGroupByFieldMetadataId: null, - type: convertViewTypeToCore(viewType), - calendarLayout: ViewCalendarLayout.MONTH, - calendarFieldMetadataId, - }, - ]); + setRecordIndexViewType(viewType); + jotaiStore.set(coreViewsState.atom, [ + ...existingCoreViews.filter( + (coreView) => coreView.id !== currentView.id, + ), + { + ...currentCoreView, + mainGroupByFieldMetadataId: null, + type: convertViewTypeToCore(viewType), + calendarLayout: ViewCalendarLayout.MONTH, + calendarFieldMetadataId, + }, + ]); - loadRecordIndexStates( - { - ...currentView, - type: viewType, - calendarFieldMetadataId, - calendarLayout: ViewCalendarLayout.MONTH, - }, - objectMetadataItem, - ); + loadRecordIndexStates( + { + ...currentView, + type: viewType, + calendarFieldMetadataId, + calendarLayout: ViewCalendarLayout.MONTH, + }, + objectMetadataItem, + ); - if (shouldChangeIcon(currentView.icon, currentView.type)) { - updateCurrentViewParams.icon = - viewTypeIconMapping(viewType).displayName; - } - updateCurrentViewParams.calendarLayout = ViewCalendarLayout.MONTH; - updateCurrentViewParams.calendarFieldMetadataId = - calendarFieldMetadataId; - updateCurrentViewParams.mainGroupByFieldMetadataId = null; - return await updateCurrentView(updateCurrentViewParams); - } - case ViewType.FieldsWidget: { - return; - } - default: { - return assertUnreachable(viewType); + if (shouldChangeIcon(currentView.icon, currentView.type)) { + updateCurrentViewParams.icon = + viewTypeIconMapping(viewType).displayName; } + updateCurrentViewParams.calendarLayout = ViewCalendarLayout.MONTH; + updateCurrentViewParams.calendarFieldMetadataId = + calendarFieldMetadataId; + updateCurrentViewParams.mainGroupByFieldMetadataId = null; + return await updateCurrentView(updateCurrentViewParams); } - }, + case ViewType.FieldsWidget: { + return; + } + default: { + return assertUnreachable(viewType); + } + } + }, [ availableFieldsForGrouping, setRecordIndexViewType, + store, updateCurrentView, availableFieldsForCalendar, loadRecordIndexStates, diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions.ts index c22abcb218..0682da5987 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions.ts @@ -1,6 +1,7 @@ import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; import { recordIndexOpenRecordInStateV2 } from '@/object-record/record-index/states/recordIndexOpenRecordInStateV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useStore } from 'jotai'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { type GraphQLView } from '@/views/types/GraphQLView'; @@ -8,20 +9,19 @@ import { type ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState'; import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState'; import { useCallback } from 'react'; -import { useSetRecoilState } from 'recoil'; export const useUpdateObjectViewOptions = () => { const store = useStore(); - const setRecordIndexOpenRecordIn = useSetRecoilState( + const setRecordIndexOpenRecordIn = useSetRecoilStateV2( recordIndexOpenRecordInState, ); - const setRecordIndexViewName = useSetRecoilComponentState( + const setRecordIndexViewName = useSetRecoilComponentStateV2( viewPickerInputNameComponentState, ); - const setRecordIndexViewIcon = useSetRecoilComponentState( + const setRecordIndexViewIcon = useSetRecoilComponentStateV2( viewPickerSelectedIconComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState.ts index 3741c4b7a4..3ff53b1503 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const objectOptionsDropdownSearchInputComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectOptionsDropdownSearchInputComponentState', defaultValue: '', componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx index e4c6deda65..6a14f6a7f3 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx @@ -25,10 +25,9 @@ import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDrop import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { Trans, useLingui } from '@lingui/react/macro'; @@ -42,7 +41,7 @@ export const ObjectSortDropdownButton = () => { const { resetRecordSortDropdownSearchInput } = useResetRecordSortDropdownSearchInput(); - const setObjectSortDropdownSearchInput = useSetRecoilComponentState( + const setObjectSortDropdownSearchInput = useSetRecoilComponentStateV2( objectSortDropdownSearchInputComponentState, ); @@ -50,7 +49,7 @@ export const ObjectSortDropdownButton = () => { const { recordIndexId, objectMetadataItem } = useRecordIndexContextOrThrow(); - const objectSortDropdownSearchInput = useRecoilComponentValue( + const objectSortDropdownSearchInput = useRecoilComponentValueV2( objectSortDropdownSearchInputComponentState, ); @@ -63,7 +62,7 @@ export const ObjectSortDropdownButton = () => { const { getIcon } = useIcons(); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, recordIndexId, ); @@ -130,9 +129,9 @@ export const ObjectSortDropdownButton = () => { }; const [selectedRecordSortDirection, setSelectedRecordSortDirection] = - useRecoilComponentState(selectedRecordSortDirectionComponentState); + useRecoilComponentStateV2(selectedRecordSortDirectionComponentState); - const setIsRecordSortDirectionMenuUnfolded = useSetRecoilComponentState( + const setIsRecordSortDirectionMenuUnfolded = useSetRecoilComponentStateV2( isRecordSortDirectionDropdownMenuUnfoldedComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput.ts index d5dafae001..24b668c798 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput.ts @@ -1,20 +1,19 @@ import { objectSortDropdownSearchInputComponentState } from '@/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useResetRecordSortDropdownSearchInput = () => { const objectSortDropdownSearchInputCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( objectSortDropdownSearchInputComponentState, ); - const resetRecordSortDropdownSearchInput = useRecoilCallback( - ({ set }) => - () => { - set(objectSortDropdownSearchInputCallbackState, ''); - }, - [objectSortDropdownSearchInputCallbackState], - ); + const store = useStore(); + + const resetRecordSortDropdownSearchInput = useCallback(() => { + store.set(objectSortDropdownSearchInputCallbackState, ''); + }, [objectSortDropdownSearchInputCallbackState, store]); return { resetRecordSortDropdownSearchInput, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetSortDropdown.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetSortDropdown.ts index 0b4e99fe0a..9e1698f357 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetSortDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/hooks/useResetSortDropdown.ts @@ -1,15 +1,15 @@ import { isRecordSortDirectionDropdownMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState'; import { selectedRecordSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ViewSortDirection } from '~/generated-metadata/graphql'; export const useResetSortDropdown = () => { const setIsRecordSortDirectionDropdownMenuUnfolded = - useSetRecoilComponentState( + useSetRecoilComponentStateV2( isRecordSortDirectionDropdownMenuUnfoldedComponentState, ); - const setSelectedRecordSortDirection = useSetRecoilComponentState( + const setSelectedRecordSortDirection = useSetRecoilComponentStateV2( selectedRecordSortDirectionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState.ts index 84ea0cd096..66a458fbb8 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState.ts @@ -1,8 +1,8 @@ import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordSortDirectionDropdownMenuUnfoldedComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordSortDirectionDropdownMenuUnfoldedComponentState', defaultValue: false, componentInstanceContext: ObjectSortDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState.ts index dd3894c371..4badb45065 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState.ts @@ -1,8 +1,8 @@ import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const objectSortDropdownSearchInputComponentState = - createComponentState({ + createComponentStateV2({ key: 'objectSortDropdownSearchInputComponentState', defaultValue: '', componentInstanceContext: ObjectSortDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState.ts index 16ba281903..2964b95b71 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState.ts @@ -1,9 +1,9 @@ import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewSortDirection } from '~/generated-metadata/graphql'; export const selectedRecordSortDirectionComponentState = - createComponentState({ + createComponentStateV2({ key: 'selectedRecordSortDirectionComponentState', defaultValue: ViewSortDirection.ASC, componentInstanceContext: ObjectSortDropdownComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardBodyEscapeHotkeyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardBodyEscapeHotkeyEffect.tsx index 287c58c0f3..471862ea98 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardBodyEscapeHotkeyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardBodyEscapeHotkeyEffect.tsx @@ -8,7 +8,7 @@ import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/r import { useResetFocusStackToRecordIndex } from '@/object-record/record-index/hooks/useResetFocusStackToRecordIndex'; import { PageFocusId } from '@/types/PageFocusId'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; export const RecordBoardBodyEscapeHotkeyEffect = () => { const { recordBoardId } = useContext(RecordBoardContext); @@ -18,7 +18,7 @@ export const RecordBoardBodyEscapeHotkeyEffect = () => { const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId); const { resetFocusStackToRecordIndex } = useResetFocusStackToRecordIndex(); - const selectedRecordIds = useRecoilComponentValue( + const selectedRecordIds = useRecoilComponentSelectorValueV2( recordBoardSelectedRecordIdsComponentSelector, recordBoardId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardClickOutsideEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardClickOutsideEffect.tsx index 2b8d77ee13..71c8557acd 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardClickOutsideEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardClickOutsideEffect.tsx @@ -11,15 +11,16 @@ import { isDraggingRecordComponentState } from '@/object-record/record-drag/stat import { MODAL_BACKDROP_CLICK_OUTSIDE_ID } from '@/ui/layout/modal/constants/ModalBackdropClickOutsideId'; import { PAGE_ACTION_CONTAINER_CLICK_OUTSIDE_ID } from '@/ui/layout/page/constants/PageActionContainerClickOutsideId'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { LINK_CHIP_CLICK_OUTSIDE_ID } from 'twenty-ui/components'; export const RecordBoardClickOutsideEffect = () => { const { recordBoardId } = useContext(RecordBoardContext); - const isDraggingRecord = useRecoilComponentValue( + const isDraggingRecord = useRecoilComponentValueV2( isDraggingRecordComponentState, + recordBoardId, ); const { deactivateBoardCard } = useActiveRecordBoardCard(recordBoardId); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardColumns.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardColumns.tsx index 89b0f7ee31..3923085d3a 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardColumns.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardColumns.tsx @@ -1,6 +1,6 @@ import { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn'; import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; import { ViewType } from '@/views/types/ViewType'; import styled from '@emotion/styled'; @@ -13,7 +13,7 @@ const StyledColumnContainer = styled.div` `; export const RecordBoardColumns = () => { - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, ViewType.Kanban, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardContainer.tsx index dd34d706c7..eae76be24e 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardContainer.tsx @@ -14,7 +14,6 @@ import { RecordIndexRemoveSortingModal } from '@/object-record/record-index/comp import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-index/constants/RecordIndexRemoveSortingModalId'; import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; @@ -36,7 +35,7 @@ export const RecordBoardContainer = ({ objectMetadataItem.id, ); - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx index bc7f220335..a63f1ec890 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx @@ -1,3 +1,5 @@ +import { useStore } from 'jotai'; + import { useListenToObjectRecordOperationBrowserEvent } from '@/browser-event/hooks/useListenToObjectRecordOperationBrowserEvent'; import { useGetShouldInitializeRecordBoardForUpdateInputs } from '@/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs'; import { useRemoveRecordsFromBoard } from '@/object-record/record-board/hooks/useRemoveRecordsFromBoard'; @@ -8,12 +10,14 @@ import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecordOperationBrowserEventDetail } from '@/browser-event/types/ObjectRecordOperationBrowserEventDetail'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilySelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const RecordBoardDataChangedEffect = () => { + const store = useStore(); const { objectMetadataItem } = useRecordIndexContextOrThrow(); const { triggerRecordBoardInitialQuery } = useTriggerRecordBoardInitialQuery(); @@ -21,143 +25,139 @@ export const RecordBoardDataChangedEffect = () => { useGetShouldInitializeRecordBoardForUpdateInputs(); const recordGroupFromGroupValueCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilySelectorCallbackStateV2( recordGroupFromGroupValueComponentFamilySelector, ); - const recordIndexGroupFieldMetadataItemCallbackState = - useRecoilComponentCallbackState( + const recordIndexGroupFieldMetadataItemAtom = + useRecoilComponentStateCallbackStateV2( recordIndexGroupFieldMetadataItemComponentState, ); const recordIndexRecordIdsByGroupCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); const { removeRecordsFromBoard } = useRemoveRecordsFromBoard(); - const handleObjectRecordOperation = useRecoilCallback( - ({ snapshot }) => - ( - objectRecordOperationEventDetail: ObjectRecordOperationBrowserEventDetail, - ) => { - const objectRecordOperation = - objectRecordOperationEventDetail.operation; + const handleObjectRecordOperation = useCallback( + ( + objectRecordOperationEventDetail: ObjectRecordOperationBrowserEventDetail, + ) => { + const objectRecordOperation = objectRecordOperationEventDetail.operation; - switch (objectRecordOperation.type) { - case 'update-one': - case 'update-many': - { - const updateInputs = - objectRecordOperation.type === 'update-one' - ? [objectRecordOperation.result.updateInput] - : objectRecordOperation.result.updateInputs; + switch (objectRecordOperation.type) { + case 'update-one': + case 'update-many': + { + const updateInputs = + objectRecordOperation.type === 'update-one' + ? [objectRecordOperation.result.updateInput] + : objectRecordOperation.result.updateInputs; - const shouldInitializeForUpdateOperation = - getShouldInitializeRecordBoardForUpdateInputs(updateInputs); + const shouldInitializeForUpdateOperation = + getShouldInitializeRecordBoardForUpdateInputs(updateInputs); - if (shouldInitializeForUpdateOperation) { - triggerRecordBoardInitialQuery(); - } - } - break; - case 'create-one': { - if (objectRecordOperation.createdRecord.position === 'first') { + if (shouldInitializeForUpdateOperation) { triggerRecordBoardInitialQuery(); - } else { - const createdRecordPosition = - objectRecordOperation.createdRecord.position; - - if (!isDefined(createdRecordPosition)) { - return; - } - - const recordIndexGroupFieldMetadataItem = getSnapshotValue( - snapshot, - recordIndexGroupFieldMetadataItemCallbackState, - ); - - if (!isDefined(recordIndexGroupFieldMetadataItem)) { - return; - } - - const recordGroupValue = - objectRecordOperation.createdRecord[ - recordIndexGroupFieldMetadataItem.name - ]; - - const recordGroupDefinitionFromGroupValue = getSnapshotValue( - snapshot, - recordGroupFromGroupValueCallbackState({ recordGroupValue }), - ); - - if (!isDefined(recordGroupDefinitionFromGroupValue)) { - return; - } - - const recordIdsForGroup = getSnapshotValue( - snapshot, - recordIndexRecordIdsByGroupCallbackState( - recordGroupDefinitionFromGroupValue.id, - ), - ); - - const recordIdsWithoutCreatedRecord = recordIdsForGroup.filter( - (recordId) => - recordId !== objectRecordOperation.createdRecord.id, - ); - - const groupIsEmpty = recordIdsWithoutCreatedRecord.length === 0; - - if (groupIsEmpty) { - triggerRecordBoardInitialQuery(); - return; - } - - const firstRecordIdInGroup = recordIdsWithoutCreatedRecord[0]; - const firstExistingRecordInGroup = getSnapshotValue( - snapshot, - recordStoreFamilyState(firstRecordIdInGroup), - ); - - if (!isDefined(firstExistingRecordInGroup)) { - return; - } - - if (createdRecordPosition < firstExistingRecordInGroup.position) { - triggerRecordBoardInitialQuery(); - } } - break; } - case 'delete-one': { - const removedRecordId = objectRecordOperation.deletedRecordId; - - removeRecordsFromBoard({ - recordIdsToRemove: [removedRecordId], - }); - return; - } - case 'delete-many': { - const removedRecordIds = objectRecordOperation.deletedRecordIds; - - removeRecordsFromBoard({ - recordIdsToRemove: removedRecordIds, - }); - return; - } - case 'restore-many': - case 'restore-one': { - return; - } - default: { + break; + case 'create-one': { + if (objectRecordOperation.createdRecord.position === 'first') { triggerRecordBoardInitialQuery(); + } else { + const createdRecordPosition = + objectRecordOperation.createdRecord.position; + + if (!isDefined(createdRecordPosition)) { + return; + } + + const recordIndexGroupFieldMetadataItem = store.get( + recordIndexGroupFieldMetadataItemAtom, + ); + + if (!isDefined(recordIndexGroupFieldMetadataItem)) { + return; + } + + const recordGroupValue = + objectRecordOperation.createdRecord[ + recordIndexGroupFieldMetadataItem.name + ]; + + const recordGroupDefinitionFromGroupValue = store.get( + recordGroupFromGroupValueCallbackState({ recordGroupValue }), + ); + + if (!isDefined(recordGroupDefinitionFromGroupValue)) { + return; + } + + const recordIdsForGroup = store.get( + recordIndexRecordIdsByGroupCallbackState( + recordGroupDefinitionFromGroupValue.id, + ), + ); + + const recordIdsWithoutCreatedRecord = recordIdsForGroup.filter( + (recordId) => recordId !== objectRecordOperation.createdRecord.id, + ); + + const groupIsEmpty = recordIdsWithoutCreatedRecord.length === 0; + + if (groupIsEmpty) { + triggerRecordBoardInitialQuery(); + return; + } + + const firstRecordIdInGroup = recordIdsWithoutCreatedRecord[0]; + const firstExistingRecordInGroup = store.get( + recordStoreFamilyState.atomFamily(firstRecordIdInGroup), + ) as { position?: number } | null | undefined; + + if (!isDefined(firstExistingRecordInGroup)) { + return; + } + + if ( + createdRecordPosition < (firstExistingRecordInGroup.position ?? 0) + ) { + triggerRecordBoardInitialQuery(); + } } + break; } - }, + case 'delete-one': { + const removedRecordId = objectRecordOperation.deletedRecordId; + + removeRecordsFromBoard({ + recordIdsToRemove: [removedRecordId], + }); + return; + } + case 'delete-many': { + const removedRecordIds = objectRecordOperation.deletedRecordIds; + + removeRecordsFromBoard({ + recordIdsToRemove: removedRecordIds, + }); + return; + } + case 'restore-many': + case 'restore-one': { + return; + } + default: { + triggerRecordBoardInitialQuery(); + } + } + }, [ + store, triggerRecordBoardInitialQuery, getShouldInitializeRecordBoardForUpdateInputs, - recordIndexGroupFieldMetadataItemCallbackState, + recordIndexGroupFieldMetadataItemAtom, recordGroupFromGroupValueCallbackState, recordIndexRecordIdsByGroupCallbackState, removeRecordsFromBoard, diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDragDropContext.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDragDropContext.tsx index e38da043f9..a0f672e661 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDragDropContext.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDragDropContext.tsx @@ -8,84 +8,83 @@ import { originalDragSelectionComponentState } from '@/object-record/record-drag import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-index/constants/RecordIndexRemoveSortingModalId'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; import { DragDropContext, type DragStart, type OnDragEndResponder, } from '@hello-pangea/dnd'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useContext } from 'react'; export const RecordBoardDragDropContext = ({ children, }: React.PropsWithChildren) => { const { recordBoardId } = useContext(RecordBoardContext); - const currentRecordSortCallbackState = useRecoilComponentCallbackState( + const currentRecordSortsAtom = useRecoilComponentStateCallbackStateV2( currentRecordSortsComponentState, - ); - - const recordBoardSelectedRecordIdsSelector = useRecoilComponentCallbackState( - recordBoardSelectedRecordIdsComponentSelector, recordBoardId, ); - const originalDragSelectionCallbackState = useRecoilComponentCallbackState( + const recordBoardSelectedRecordIdsAtom = + useRecoilComponentSelectorCallbackStateV2( + recordBoardSelectedRecordIdsComponentSelector, + recordBoardId, + ); + + const store = useStore(); + + const originalDragSelectionAtom = useRecoilComponentStateCallbackStateV2( originalDragSelectionComponentState, + recordBoardId, ); - const { startRecordDrag } = useStartRecordDrag(); - const { endRecordDrag } = useEndRecordDrag(); + const { startRecordDrag } = useStartRecordDrag(recordBoardId); + const { endRecordDrag } = useEndRecordDrag(recordBoardId); const { processBoardCardDrop } = useProcessBoardCardDrop(); const { openModal } = useModal(); - const handleDragStart = useRecoilCallback( - ({ snapshot }) => - (start: DragStart) => { - const currentSelectedRecordIds = getSnapshotValue( - snapshot, - recordBoardSelectedRecordIdsSelector, - ); + const handleDragStart = useCallback( + (start: DragStart) => { + const currentSelectedRecordIds = store.get( + recordBoardSelectedRecordIdsAtom, + ); - startRecordDrag(start, currentSelectedRecordIds); - }, - [recordBoardSelectedRecordIdsSelector, startRecordDrag], + startRecordDrag(start, currentSelectedRecordIds); + }, + [recordBoardSelectedRecordIdsAtom, startRecordDrag, store], ); - const handleDragEnd: OnDragEndResponder = useRecoilCallback( - ({ snapshot }) => - (result) => { - endRecordDrag(); + const handleDragEnd: OnDragEndResponder = useCallback( + (result) => { + endRecordDrag(); - if (!result.destination) return; + if (!result.destination) return; - const currentRecordSorts = getSnapshotValue( - snapshot, - currentRecordSortCallbackState, - ); + const currentRecordSorts = store.get(currentRecordSortsAtom); - if (currentRecordSorts.length > 0) { - openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID); - return; - } + if (currentRecordSorts.length > 0) { + openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID); + return; + } - const originalSelection = getSnapshotValue( - snapshot, - originalDragSelectionCallbackState, - ); + const originalSelection = store.get( + originalDragSelectionAtom, + ) as string[]; - processBoardCardDrop(result, originalSelection); - }, + processBoardCardDrop(result, originalSelection); + }, [ processBoardCardDrop, - originalDragSelectionCallbackState, + originalDragSelectionAtom, endRecordDrag, - currentRecordSortCallbackState, + currentRecordSortsAtom, openModal, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardFetchMoreInViewTriggerComponent.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardFetchMoreInViewTriggerComponent.tsx index 1554ec00be..433d28cf9f 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardFetchMoreInViewTriggerComponent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardFetchMoreInViewTriggerComponent.tsx @@ -10,9 +10,9 @@ import { recordBoardShouldFetchMoreComponentState } from '@/object-record/record import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector'; import { recordIndexRecordGroupsAreInInitialLoadingComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; const StyledFetchMoreTriggerDiv = styled.div<{ width: number }>` @@ -21,15 +21,15 @@ const StyledFetchMoreTriggerDiv = styled.div<{ width: number }>` `; export const RecordBoardFetchMoreInViewTriggerComponent = () => { - const [shouldFetchMore, setShouldFetchMore] = useRecoilComponentState( + const [shouldFetchMore, setShouldFetchMore] = useRecoilComponentStateV2( recordBoardShouldFetchMoreComponentState, ); - const isInitialLoading = useRecoilComponentValue( + const isInitialLoading = useRecoilComponentValueV2( recordIndexRecordGroupsAreInInitialLoadingComponentState, ); - const isFetchingMore = useRecoilComponentValue( + const isFetchingMore = useRecoilComponentValueV2( recordBoardIsFetchingMoreComponentState, ); @@ -40,7 +40,7 @@ export const RecordBoardFetchMoreInViewTriggerComponent = () => { root: scrollWrapperHTMLElement, }); - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, ViewType.Kanban, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx index 821c0fb075..51f9d96ffe 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx @@ -2,7 +2,7 @@ import { RecordBoardColumnHeaderWrapper } from '@/object-record/record-board/rec import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext'; import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector'; import { RecordIndexGroupAggregatesDataLoader } from '@/object-record/record-index/components/RecordIndexGroupAggregatesDataLoader'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; import { ViewType } from '@/views/types/ViewType'; import styled from '@emotion/styled'; @@ -26,7 +26,7 @@ const StyledHeaderContainer = styled.div` `; export const RecordBoardHeader = () => { - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, ViewType.Kanban, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx index fb5ac2c501..c081a71ff6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx @@ -12,9 +12,9 @@ import { useRecordIndexGroupCommonQueryVariables } from '@/object-record/record- import { recordIndexRecordGroupsAreInInitialLoadingComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState'; import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -23,17 +23,17 @@ export const RecordBoardQueryEffect = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); const [lastRecordBoardQueryIdentifier, setLastRecordBoardQueryIdentifier] = - useRecoilComponentState(lastRecordBoardQueryIdentifierComponentState); + useRecoilComponentStateV2(lastRecordBoardQueryIdentifierComponentState); - const [lastRecordGroupIds, setLastRecordGroupIds] = useRecoilComponentState( + const [lastRecordGroupIds, setLastRecordGroupIds] = useRecoilComponentStateV2( lastRecordGroupIdsComponentState, ); - const [recordIndexRecordGroupsAreInInitialLoading] = useRecoilComponentState( + const recordIndexRecordGroupsAreInInitialLoading = useRecoilComponentValueV2( recordIndexRecordGroupsAreInInitialLoadingComponentState, ); - const setRecordBoardCurrentGroupByQueryOffset = useSetRecoilComponentState( + const setRecordBoardCurrentGroupByQueryOffset = useSetRecoilComponentStateV2( recordBoardCurrentGroupByQueryOffsetComponentState, ); @@ -51,11 +51,11 @@ export const RecordBoardQueryEffect = () => { const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement(); - const [shouldFetchMore] = useRecoilComponentState( + const [shouldFetchMore] = useRecoilComponentStateV2( recordBoardShouldFetchMoreComponentState, ); - const recordBoardIsFetchingMore = useRecoilComponentValue( + const recordBoardIsFetchingMore = useRecoilComponentValueV2( recordBoardIsFetchingMoreComponentState, ); @@ -64,7 +64,9 @@ export const RecordBoardQueryEffect = () => { const { triggerRecordBoardInitialQuery } = useTriggerRecordBoardInitialQuery(); - const recordGroupdIds = useRecoilComponentValue(recordGroupIdsComponentState); + const recordGroupdIds = useRecoilComponentValueV2( + recordGroupIdsComponentState, + ); const recordGroupIdsHaveChanged = !isDeeplyEqual( [...recordGroupdIds].sort(), [...lastRecordGroupIds].sort(), diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardScrollToFocusedCardEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardScrollToFocusedCardEffect.tsx index d0e0e6b3f4..46ab01fdd1 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardScrollToFocusedCardEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardScrollToFocusedCardEffect.tsx @@ -1,16 +1,21 @@ -import { useEffect } from 'react'; +import { useContext, useEffect } from 'react'; +import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { focusedRecordBoardCardIndexesComponentState } from '@/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState'; import { isRecordBoardCardFocusActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const RecordBoardScrollToFocusedCardEffect = () => { - const focusedCardIndexes = useRecoilComponentValue( + const { recordBoardId } = useContext(RecordBoardContext); + + const focusedCardIndexes = useRecoilComponentValueV2( focusedRecordBoardCardIndexesComponentState, + recordBoardId, ); - const isFocusActive = useRecoilComponentValue( + const isFocusActive = useRecoilComponentValueV2( isRecordBoardCardFocusActiveComponentState, + recordBoardId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardSelectRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardSelectRecordsEffect.tsx index f511d4564b..3c234a6002 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardSelectRecordsEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardSelectRecordsEffect.tsx @@ -2,16 +2,20 @@ import { useEffect } from 'react'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const RecordBoardSelectRecordsEffect = () => { - const selectedRecordIds = useRecoilComponentValue( + const { recordIndexId } = useRecordIndexContextOrThrow(); + + const selectedRecordIds = useRecoilComponentSelectorValueV2( recordBoardSelectedRecordIdsComponentSelector, ); - const setContextStoreTargetedRecords = useSetRecoilComponentState( + const setContextStoreTargetedRecords = useSetRecoilComponentStateV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useActiveRecordBoardCard.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useActiveRecordBoardCard.ts index e20bc5e44d..3ae0789b9f 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useActiveRecordBoardCard.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useActiveRecordBoardCard.ts @@ -1,60 +1,62 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { activeRecordBoardCardIndexesComponentState } from '@/object-record/record-board/states/activeRecordBoardCardIndexesComponentState'; import { isRecordBoardCardActiveComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardActiveComponentFamilyState'; import { type BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useActiveRecordBoardCard = (recordBoardId?: string) => { - const isCardActiveState = useRecoilComponentCallbackState( + const isCardActiveState = useRecoilComponentFamilyStateCallbackStateV2( isRecordBoardCardActiveComponentFamilyState, recordBoardId, ); - const activeBoardCardIndexesState = useRecoilComponentCallbackState( + const activeBoardCardIndexesState = useRecoilComponentStateCallbackStateV2( activeRecordBoardCardIndexesComponentState, recordBoardId, ); - const deactivateBoardCard = useRecoilCallback( - ({ set, snapshot }) => - () => { - const activeBoardCardIndexes = snapshot - .getLoadable(activeBoardCardIndexesState) - .getValue(); + const store = useStore(); - if (!isDefined(activeBoardCardIndexes)) { - return; - } + const deactivateBoardCard = useCallback(() => { + const activeBoardCardIndexes = store.get(activeBoardCardIndexesState) as + | BoardCardIndexes + | null + | undefined; - set(activeBoardCardIndexesState, null); - set(isCardActiveState(activeBoardCardIndexes), false); - }, - [activeBoardCardIndexesState, isCardActiveState], - ); + if (!isDefined(activeBoardCardIndexes)) { + return; + } - const activateBoardCard = useRecoilCallback( - ({ set, snapshot }) => - (boardCardIndexes: BoardCardIndexes) => { - const activeBoardCardIndexes = snapshot - .getLoadable(activeBoardCardIndexesState) - .getValue(); + store.set(activeBoardCardIndexesState, null); + store.set(isCardActiveState(activeBoardCardIndexes), false); + }, [activeBoardCardIndexesState, isCardActiveState, store]); - if ( - activeBoardCardIndexes?.rowIndex === boardCardIndexes.rowIndex && - activeBoardCardIndexes?.columnIndex === boardCardIndexes.columnIndex - ) { - return; - } + const activateBoardCard = useCallback( + (boardCardIndexes: BoardCardIndexes) => { + const activeBoardCardIndexes = store.get(activeBoardCardIndexesState) as + | BoardCardIndexes + | null + | undefined; - if (isDefined(activeBoardCardIndexes)) { - set(isCardActiveState(activeBoardCardIndexes), false); - } + if ( + activeBoardCardIndexes?.rowIndex === boardCardIndexes.rowIndex && + activeBoardCardIndexes?.columnIndex === boardCardIndexes.columnIndex + ) { + return; + } - set(activeBoardCardIndexesState, boardCardIndexes); - set(isCardActiveState(boardCardIndexes), true); - }, - [activeBoardCardIndexesState, isCardActiveState], + if (isDefined(activeBoardCardIndexes)) { + store.set(isCardActiveState(activeBoardCardIndexes), false); + } + + store.set(activeBoardCardIndexesState, boardCardIndexes); + store.set(isCardActiveState(boardCardIndexes), true); + }, + [activeBoardCardIndexesState, isCardActiveState, store], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useFocusedRecordBoardCard.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useFocusedRecordBoardCard.ts index c96a0b6aca..33609eb683 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useFocusedRecordBoardCard.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useFocusedRecordBoardCard.ts @@ -6,22 +6,25 @@ import { type BoardCardIndexes } from '@/object-record/record-board/types/BoardC import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useFocusedRecordBoardCard = (recordBoardId?: string) => { - const isCardFocusedState = useRecoilComponentCallbackState( + const store = useStore(); + const isCardFocusedAtom = useRecoilComponentFamilyStateCallbackStateV2( isRecordBoardCardFocusedComponentFamilyState, recordBoardId, ); - const focusedBoardCardIndexesState = useRecoilComponentCallbackState( + const focusedBoardCardIndexesAtom = useRecoilComponentStateCallbackStateV2( focusedRecordBoardCardIndexesComponentState, recordBoardId, ); - const isCardFocusActiveState = useRecoilComponentCallbackState( + const isCardFocusActiveAtom = useRecoilComponentStateCallbackStateV2( isRecordBoardCardFocusActiveComponentState, recordBoardId, ); @@ -30,85 +33,83 @@ export const useFocusedRecordBoardCard = (recordBoardId?: string) => { const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const unfocusBoardCard = useRecoilCallback( - ({ set, snapshot }) => - () => { - const focusedBoardCardIndexes = snapshot - .getLoadable(focusedBoardCardIndexesState) - .getValue(); + const unfocusBoardCard = useCallback(() => { + const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as + | BoardCardIndexes + | null + | undefined; - if (!isDefined(focusedBoardCardIndexes)) { - return; - } + if (!isDefined(focusedBoardCardIndexes)) { + return; + } - const focusId = getRecordBoardCardFocusId({ + const focusId = getRecordBoardCardFocusId({ + recordBoardId: recordBoardId || '', + cardIndexes: focusedBoardCardIndexes, + }); + + removeFocusItemFromFocusStackById({ + focusId, + }); + + store.set(focusedBoardCardIndexesAtom, null); + store.set(isCardFocusedAtom(focusedBoardCardIndexes), false); + store.set(isCardFocusActiveAtom, false); + }, [ + store, + focusedBoardCardIndexesAtom, + isCardFocusedAtom, + isCardFocusActiveAtom, + recordBoardId, + removeFocusItemFromFocusStackById, + ]); + + const focusBoardCard = useCallback( + (boardCardIndexes: BoardCardIndexes) => { + const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as + | BoardCardIndexes + | null + | undefined; + + if ( + isDefined(focusedBoardCardIndexes) && + (focusedBoardCardIndexes.rowIndex !== boardCardIndexes.rowIndex || + focusedBoardCardIndexes.columnIndex !== boardCardIndexes.columnIndex) + ) { + store.set(isCardFocusedAtom(focusedBoardCardIndexes), false); + + const currentFocusId = getRecordBoardCardFocusId({ recordBoardId: recordBoardId || '', cardIndexes: focusedBoardCardIndexes, }); removeFocusItemFromFocusStackById({ - focusId, + focusId: currentFocusId, }); + } - set(focusedBoardCardIndexesState, null); - set(isCardFocusedState(focusedBoardCardIndexes), false); - set(isCardFocusActiveState, false); - }, + const focusId = getRecordBoardCardFocusId({ + recordBoardId: recordBoardId || '', + cardIndexes: boardCardIndexes, + }); + + pushFocusItemToFocusStack({ + focusId, + component: { + type: FocusComponentType.RECORD_BOARD_CARD, + instanceId: focusId, + }, + }); + + store.set(focusedBoardCardIndexesAtom, boardCardIndexes); + store.set(isCardFocusedAtom(boardCardIndexes), true); + store.set(isCardFocusActiveAtom, true); + }, [ - focusedBoardCardIndexesState, - isCardFocusedState, - isCardFocusActiveState, - recordBoardId, - removeFocusItemFromFocusStackById, - ], - ); - - const focusBoardCard = useRecoilCallback( - ({ set, snapshot }) => - (boardCardIndexes: BoardCardIndexes) => { - const focusedBoardCardIndexes = snapshot - .getLoadable(focusedBoardCardIndexesState) - .getValue(); - - if ( - isDefined(focusedBoardCardIndexes) && - (focusedBoardCardIndexes.rowIndex !== boardCardIndexes.rowIndex || - focusedBoardCardIndexes.columnIndex !== - boardCardIndexes.columnIndex) - ) { - set(isCardFocusedState(focusedBoardCardIndexes), false); - - const currentFocusId = getRecordBoardCardFocusId({ - recordBoardId: recordBoardId || '', - cardIndexes: focusedBoardCardIndexes, - }); - - removeFocusItemFromFocusStackById({ - focusId: currentFocusId, - }); - } - - const focusId = getRecordBoardCardFocusId({ - recordBoardId: recordBoardId || '', - cardIndexes: boardCardIndexes, - }); - - pushFocusItemToFocusStack({ - focusId, - component: { - type: FocusComponentType.RECORD_BOARD_CARD, - instanceId: focusId, - }, - }); - - set(focusedBoardCardIndexesState, boardCardIndexes); - set(isCardFocusedState(boardCardIndexes), true); - set(isCardFocusActiveState, true); - }, - [ - focusedBoardCardIndexesState, - isCardFocusedState, - isCardFocusActiveState, + store, + focusedBoardCardIndexesAtom, + isCardFocusedAtom, + isCardFocusActiveAtom, recordBoardId, pushFocusItemToFocusStack, removeFocusItemFromFocusStackById, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts index 90c790193e..3c92363f45 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts @@ -4,7 +4,7 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/conte import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { type ObjectRecordOperationUpdateInput } from '@/object-record/types/ObjectRecordOperationUpdateInput'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined, mapById } from 'twenty-shared/utils'; @@ -15,15 +15,15 @@ export const useGetShouldInitializeRecordBoardForUpdateInputs = () => { objectMetadataItem, }); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardHotkeys.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardHotkeys.ts index e0abe4dc31..63cf95286d 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardHotkeys.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardHotkeys.ts @@ -9,8 +9,8 @@ import { RecordBoardCardContext } from '@/object-record/record-board/record-boar import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useContext } from 'react'; import { Key } from 'ts-key-enum'; @@ -27,12 +27,12 @@ export const useRecordBoardCardHotkeys = (focusId: string) => { const { resetRecordBoardSelection } = useResetRecordBoardSelection(); const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId); - const isRecordBoardCardSelected = useRecoilComponentFamilyValue( + const isRecordBoardCardSelected = useRecoilComponentFamilyValueV2( isRecordBoardCardSelectedComponentFamilyState, recordId, ); - const selectedRecordIds = useRecoilComponentValue( + const selectedRecordIds = useRecoilComponentSelectorValueV2( recordBoardSelectedRecordIdsComponentSelector, recordBoardId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardNavigation.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardNavigation.ts index 2ed606e207..527b64112f 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardNavigation.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardCardNavigation.ts @@ -1,141 +1,139 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard'; import { focusedRecordBoardCardIndexesComponentState } from '@/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState'; import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; import { ViewType } from '@/views/types/ViewType'; import { isDefined } from 'twenty-shared/utils'; type NavigationDirection = 'up' | 'down' | 'left' | 'right'; export const useRecordBoardCardNavigation = (recordBoardId?: string) => { + const store = useStore(); const { focusBoardCard } = useFocusedRecordBoardCard(recordBoardId); - const focusedBoardCardIndexesState = useRecoilComponentCallbackState( + const focusedBoardCardIndexesAtom = useRecoilComponentStateCallbackStateV2( focusedRecordBoardCardIndexesComponentState, recordBoardId, ); - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, ViewType.Kanban, ); - const recordIdsByGroupState = useRecoilComponentCallbackState( + const recordIdsByGroupState = useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); - const focusFirstAvailableRecord = useRecoilCallback( - ({ snapshot }) => - () => { - if (visibleRecordGroupIds.length === 0) { - return; - } + const focusFirstAvailableRecord = useCallback(() => { + if (visibleRecordGroupIds.length === 0) { + return; + } - const firstColumnWithRecords = visibleRecordGroupIds.findIndex( - (groupId) => { - const recordIdsInGroup = snapshot - .getLoadable(recordIdsByGroupState(groupId)) - .getValue(); - return ( - Array.isArray(recordIdsInGroup) && recordIdsInGroup.length > 0 - ); - }, - ); - - if (firstColumnWithRecords !== -1) { - focusBoardCard({ - columnIndex: firstColumnWithRecords, - rowIndex: 0, - }); - } + const firstColumnWithRecords = visibleRecordGroupIds.findIndex( + (groupId) => { + const recordIdsInGroup = store.get( + recordIdsByGroupState(groupId), + ) as string[]; + return Array.isArray(recordIdsInGroup) && recordIdsInGroup.length > 0; }, - [visibleRecordGroupIds, recordIdsByGroupState, focusBoardCard], - ); + ); - const moveHorizontally = useRecoilCallback( - ({ snapshot }) => - (direction: 'left' | 'right') => { - const focusedBoardCardIndexes = snapshot - .getLoadable(focusedBoardCardIndexesState) - .getValue(); + if (firstColumnWithRecords !== -1) { + focusBoardCard({ + columnIndex: firstColumnWithRecords, + rowIndex: 0, + }); + } + }, [store, visibleRecordGroupIds, recordIdsByGroupState, focusBoardCard]); - if (!isDefined(focusedBoardCardIndexes)) { - focusFirstAvailableRecord(); - return; - } + const moveHorizontally = useCallback( + (direction: 'left' | 'right') => { + const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as + | { rowIndex: number; columnIndex: number } + | null + | undefined; - if (visibleRecordGroupIds.length === 0) { - return; - } + if (!isDefined(focusedBoardCardIndexes)) { + focusFirstAvailableRecord(); + return; + } - let newColumnIndex = - direction === 'right' - ? focusedBoardCardIndexes.columnIndex + 1 - : focusedBoardCardIndexes.columnIndex - 1; + if (visibleRecordGroupIds.length === 0) { + return; + } - if (newColumnIndex < 0) { - newColumnIndex = 0; - } else if (newColumnIndex >= visibleRecordGroupIds.length) { - newColumnIndex = visibleRecordGroupIds.length - 1; - } + let newColumnIndex = + direction === 'right' + ? focusedBoardCardIndexes.columnIndex + 1 + : focusedBoardCardIndexes.columnIndex - 1; - if (newColumnIndex === focusedBoardCardIndexes.columnIndex) { - return; - } + if (newColumnIndex < 0) { + newColumnIndex = 0; + } else if (newColumnIndex >= visibleRecordGroupIds.length) { + newColumnIndex = visibleRecordGroupIds.length - 1; + } - let foundColumnWithRecords = false; - const initialColumnIndex = newColumnIndex; + if (newColumnIndex === focusedBoardCardIndexes.columnIndex) { + return; + } - while (!foundColumnWithRecords) { - const currentGroupId = visibleRecordGroupIds[newColumnIndex]; - const recordIdsInGroup = snapshot - .getLoadable(recordIdsByGroupState(currentGroupId)) - .getValue(); + let foundColumnWithRecords = false; + const initialColumnIndex = newColumnIndex; - if (Array.isArray(recordIdsInGroup) && recordIdsInGroup.length > 0) { - foundColumnWithRecords = true; - } else { - newColumnIndex = - direction === 'right' ? newColumnIndex + 1 : newColumnIndex - 1; + while (!foundColumnWithRecords) { + const currentGroupId = visibleRecordGroupIds[newColumnIndex]; + const recordIdsInGroup = store.get( + recordIdsByGroupState(currentGroupId), + ) as string[]; - if ( - newColumnIndex < 0 || - newColumnIndex >= visibleRecordGroupIds.length - ) { - focusFirstAvailableRecord(); - return; - } + if (Array.isArray(recordIdsInGroup) && recordIdsInGroup.length > 0) { + foundColumnWithRecords = true; + } else { + newColumnIndex = + direction === 'right' ? newColumnIndex + 1 : newColumnIndex - 1; - if ( - (direction === 'right' && newColumnIndex <= initialColumnIndex) || - (direction === 'left' && newColumnIndex >= initialColumnIndex) - ) { - return; - } + if ( + newColumnIndex < 0 || + newColumnIndex >= visibleRecordGroupIds.length + ) { + focusFirstAvailableRecord(); + return; + } + + if ( + (direction === 'right' && newColumnIndex <= initialColumnIndex) || + (direction === 'left' && newColumnIndex >= initialColumnIndex) + ) { + return; } } + } - const currentGroupId = visibleRecordGroupIds[newColumnIndex]; - const recordIdsInGroup = snapshot - .getLoadable(recordIdsByGroupState(currentGroupId)) - .getValue(); + const currentGroupId = visibleRecordGroupIds[newColumnIndex]; + const recordIdsInGroup = store.get( + recordIdsByGroupState(currentGroupId), + ) as string[]; - let newRowIndex = focusedBoardCardIndexes.rowIndex; - if (newRowIndex >= recordIdsInGroup.length) { - newRowIndex = recordIdsInGroup.length - 1; - } + let newRowIndex = focusedBoardCardIndexes.rowIndex; + if (newRowIndex >= recordIdsInGroup.length) { + newRowIndex = recordIdsInGroup.length - 1; + } - focusBoardCard({ - columnIndex: newColumnIndex, - rowIndex: newRowIndex, - }); - }, + focusBoardCard({ + columnIndex: newColumnIndex, + rowIndex: newRowIndex, + }); + }, [ - focusedBoardCardIndexesState, + store, + focusedBoardCardIndexesAtom, visibleRecordGroupIds, recordIdsByGroupState, focusBoardCard, @@ -143,53 +141,54 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => { ], ); - const moveVertically = useRecoilCallback( - ({ snapshot }) => - (direction: 'up' | 'down') => { - const focusedBoardCardIndexes = snapshot - .getLoadable(focusedBoardCardIndexesState) - .getValue(); + const moveVertically = useCallback( + (direction: 'up' | 'down') => { + const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as + | { rowIndex: number; columnIndex: number } + | null + | undefined; - if (!isDefined(focusedBoardCardIndexes)) { - focusFirstAvailableRecord(); - return; - } + if (!isDefined(focusedBoardCardIndexes)) { + focusFirstAvailableRecord(); + return; + } - if (visibleRecordGroupIds.length === 0) return; + if (visibleRecordGroupIds.length === 0) return; - const currentGroupId = - visibleRecordGroupIds[focusedBoardCardIndexes.columnIndex]; - const recordIdsInGroup = snapshot - .getLoadable(recordIdsByGroupState(currentGroupId)) - .getValue(); + const currentGroupId = + visibleRecordGroupIds[focusedBoardCardIndexes.columnIndex]; + const recordIdsInGroup = store.get( + recordIdsByGroupState(currentGroupId), + ) as string[]; - if (!Array.isArray(recordIdsInGroup) || recordIdsInGroup.length === 0) { - focusFirstAvailableRecord(); - return; - } + if (!Array.isArray(recordIdsInGroup) || recordIdsInGroup.length === 0) { + focusFirstAvailableRecord(); + return; + } - let newRowIndex = - direction === 'down' - ? focusedBoardCardIndexes.rowIndex + 1 - : focusedBoardCardIndexes.rowIndex - 1; + let newRowIndex = + direction === 'down' + ? focusedBoardCardIndexes.rowIndex + 1 + : focusedBoardCardIndexes.rowIndex - 1; - if (newRowIndex < 0) { - newRowIndex = 0; - } else if (newRowIndex >= recordIdsInGroup.length) { - newRowIndex = recordIdsInGroup.length - 1; - } + if (newRowIndex < 0) { + newRowIndex = 0; + } else if (newRowIndex >= recordIdsInGroup.length) { + newRowIndex = recordIdsInGroup.length - 1; + } - if (newRowIndex === focusedBoardCardIndexes.rowIndex) { - return; - } + if (newRowIndex === focusedBoardCardIndexes.rowIndex) { + return; + } - focusBoardCard({ - columnIndex: focusedBoardCardIndexes.columnIndex, - rowIndex: newRowIndex, - }); - }, + focusBoardCard({ + columnIndex: focusedBoardCardIndexes.columnIndex, + rowIndex: newRowIndex, + }); + }, [ - focusedBoardCardIndexesState, + store, + focusedBoardCardIndexesAtom, visibleRecordGroupIds, recordIdsByGroupState, focusBoardCard, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts index 0cd8adb552..6e0cf62513 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts @@ -1,5 +1,3 @@ -import { useRecoilCallback } from 'recoil'; - import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; @@ -7,8 +5,10 @@ import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/r import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useRecordBoardSelection = (recordBoardId?: string) => { const instanceIdFromProps = useAvailableComponentInstanceIdOrThrow( @@ -16,51 +16,46 @@ export const useRecordBoardSelection = (recordBoardId?: string) => { recordBoardId, ); - const isRecordBoardCardSelectedFamilyState = useRecoilComponentCallbackState( - isRecordBoardCardSelectedComponentFamilyState, - recordBoardId, - ); + const isRecordBoardCardSelectedFamilyState = + useRecoilComponentFamilyStateCallbackStateV2( + isRecordBoardCardSelectedComponentFamilyState, + recordBoardId, + ); - const recordBoardSelectedRecordIdsSelector = useRecoilComponentCallbackState( - recordBoardSelectedRecordIdsComponentSelector, - recordBoardId, - ); + const recordBoardSelectedRecordIdsAtom = + useRecoilComponentSelectorCallbackStateV2( + recordBoardSelectedRecordIdsComponentSelector, + recordBoardId, + ); const { closeDropdown } = useCloseDropdown(); + const store = useStore(); const dropdownId = getActionMenuDropdownIdFromActionMenuId( getActionMenuIdFromRecordIndexId(instanceIdFromProps), ); - const setRecordAsSelected = useRecoilCallback( - ({ snapshot, set }) => - (recordId: string, isSelected: boolean) => { - const isRecordCurrentlySelected = snapshot - .getLoadable(isRecordBoardCardSelectedFamilyState(recordId)) - .getValue(); + const setRecordAsSelected = useCallback( + (recordId: string, isSelected: boolean) => { + const atom = isRecordBoardCardSelectedFamilyState(recordId); + const isRecordCurrentlySelected = store.get(atom); - if (isRecordCurrentlySelected === isSelected) { - return; - } + if (isRecordCurrentlySelected === isSelected) { + return; + } - set(isRecordBoardCardSelectedFamilyState(recordId), isSelected); - }, - [isRecordBoardCardSelectedFamilyState], + store.set(atom, isSelected); + }, + [isRecordBoardCardSelectedFamilyState, store], ); - const checkIfLastUnselectAndCloseDropdown = useRecoilCallback( - ({ snapshot }) => - () => { - const recordIds = getSnapshotValue( - snapshot, - recordBoardSelectedRecordIdsSelector, - ); - if (recordIds.length === 0) { - closeDropdown(dropdownId); - } - }, - [recordBoardSelectedRecordIdsSelector, closeDropdown, dropdownId], - ); + const checkIfLastUnselectAndCloseDropdown = useCallback(() => { + const recordIds = store.get(recordBoardSelectedRecordIdsAtom); + + if (recordIds.length === 0) { + closeDropdown(dropdownId); + } + }, [recordBoardSelectedRecordIdsAtom, store, closeDropdown, dropdownId]); return { setRecordAsSelected, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveRecordsFromBoard.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveRecordsFromBoard.ts index 249c571947..e954ae5092 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveRecordsFromBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveRecordsFromBoard.ts @@ -1,95 +1,96 @@ +import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { recordGroupFromGroupValueComponentFamilySelector } from '@/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; +import { useStore } from 'jotai'; + import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilySelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRemoveRecordsFromBoard = () => { - const recordIndexGroupFieldMetadataItemCallbackState = - useRecoilComponentCallbackState( + const store = useStore(); + const recordIndexGroupFieldMetadataItemAtom = + useRecoilComponentStateCallbackStateV2( recordIndexGroupFieldMetadataItemComponentState, ); const recordGroupFromGroupValueFamilyCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilySelectorCallbackStateV2( recordGroupFromGroupValueComponentFamilySelector, ); const recordIndexRecordIdsByGroupFamilyCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); - const removeRecordsFromBoard = useRecoilCallback( - ({ snapshot, set }) => - ({ recordIdsToRemove }: { recordIdsToRemove: string[] }) => { - const recordIdsToRemoveByGroup = new Map(); + const removeRecordsFromBoard = useCallback( + ({ recordIdsToRemove }: { recordIdsToRemove: string[] }) => { + const recordIdsToRemoveByGroup = new Map(); - for (const recordIdToRemove of recordIdsToRemove) { - const recordToRemove = getSnapshotValue( - snapshot, - recordStoreFamilyState(recordIdToRemove), - ); + for (const recordIdToRemove of recordIdsToRemove) { + const recordToRemove = store.get( + recordStoreFamilyState.atomFamily(recordIdToRemove), + ) as Record | null | undefined; - if (!isDefined(recordToRemove)) { - continue; - } - - const recordIndexGroupFieldMetadataItem = getSnapshotValue( - snapshot, - recordIndexGroupFieldMetadataItemCallbackState, - ); - - if (!isDefined(recordIndexGroupFieldMetadataItem)) { - continue; - } - - const recordGroupValue = - recordToRemove[recordIndexGroupFieldMetadataItem.name]; - - const recordGroupDefinitionFromGroupValue = getSnapshotValue( - snapshot, - recordGroupFromGroupValueFamilyCallbackState({ recordGroupValue }), - ); - - if (!isDefined(recordGroupDefinitionFromGroupValue)) { - continue; - } - - const groupId = recordGroupDefinitionFromGroupValue.id; - - if (!recordIdsToRemoveByGroup.has(groupId)) { - recordIdsToRemoveByGroup.set(groupId, []); - } - - recordIdsToRemoveByGroup.get(groupId)?.push(recordIdToRemove); + if (!isDefined(recordToRemove)) { + continue; } - for (const [ - groupId, - recordIdsToRemoveInGroup, - ] of recordIdsToRemoveByGroup) { - const currentRecordIdsForGroup = getSnapshotValue( - snapshot, - recordIndexRecordIdsByGroupFamilyCallbackState(groupId), - ); + const recordIndexGroupFieldMetadataItem = store.get( + recordIndexGroupFieldMetadataItemAtom, + ) as FieldMetadataItem | undefined; - const recordIdsWithoutRemovedRecords = - currentRecordIdsForGroup.filter( - (recordId) => !recordIdsToRemoveInGroup.includes(recordId), - ); - - set( - recordIndexRecordIdsByGroupFamilyCallbackState(groupId), - recordIdsWithoutRemovedRecords, - ); + if (!isDefined(recordIndexGroupFieldMetadataItem)) { + continue; } - }, + + const recordGroupValue = recordToRemove[ + recordIndexGroupFieldMetadataItem.name + ] as string | undefined; + + const recordGroupDefinitionFromGroupValue = store.get( + recordGroupFromGroupValueFamilyCallbackState({ recordGroupValue }), + ); + + if (!isDefined(recordGroupDefinitionFromGroupValue)) { + continue; + } + + const groupId = recordGroupDefinitionFromGroupValue.id; + + if (!recordIdsToRemoveByGroup.has(groupId)) { + recordIdsToRemoveByGroup.set(groupId, []); + } + + recordIdsToRemoveByGroup.get(groupId)?.push(recordIdToRemove); + } + + for (const [ + groupId, + recordIdsToRemoveInGroup, + ] of recordIdsToRemoveByGroup) { + const currentRecordIdsForGroup = store.get( + recordIndexRecordIdsByGroupFamilyCallbackState(groupId), + ) as string[]; + + const recordIdsWithoutRemovedRecords = currentRecordIdsForGroup.filter( + (recordId) => !recordIdsToRemoveInGroup.includes(recordId), + ); + + store.set( + recordIndexRecordIdsByGroupFamilyCallbackState(groupId), + recordIdsWithoutRemovedRecords, + ); + } + }, [ - recordIndexGroupFieldMetadataItemCallbackState, + store, + recordIndexGroupFieldMetadataItemAtom, recordGroupFromGroupValueFamilyCallbackState, recordIndexRecordIdsByGroupFamilyCallbackState, ], diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveSelectedRecordsFromRecordBoard.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveSelectedRecordsFromRecordBoard.ts index f676172116..a9d1b793f9 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveSelectedRecordsFromRecordBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRemoveSelectedRecordsFromRecordBoard.ts @@ -1,35 +1,38 @@ +import { useStore } from 'jotai'; + import { useResetRecordBoardSelection } from '@/object-record/record-board/hooks/useResetRecordBoardSelection'; import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; import { recordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useCallback } from 'react'; import { isDefined, isNonEmptyArray } from 'twenty-shared/utils'; export const useRemoveSelectedRecordsFromRecordBoard = ( recordBoardIndexId: string, ) => { - const recordGroupDefinitions = useRecoilComponentValue( + const store = useStore(); + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, recordBoardIndexId, ); - const groupByFieldMetadataItem = useRecoilComponentValue( + const groupByFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, recordBoardIndexId, ); const recordIndexRecordIdsByGroupCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, - recordBoardIndexId, ); - const recordBoardSelectedRecordIdsCallbackSelector = - useRecoilComponentCallbackState( + const recordBoardSelectedRecordIdsAtom = + useRecoilComponentSelectorCallbackStateV2( recordBoardSelectedRecordIdsComponentSelector, recordBoardIndexId, ); @@ -37,63 +40,58 @@ export const useRemoveSelectedRecordsFromRecordBoard = ( const { resetRecordBoardSelection } = useResetRecordBoardSelection(recordBoardIndexId); - const removeSelectedRecordsFromRecordBoard = useRecoilCallback( - ({ snapshot, set }) => - () => { - const deletedRecordIds = getSnapshotValue( - snapshot, - recordBoardSelectedRecordIdsCallbackSelector, - ); + const removeSelectedRecordsFromRecordBoard = useCallback(() => { + const deletedRecordIds = store.get( + recordBoardSelectedRecordIdsAtom, + ) as string[]; - if ( - !isDefined(groupByFieldMetadataItem) || - !isNonEmptyArray(recordGroupDefinitions) || - !isNonEmptyArray(deletedRecordIds) - ) { - return; - } + if ( + !isDefined(groupByFieldMetadataItem) || + !isNonEmptyArray(recordGroupDefinitions) || + !isNonEmptyArray(deletedRecordIds) + ) { + return; + } - for (const recordGroup of recordGroupDefinitions) { - const currentRecordIds = getSnapshotValue( - snapshot, - recordIndexRecordIdsByGroupCallbackState(recordGroup.id), + for (const recordGroup of recordGroupDefinitions) { + const currentRecordIds = store.get( + recordIndexRecordIdsByGroupCallbackState(recordGroup.id), + ) as string[]; + + let groupRecordIdsUpdated = [...currentRecordIds]; + + for (const deletedRecordId of deletedRecordIds) { + const indexOfDeletedRecordIdInGroupRecordIds = + groupRecordIdsUpdated.findIndex( + (recordIdInRecordGroup) => + recordIdInRecordGroup === deletedRecordId, ); - let groupRecordIdsUpdated = [...currentRecordIds]; - - for (const deletedRecordId of deletedRecordIds) { - const indexOfDeletedRecordIdInGroupRecordIds = - groupRecordIdsUpdated.findIndex( - (recordIdInRecordGroup) => - recordIdInRecordGroup === deletedRecordId, - ); - - if (indexOfDeletedRecordIdInGroupRecordIds > -1) { - groupRecordIdsUpdated = groupRecordIdsUpdated.toSpliced( - indexOfDeletedRecordIdInGroupRecordIds, - 1, - ); - } - } - - if (groupRecordIdsUpdated.length !== currentRecordIds.length) { - set( - recordIndexRecordIdsByGroupCallbackState(recordGroup.id), - groupRecordIdsUpdated, - ); - } + if (indexOfDeletedRecordIdInGroupRecordIds > -1) { + groupRecordIdsUpdated = groupRecordIdsUpdated.toSpliced( + indexOfDeletedRecordIdInGroupRecordIds, + 1, + ); } + } - resetRecordBoardSelection(); - }, - [ - groupByFieldMetadataItem, - recordIndexRecordIdsByGroupCallbackState, - recordGroupDefinitions, - recordBoardSelectedRecordIdsCallbackSelector, - resetRecordBoardSelection, - ], - ); + if (groupRecordIdsUpdated.length !== currentRecordIds.length) { + store.set( + recordIndexRecordIdsByGroupCallbackState(recordGroup.id), + groupRecordIdsUpdated, + ); + } + } + + resetRecordBoardSelection(); + }, [ + store, + groupByFieldMetadataItem, + recordIndexRecordIdsByGroupCallbackState, + recordGroupDefinitions, + recordBoardSelectedRecordIdsAtom, + resetRecordBoardSelection, + ]); return { removeSelectedRecordsFromRecordBoard, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useResetRecordBoardSelection.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useResetRecordBoardSelection.ts index e33a7f9b57..51ad6108dc 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useResetRecordBoardSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useResetRecordBoardSelection.ts @@ -1,5 +1,3 @@ -import { useRecoilCallback } from 'recoil'; - import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; @@ -7,8 +5,10 @@ import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/r import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useResetRecordBoardSelection = (recordBoardId?: string) => { const instanceIdFromProps = useAvailableComponentInstanceIdOrThrow( @@ -16,43 +16,40 @@ export const useResetRecordBoardSelection = (recordBoardId?: string) => { recordBoardId, ); - const isRecordBoardCardSelectedFamilyState = useRecoilComponentCallbackState( - isRecordBoardCardSelectedComponentFamilyState, - recordBoardId, - ); + const isRecordBoardCardSelectedFamilyState = + useRecoilComponentFamilyStateCallbackStateV2( + isRecordBoardCardSelectedComponentFamilyState, + recordBoardId, + ); - const recordBoardSelectedRecordIdsSelector = useRecoilComponentCallbackState( - recordBoardSelectedRecordIdsComponentSelector, - recordBoardId, - ); + const recordBoardSelectedRecordIdsAtom = + useRecoilComponentSelectorCallbackStateV2( + recordBoardSelectedRecordIdsComponentSelector, + recordBoardId, + ); const { closeDropdown } = useCloseDropdown(); + const store = useStore(); const dropdownId = getActionMenuDropdownIdFromActionMenuId( getActionMenuIdFromRecordIndexId(instanceIdFromProps), ); - const resetRecordBoardSelection = useRecoilCallback( - ({ snapshot, set }) => - () => { - closeDropdown(dropdownId); + const resetRecordBoardSelection = useCallback(() => { + closeDropdown(dropdownId); - const recordIds = getSnapshotValue( - snapshot, - recordBoardSelectedRecordIdsSelector, - ); + const recordIds = store.get(recordBoardSelectedRecordIdsAtom); - for (const recordId of recordIds) { - set(isRecordBoardCardSelectedFamilyState(recordId), false); - } - }, - [ - closeDropdown, - dropdownId, - recordBoardSelectedRecordIdsSelector, - isRecordBoardCardSelectedFamilyState, - ], - ); + for (const recordId of recordIds) { + store.set(isRecordBoardCardSelectedFamilyState(recordId), false); + } + }, [ + closeDropdown, + dropdownId, + recordBoardSelectedRecordIdsAtom, + isRecordBoardCardSelectedFamilyState, + store, + ]); return { resetRecordBoardSelection, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useSelectAllCards.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useSelectAllCards.ts index 42ec66541f..7130ddecd6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useSelectAllCards.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useSelectAllCards.ts @@ -1,23 +1,24 @@ -import { useRecoilCallback } from 'recoil'; - import { useResetRecordBoardSelection } from '@/object-record/record-board/hooks/useResetRecordBoardSelection'; import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; import { allCardsSelectedStatusComponentSelector } from '@/object-record/record-board/states/selectors/allCardsSelectedStatusComponentSelector'; import { allRecordIdsOfAllRecordGroupsComponentSelector } from '@/object-record/record-index/states/selectors/allRecordIdsOfAllRecordGroupsComponentSelector'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useSelectAllCards = (recordBoardId?: string) => { - const allCardsSelectedStatusSelector = useRecoilComponentCallbackState( + const allCardsSelectedStatusAtom = useRecoilComponentSelectorCallbackStateV2( allCardsSelectedStatusComponentSelector, recordBoardId, ); - const isRecordBoardCardSelectedFamilyState = useRecoilComponentCallbackState( - isRecordBoardCardSelectedComponentFamilyState, - recordBoardId, - ); - const allRecordIdsOfAllRecordGroupsCallbackSelector = - useRecoilComponentCallbackState( + const isRecordBoardCardSelectedFamilyState = + useRecoilComponentFamilyStateCallbackStateV2( + isRecordBoardCardSelectedComponentFamilyState, + recordBoardId, + ); + const allRecordIdsOfAllRecordGroupsAtom = + useRecoilComponentSelectorCallbackStateV2( allRecordIdsOfAllRecordGroupsComponentSelector, recordBoardId, ); @@ -25,38 +26,29 @@ export const useSelectAllCards = (recordBoardId?: string) => { const { resetRecordBoardSelection } = useResetRecordBoardSelection(recordBoardId); - const selectAllCards = useRecoilCallback( - ({ set, snapshot }) => - () => { - const allCardsSelectedStatus = getSnapshotValue( - snapshot, - allCardsSelectedStatusSelector, - ); + const store = useStore(); - const allRecordIds = getSnapshotValue( - snapshot, - allRecordIdsOfAllRecordGroupsCallbackSelector, - ); + const selectAllCards = useCallback(() => { + const allCardsSelectedStatus = store.get(allCardsSelectedStatusAtom); + const allRecordIds = store.get(allRecordIdsOfAllRecordGroupsAtom); - if (allCardsSelectedStatus === 'all') { - resetRecordBoardSelection(); - } + if (allCardsSelectedStatus === 'all') { + resetRecordBoardSelection(); + } - for (const recordId of allRecordIds) { - const isSelected = - allCardsSelectedStatus === 'none' || - allCardsSelectedStatus === 'some'; + for (const recordId of allRecordIds) { + const isSelected = + allCardsSelectedStatus === 'none' || allCardsSelectedStatus === 'some'; - set(isRecordBoardCardSelectedFamilyState(recordId), isSelected); - } - }, - [ - allCardsSelectedStatusSelector, - allRecordIdsOfAllRecordGroupsCallbackSelector, - resetRecordBoardSelection, - isRecordBoardCardSelectedFamilyState, - ], - ); + store.set(isRecordBoardCardSelectedFamilyState(recordId), isSelected); + } + }, [ + allCardsSelectedStatusAtom, + allRecordIdsOfAllRecordGroupsAtom, + resetRecordBoardSelection, + isRecordBoardCardSelectedFamilyState, + store, + ]); return { selectAllCards, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useSetRecordIdsForColumn.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useSetRecordIdsForColumn.ts index 428783d127..ef9358d7cc 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useSetRecordIdsForColumn.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useSetRecordIdsForColumn.ts @@ -1,85 +1,83 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { emptyRecordGroupByIdComponentFamilyState } from '@/object-record/record-group/states/emptyRecordGroupByIdComponentFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useSetRecordIdsForColumn = (recordBoardId?: string) => { - const recordGroupFieldMetadataState = useRecoilComponentCallbackState( + const store = useStore(); + + const recordGroupFieldMetadataAtom = useRecoilComponentStateCallbackStateV2( recordIndexGroupFieldMetadataItemComponentState, recordBoardId, ); const recordIndexRecordIdsByGroupFamilyState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, recordBoardId, ); - const emptyRecordGroupByIdCallbackState = useRecoilComponentCallbackState( - emptyRecordGroupByIdComponentFamilyState, - ); + const emptyRecordGroupByIdCallbackState = + useRecoilComponentFamilyStateCallbackStateV2( + emptyRecordGroupByIdComponentFamilyState, + ); - const setRecordIdsForColumn = useRecoilCallback( - ({ set, snapshot }) => - (currentRecordGroupId: string, records: ObjectRecord[]) => { - const recordGroup = getSnapshotValue( - snapshot, - recordGroupDefinitionFamilyState(currentRecordGroupId), - ); + const setRecordIdsForColumn = useCallback( + (currentRecordGroupId: string, records: ObjectRecord[]) => { + const recordGroup = store.get( + recordGroupDefinitionFamilyState.atomFamily(currentRecordGroupId), + ); - const existingRecordGroupRowIds = getSnapshotValue( - snapshot, + const existingRecordGroupRowIds = store.get( + recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId), + ); + + const recordGroupFieldMetadata = store.get(recordGroupFieldMetadataAtom); + + if (!isDefined(recordGroupFieldMetadata)) { + return; + } + + const recordGroupRowIds = records + .filter( + (record) => + record[recordGroupFieldMetadata.name] === recordGroup?.value, + ) + .map((record) => record.id); + + if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) { + store.set( recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId), + recordGroupRowIds, ); + } - const recordGroupFieldMetadata = getSnapshotValue( - snapshot, - recordGroupFieldMetadataState, - ); + const isEmptyRecordGroup = store.get( + emptyRecordGroupByIdCallbackState(currentRecordGroupId), + ); - if (!isDefined(recordGroupFieldMetadata)) { - return; - } + const computedIsEmptyRecordGroup = recordGroupRowIds.length === 0; - const recordGroupRowIds = records - .filter( - (record) => - record[recordGroupFieldMetadata.name] === recordGroup?.value, - ) - .map((record) => record.id); - - if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) { - set( - recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId), - recordGroupRowIds, - ); - } - - const isEmptyRecordGroup = getSnapshotValue( - snapshot, + if (computedIsEmptyRecordGroup !== isEmptyRecordGroup) { + store.set( emptyRecordGroupByIdCallbackState(currentRecordGroupId), + computedIsEmptyRecordGroup, ); - - const computedIsEmptyRecordGroup = recordGroupRowIds.length === 0; - - if (computedIsEmptyRecordGroup !== isEmptyRecordGroup) { - set( - emptyRecordGroupByIdCallbackState(currentRecordGroupId), - computedIsEmptyRecordGroup, - ); - } - }, + } + }, [ recordIndexRecordIdsByGroupFamilyState, - recordGroupFieldMetadataState, + recordGroupFieldMetadataAtom, emptyRecordGroupByIdCallbackState, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardFetchMore.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardFetchMore.ts index 7ddf6a03d6..be05a7ec59 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardFetchMore.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardFetchMore.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; import { RECORD_BOARD_FETCH_MORE_THROTTLING_WAIT_TIME_IN_MILLISECONDS_TO_AVOID_REACT_FREEZE } from '@/object-record/record-board/constants/RecordBoardFetchMoreThrottlingWaitTimeInMillisecondsToAvoidReactFreeze'; import { RECORD_BOARD_QUERY_PAGE_SIZE } from '@/object-record/record-board/constants/RecordBoardQueryPageSize'; @@ -13,28 +16,29 @@ import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { getGroupByQueryResultGqlFieldName } from '@/page-layout/utils/getGroupByQueryResultGqlFieldName'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { isNonEmptyArray } from '@sniptt/guards'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { sortByProperty } from '~/utils/array/sortByProperty'; import { sleep } from '~/utils/sleep'; export const useTriggerRecordBoardFetchMore = () => { - const recordGroupDefinitions = useRecoilComponentValue( + const store = useStore(); + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, ); const { objectMetadataItem } = useRecordIndexContextOrThrow(); - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); const recordBoardShouldFetchMoreInColumnFamilyCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordBoardShouldFetchMoreInColumnComponentFamilyState, ); @@ -43,7 +47,7 @@ export const useTriggerRecordBoardFetchMore = () => { const { upsertRecordsInStore } = useUpsertRecordsInStore(); const recordBoardCurrentGroupByQueryOffsetCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( recordBoardCurrentGroupByQueryOffsetComponentState, ); @@ -54,177 +58,169 @@ export const useTriggerRecordBoardFetchMore = () => { }); const recordIndexRecordIdsByGroupCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); - const recordBoardIsFetchingMoreCallbackState = - useRecoilComponentCallbackState(recordBoardIsFetchingMoreComponentState); - - const triggerRecordBoardFetchMore = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const isAlreadyFetchingMore = getSnapshotValue( - snapshot, - recordBoardIsFetchingMoreCallbackState, - ); - - const cleanStateBeforeExit = () => { - set(recordBoardIsFetchingMoreCallbackState, false); - }; - - if (isAlreadyFetchingMore) { - return; - } - - set(recordBoardIsFetchingMoreCallbackState, true); - - const currentOffset = getSnapshotValue( - snapshot, - recordBoardCurrentGroupByQueryOffsetCallbackState, - ); - - const newOffset = currentOffset + RECORD_BOARD_QUERY_PAGE_SIZE; - - const recordGroupValuesThatShouldBeFetched = recordGroupDefinitions - .filter((recordGroupDefinition) => { - return getSnapshotValue( - snapshot, - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - ); - }) - .map((recordGroupDefinition) => recordGroupDefinition.value) - .filter(isDefined); - - if (!isNonEmptyArray(recordGroupValuesThatShouldBeFetched)) { - cleanStateBeforeExit(); - - return; - } - - const recordIndexGroupsRecordsGroupByLazyQueryResult = - await executeRecordIndexGroupsRecordsLazyGroupBy({ - variables: { - offsetForRecords: newOffset, - filter: { - ...combinedFilters, - [recordIndexGroupFieldMetadataItem?.name ?? '']: { - in: [...recordGroupValuesThatShouldBeFetched], - }, - }, - }, - }); - - set(recordBoardCurrentGroupByQueryOffsetCallbackState, newOffset); - - if (!isDefined(recordIndexGroupsRecordsGroupByLazyQueryResult)) { - cleanStateBeforeExit(); - - return; - } - - const queryFieldName = - getGroupByQueryResultGqlFieldName(objectMetadataItem); - - const groups = - recordIndexGroupsRecordsGroupByLazyQueryResult.data?.[queryFieldName]; - - if (!isDefined(groups)) { - cleanStateBeforeExit(); - - return; - } - - const sortedRecordGroupDefinitions = recordGroupDefinitions.toSorted( - sortByProperty('position'), - ); - - for (const recordGroupDefinition of sortedRecordGroupDefinitions) { - const foundGroupInResult = groups.find( - (recordGroup: any) => - (recordGroup.groupByDimensionValues[0] as string) === - recordGroupDefinition.value, - ); - - if (!isDefined(foundGroupInResult)) { - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - false, - ); - continue; - } - - const newRecords = getRecordsFromRecordConnection({ - recordConnection: foundGroupInResult, - }); - - if (!isNonEmptyArray(newRecords)) { - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - false, - ); - continue; - } - - const currentRecordIds = getSnapshotValue( - snapshot, - recordIndexRecordIdsByGroupCallbackState(recordGroupDefinition.id), - ); - - const newRecordIds = currentRecordIds.concat( - newRecords.map((record) => record.id), - ); - - set( - recordIndexRecordIdsByGroupCallbackState(recordGroupDefinition.id), - newRecordIds, - ); - - upsertRecordsInStore({ partialRecords: newRecords }); - - if (newRecords.length < RECORD_BOARD_QUERY_PAGE_SIZE) { - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - false, - ); - } else { - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - true, - ); - } - - await sleep( - RECORD_BOARD_FETCH_MORE_THROTTLING_WAIT_TIME_IN_MILLISECONDS_TO_AVOID_REACT_FREEZE, - ); - } - - cleanStateBeforeExit(); - }, - [ - objectMetadataItem, - recordGroupDefinitions, - upsertRecordsInStore, - executeRecordIndexGroupsRecordsLazyGroupBy, - recordIndexRecordIdsByGroupCallbackState, - recordBoardIsFetchingMoreCallbackState, - recordBoardCurrentGroupByQueryOffsetCallbackState, - recordBoardShouldFetchMoreInColumnFamilyCallbackState, - combinedFilters, - recordIndexGroupFieldMetadataItem, - ], + const recordBoardIsFetchingMoreAtom = useRecoilComponentStateCallbackStateV2( + recordBoardIsFetchingMoreComponentState, ); + const triggerRecordBoardFetchMore = useCallback(async () => { + const isAlreadyFetchingMore = store.get(recordBoardIsFetchingMoreAtom); + + const cleanStateBeforeExit = () => { + store.set(recordBoardIsFetchingMoreAtom, false); + }; + + if (isAlreadyFetchingMore) { + return; + } + + store.set(recordBoardIsFetchingMoreAtom, true); + + const currentOffset = store.get( + recordBoardCurrentGroupByQueryOffsetCallbackState, + ); + + const newOffset = currentOffset + RECORD_BOARD_QUERY_PAGE_SIZE; + + const recordGroupValuesThatShouldBeFetched = recordGroupDefinitions + .filter((recordGroupDefinition) => { + return store.get( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + ); + }) + .map((recordGroupDefinition) => recordGroupDefinition.value) + .filter(isDefined); + + if (!isNonEmptyArray(recordGroupValuesThatShouldBeFetched)) { + cleanStateBeforeExit(); + + return; + } + + const recordIndexGroupsRecordsGroupByLazyQueryResult = + await executeRecordIndexGroupsRecordsLazyGroupBy({ + variables: { + offsetForRecords: newOffset, + filter: { + ...combinedFilters, + [recordIndexGroupFieldMetadataItem?.name ?? '']: { + in: [...recordGroupValuesThatShouldBeFetched], + }, + }, + }, + }); + + store.set(recordBoardCurrentGroupByQueryOffsetCallbackState, newOffset); + + if (!isDefined(recordIndexGroupsRecordsGroupByLazyQueryResult)) { + cleanStateBeforeExit(); + + return; + } + + const queryFieldName = + getGroupByQueryResultGqlFieldName(objectMetadataItem); + + const groups = + recordIndexGroupsRecordsGroupByLazyQueryResult.data?.[queryFieldName]; + + if (!isDefined(groups)) { + cleanStateBeforeExit(); + + return; + } + + const sortedRecordGroupDefinitions = recordGroupDefinitions.toSorted( + sortByProperty('position'), + ); + + for (const recordGroupDefinition of sortedRecordGroupDefinitions) { + const foundGroupInResult = groups.find( + (recordGroup: any) => + (recordGroup.groupByDimensionValues[0] as string) === + recordGroupDefinition.value, + ); + + if (!isDefined(foundGroupInResult)) { + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + false, + ); + continue; + } + + const newRecords = getRecordsFromRecordConnection({ + recordConnection: foundGroupInResult, + }); + + if (!isNonEmptyArray(newRecords)) { + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + false, + ); + continue; + } + + const currentRecordIds = store.get( + recordIndexRecordIdsByGroupCallbackState(recordGroupDefinition.id), + ) as string[]; + + const newRecordIds = currentRecordIds.concat( + newRecords.map((record) => record.id), + ); + + store.set( + recordIndexRecordIdsByGroupCallbackState(recordGroupDefinition.id), + newRecordIds, + ); + + upsertRecordsInStore({ partialRecords: newRecords }); + + if (newRecords.length < RECORD_BOARD_QUERY_PAGE_SIZE) { + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + false, + ); + } else { + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + true, + ); + } + + await sleep( + RECORD_BOARD_FETCH_MORE_THROTTLING_WAIT_TIME_IN_MILLISECONDS_TO_AVOID_REACT_FREEZE, + ); + } + + cleanStateBeforeExit(); + }, [ + store, + objectMetadataItem, + recordGroupDefinitions, + upsertRecordsInStore, + executeRecordIndexGroupsRecordsLazyGroupBy, + recordIndexRecordIdsByGroupCallbackState, + recordBoardIsFetchingMoreAtom, + recordBoardCurrentGroupByQueryOffsetCallbackState, + recordBoardShouldFetchMoreInColumnFamilyCallbackState, + combinedFilters, + recordIndexGroupFieldMetadataItem, + ]); + return { triggerRecordBoardFetchMore, }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts index 069bacd0ad..76f1ce1c08 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts @@ -14,39 +14,44 @@ import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useU import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; import { getGroupByQueryResultGqlFieldName } from '@/page-layout/utils/getGroupByQueryResultGqlFieldName'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isNonEmptyArray } from '@sniptt/guards'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; export const useTriggerRecordBoardInitialQuery = () => { - const recordGroupDefinitions = useRecoilComponentValue( + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, ); const { objectMetadataItem } = useRecordIndexContextOrThrow(); - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); - const setLastRecordBoardQueryIdentifier = useSetRecoilComponentState( + const setLastRecordBoardQueryIdentifier = useSetRecoilComponentStateV2( lastRecordBoardQueryIdentifierComponentState, ); const recordBoardShouldFetchMoreInColumnFamilyCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordBoardShouldFetchMoreInColumnComponentFamilyState, ); - const recordIndexRecordGroupsAreInInitialLoadingCallbackState = - useRecoilComponentCallbackState( + const recordIndexRecordGroupsAreInInitialLoadingAtom = + useRecoilComponentStateCallbackStateV2( recordIndexRecordGroupsAreInInitialLoadingComponentState, ); - const setRecordBoardCurrentGroupByQueryOffset = useSetRecoilComponentState( + const store = useStore(); + + const setRecordBoardCurrentGroupByQueryOffset = useSetRecoilComponentStateV2( recordBoardCurrentGroupByQueryOffsetComponentState, ); @@ -70,112 +75,109 @@ export const useTriggerRecordBoardInitialQuery = () => { objectMetadataItem, }); - const triggerRecordBoardInitialQuery = useRecoilCallback( - ({ set }) => - async () => { - set(recordIndexRecordGroupsAreInInitialLoadingCallbackState, true); + const triggerRecordBoardInitialQuery = useCallback(async () => { + store.set(recordIndexRecordGroupsAreInInitialLoadingAtom, true); - const cleanStateBeforeExit = () => { - set(recordIndexRecordGroupsAreInInitialLoadingCallbackState, false); + const cleanStateBeforeExit = () => { + store.set(recordIndexRecordGroupsAreInInitialLoadingAtom, false); - setLastRecordBoardQueryIdentifier(queryIdentifier); + setLastRecordBoardQueryIdentifier(queryIdentifier); - setRecordBoardCurrentGroupByQueryOffset(0); + setRecordBoardCurrentGroupByQueryOffset(0); - scrollWrapperHTMLElement?.scrollTo({ top: 0, left: 0 }); - }; + scrollWrapperHTMLElement?.scrollTo({ top: 0, left: 0 }); + }; - const recordIndexGroupsRecordsGroupByLazyQueryResult = - await executeRecordIndexGroupsRecordsLazyGroupBy(); + const recordIndexGroupsRecordsGroupByLazyQueryResult = + await executeRecordIndexGroupsRecordsLazyGroupBy(); - if (!isDefined(recordIndexGroupsRecordsGroupByLazyQueryResult)) { - cleanStateBeforeExit(); + if (!isDefined(recordIndexGroupsRecordsGroupByLazyQueryResult)) { + cleanStateBeforeExit(); - return; - } + return; + } - const queryFieldName = - getGroupByQueryResultGqlFieldName(objectMetadataItem); + const queryFieldName = + getGroupByQueryResultGqlFieldName(objectMetadataItem); - const groups = - recordIndexGroupsRecordsGroupByLazyQueryResult.data?.[queryFieldName]; + const groups = + recordIndexGroupsRecordsGroupByLazyQueryResult.data?.[queryFieldName]; - if (!isDefined(groups)) { - cleanStateBeforeExit(); + if (!isDefined(groups)) { + cleanStateBeforeExit(); - return; - } + return; + } - for (const recordGroupDefinition of recordGroupDefinitions) { - const foundGroupInResult = groups?.find( - (recordGroup: any) => - (recordGroup.groupByDimensionValues[0] as string) === - recordGroupDefinition.value, - ); + for (const recordGroupDefinition of recordGroupDefinitions) { + const foundGroupInResult = groups?.find( + (recordGroup: any) => + (recordGroup.groupByDimensionValues[0] as string) === + recordGroupDefinition.value, + ); - if (!isDefined(foundGroupInResult)) { - setRecordIdsForColumn(recordGroupDefinition.id, []); - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - false, - ); - continue; - } + if (!isDefined(foundGroupInResult)) { + setRecordIdsForColumn(recordGroupDefinition.id, []); + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + false, + ); + continue; + } - const records = getRecordsFromRecordConnection({ - recordConnection: foundGroupInResult, - }); + const records = getRecordsFromRecordConnection({ + recordConnection: foundGroupInResult, + }); - if (!isNonEmptyArray(records)) { - setRecordIdsForColumn(recordGroupDefinition.id, []); - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - false, - ); - continue; - } + if (!isNonEmptyArray(records)) { + setRecordIdsForColumn(recordGroupDefinition.id, []); + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + false, + ); + continue; + } - upsertRecordsInStore({ partialRecords: records }); + upsertRecordsInStore({ partialRecords: records }); - setRecordIdsForColumn(recordGroupDefinition.id, records); + setRecordIdsForColumn(recordGroupDefinition.id, records); - if (records.length < RECORD_BOARD_QUERY_PAGE_SIZE) { - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - false, - ); - } else { - set( - recordBoardShouldFetchMoreInColumnFamilyCallbackState( - recordGroupDefinition.id, - ), - true, - ); - } - } + if (records.length < RECORD_BOARD_QUERY_PAGE_SIZE) { + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + false, + ); + } else { + store.set( + recordBoardShouldFetchMoreInColumnFamilyCallbackState( + recordGroupDefinition.id, + ), + true, + ); + } + } - cleanStateBeforeExit(); - }, - [ - recordIndexRecordGroupsAreInInitialLoadingCallbackState, - executeRecordIndexGroupsRecordsLazyGroupBy, - objectMetadataItem, - setLastRecordBoardQueryIdentifier, - queryIdentifier, - setRecordBoardCurrentGroupByQueryOffset, - scrollWrapperHTMLElement, - recordGroupDefinitions, - upsertRecordsInStore, - setRecordIdsForColumn, - recordBoardShouldFetchMoreInColumnFamilyCallbackState, - ], - ); + cleanStateBeforeExit(); + }, [ + recordIndexRecordGroupsAreInInitialLoadingAtom, + store, + executeRecordIndexGroupsRecordsLazyGroupBy, + objectMetadataItem, + setLastRecordBoardQueryIdentifier, + queryIdentifier, + setRecordBoardCurrentGroupByQueryOffset, + scrollWrapperHTMLElement, + recordGroupDefinitions, + upsertRecordsInStore, + setRecordIdsForColumn, + recordBoardShouldFetchMoreInColumnFamilyCallbackState, + ]); return { triggerRecordBoardInitialQuery, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellEditModePortal.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellEditModePortal.tsx index 69161e565e..68b2e0d94a 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellEditModePortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellEditModePortal.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { RecordBoardCardInputContextProvider } from '@/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider'; @@ -16,7 +16,7 @@ export const RecordBoardCardCellEditModePortal = () => { const { objectMetadataItem } = useContext(RecordBoardContext); const { recordId } = useContext(RecordBoardCardContext); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordBoardCardEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellHoveredPortalContent.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellHoveredPortalContent.tsx index aa27092557..25be176ad7 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellHoveredPortalContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardCellHoveredPortalContent.tsx @@ -10,8 +10,8 @@ import { RecordInlineCellDisplayMode } from '@/object-record/record-inline-cell/ import { RecordInlineCellHoveredPortalContent } from '@/object-record/record-inline-cell/components/RecordInlineCellHoveredPortalContent'; import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext } from 'react'; export const RecordBoardCardCellHoveredPortalContent = () => { @@ -32,9 +32,9 @@ export const RecordBoardCardCellHoveredPortalContent = () => { !isRecordFieldReadOnly && !editModeContentOnly; const [recordBoardCardHoverPosition, setRecordBoardCardHoverPosition] = - useRecoilComponentState(recordBoardCardHoverPositionComponentState); + useRecoilComponentStateV2(recordBoardCardHoverPositionComponentState); - const setRecordBoardCardEditModePosition = useSetRecoilComponentState( + const setRecordBoardCardEditModePosition = useSetRecoilComponentStateV2( recordBoardCardEditModePositionComponentState, ); const { openFieldInput } = useOpenFieldInputEditMode(); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider.tsx index 7a9efb55fd..056aea7c5a 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/anchored-portal/components/RecordBoardCardInputContextProvider.tsx @@ -10,7 +10,7 @@ import { import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { currentFocusIdSelector } from '@/ui/utilities/focus/states/currentFocusIdSelector'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useStore } from 'jotai'; import { useCallback } from 'react'; @@ -23,7 +23,7 @@ export const RecordBoardCardInputContextProvider = ({ }: RecordBoardCardInputContextProviderProps) => { const store = useStore(); const { closeInlineCell } = useInlineCell(); - const setRecordBoardCardEditModePosition = useSetRecoilComponentState( + const setRecordBoardCardEditModePosition = useSetRecoilComponentStateV2( recordBoardCardEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx index 0ad245f90a..d6797aeac9 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx @@ -25,10 +25,10 @@ import { RecordFieldsScopeContextProvider } from '@/object-record/record-field-l import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import styled from '@emotion/styled'; import { useContext } from 'react'; @@ -59,12 +59,12 @@ export const RecordBoardCard = () => { RecordBoardComponentInstanceContext, ); - const isRecordIdPrimaryDragMultiple = useRecoilComponentFamilyValue( + const isRecordIdPrimaryDragMultiple = useRecoilComponentFamilyValueV2( isRecordIdPrimaryDragMultipleComponentFamilyState, { recordId }, ); - const isRecordIdSecondaryDragMultiple = useRecoilComponentFamilyValue( + const isRecordIdSecondaryDragMultiple = useRecoilComponentFamilyValueV2( isRecordIdSecondaryDragMultipleComponentFamilyState, { recordId }, ); @@ -73,18 +73,18 @@ export const RecordBoardCard = () => { const isCompactModeActive = currentView?.isCompact ?? false; - const [isCardExpanded, setIsCardExpanded] = useRecoilComponentState( + const [isCardExpanded, setIsCardExpanded] = useRecoilComponentStateV2( recordBoardCardIsExpandedComponentState, `record-board-card-${recordId}`, ); const [isCurrentCardSelected, setIsCurrentCardSelected] = - useRecoilComponentFamilyState( + useRecoilComponentFamilyStateV2( isRecordBoardCardSelectedComponentFamilyState, recordId, ); - const isCurrentCardFocused = useRecoilComponentFamilyValue( + const isCurrentCardFocused = useRecoilComponentFamilyValueV2( isRecordBoardCardFocusedComponentFamilyState, { rowIndex, @@ -92,7 +92,7 @@ export const RecordBoardCard = () => { }, ); - const isCurrentCardActive = useRecoilComponentFamilyValue( + const isCurrentCardActive = useRecoilComponentFamilyValueV2( isRecordBoardCardActiveComponentFamilyState, { rowIndex, @@ -105,7 +105,7 @@ export const RecordBoardCard = () => { const actionMenuDropdownId = getActionMenuDropdownIdFromActionMenuId(actionMenuId); - const setActionMenuDropdownPosition = useSetRecoilComponentState( + const setActionMenuDropdownPosition = useSetRecoilComponentStateV2( recordIndexActionMenuDropdownPositionComponentState, actionMenuDropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx index cce4227220..712bdf8fa6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx @@ -15,8 +15,8 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-fiel import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext } from 'react'; export const RecordBoardCardBody = () => { @@ -40,7 +40,7 @@ export const RecordBoardCardBody = () => { return [updateEntity, { loading: false }]; }; - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); @@ -49,7 +49,7 @@ export const RecordBoardCardBody = () => { recordField.fieldMetadataItemId !== labelIdentifierFieldMetadataItem?.id, ); - const setRecordBoardCardHoverPosition = useSetRecoilComponentState( + const setRecordBoardCardHoverPosition = useSetRecoilComponentStateV2( recordBoardCardHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardDraggableContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardDraggableContainer.tsx index 4fc2296aed..07f36acc28 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardDraggableContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardDraggableContainer.tsx @@ -11,7 +11,7 @@ import { RecordBoardCardContext } from '@/object-record/record-board/record-boar import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState'; import { DragAndDropLibraryLegacyReRenderBreaker } from '@/ui/drag-and-drop/components/DragAndDropReRenderBreaker'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; const StyledDraggableContainer = styled.div` position: relative; @@ -36,7 +36,7 @@ export const RecordBoardCardDraggableContainer = ({ const { columnIndex } = useContext(RecordBoardColumnContext); - const isRecordBoardCardFocusActive = useRecoilComponentFamilyValue( + const isRecordBoardCardFocusActive = useRecoilComponentFamilyValueV2( isRecordBoardCardFocusedComponentFamilyState, { rowIndex, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx index 04126dcfe5..65f921746a 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx @@ -12,13 +12,14 @@ import { RecordCardHeaderContainer } from '@/object-record/record-card/component import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView'; import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import styled from '@emotion/styled'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { ChipVariant } from 'twenty-ui/components'; import { IconEye, IconEyeOff } from 'twenty-ui/display'; @@ -53,7 +54,7 @@ export const RecordBoardCardHeader = () => { const isCompactModeActive = currentView?.isCompact ?? false; - const [isCardExpanded, setIsCardExpanded] = useRecoilComponentState( + const [isCardExpanded, setIsCardExpanded] = useRecoilComponentStateV2( recordBoardCardIsExpandedComponentState, ); @@ -61,16 +62,18 @@ export const RecordBoardCardHeader = () => { useRecordBoardSelection(recordBoardId); const [isCurrentCardSelected, setIsCurrentCardSelected] = - useRecoilComponentFamilyState( + useRecoilComponentFamilyStateV2( isRecordBoardCardSelectedComponentFamilyState, recordId, ); const { openRecordFromIndexView } = useOpenRecordFromIndexView(); - const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); + const recordIndexOpenRecordIn = useRecoilValueV2( + recordIndexOpenRecordInState, + ); - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const triggerEvent = recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragCounterChip.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragCounterChip.tsx index b008d645a9..62c3be9717 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragCounterChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragCounterChip.tsx @@ -1,5 +1,5 @@ import { originalDragSelectionComponentState } from '@/object-record/record-drag/states/originalDragSelectionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { NotificationCounter } from 'twenty-ui/navigation'; @@ -11,7 +11,7 @@ const StyledNotificationCounter = styled(NotificationCounter)` `; export const RecordBoardCardMultiDragCounterChip = () => { - const originalDragSelection = useRecoilComponentValue( + const originalDragSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragPreview.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragPreview.tsx index 851e957d7f..e951dc2202 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragPreview.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragPreview.tsx @@ -1,14 +1,14 @@ import { RecordBoardCardMultiDragCounterChip } from '@/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragCounterChip'; import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext'; import { isRecordIdPrimaryDragMultipleComponentFamilyState } from '@/object-record/record-drag/states/isRecordIdPrimaryDragMultipleComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { useContext } from 'react'; // TODO: use the same concept as PortalHovered components in the app export const RecordBoardCardMultiDragPreview = () => { const { recordId } = useContext(RecordBoardCardContext); - const isRecordIdPrimaryDragMultiple = useRecoilComponentFamilyValue( + const isRecordIdPrimaryDragMultiple = useRecoilComponentFamilyValueV2( isRecordIdPrimaryDragMultipleComponentFamilyState, { recordId }, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragStack.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragStack.tsx index c41c94b863..b9e1fb3fb5 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragStack.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardMultiDragStack.tsx @@ -1,5 +1,5 @@ import { originalDragSelectionComponentState } from '@/object-record/record-drag/states/originalDragSelectionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; const StyledRecordBoardCardStackCard = styled.div<{ offset: number }>` @@ -15,7 +15,7 @@ const StyledRecordBoardCardStackCard = styled.div<{ offset: number }>` `; export const RecordBoardCardMultiDragStack = () => { - const originalDragSelection = useRecoilComponentValue( + const originalDragSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts index 92934003ea..c70281fbdb 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts @@ -3,22 +3,23 @@ import { recordBoardCardEditModePositionComponentState } from '@/object-record/r import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState'; import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRecordBoardCardMetadataFromPosition = () => { const { objectMetadataItem } = useContext(RecordBoardContext); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordBoardCardHoverPositionComponentState, ); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordBoardCardEditModePositionComponentState, ); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState.ts index 0b13a60e60..72568be946 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardCardComponentInstanceContext } from '@/object-record/record-board/record-board-card/states/contexts/RecordBoardCardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordBoardCardEditModePositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordBoardCardEditModePositionComponentState', defaultValue: null, componentInstanceContext: RecordBoardCardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState.ts index aff482cc5e..cdb5066ab0 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState.ts @@ -1,10 +1,9 @@ import { RecordBoardCardComponentInstanceContext } from '@/object-record/record-board/record-board-card/states/contexts/RecordBoardCardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const recordBoardCardHoverPositionComponentState = createComponentState< - number | null ->({ - key: 'recordBoardCardHoverPositionComponentState', - defaultValue: null, - componentInstanceContext: RecordBoardCardComponentInstanceContext, -}); +export const recordBoardCardHoverPositionComponentState = + createComponentStateV2({ + key: 'recordBoardCardHoverPositionComponentState', + defaultValue: null, + componentInstanceContext: RecordBoardCardComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardIsExpandedComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardIsExpandedComponentState.ts index 31100eb958..ab598dcf0c 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardIsExpandedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/states/recordBoardCardIsExpandedComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardCardComponentInstanceContext } from '@/object-record/record-board/record-board-card/states/contexts/RecordBoardCardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordBoardCardIsExpandedComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordBoardCardIsExpandedComponentState', defaultValue: false, componentInstanceContext: RecordBoardCardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx index 94457e3403..5ca76180e3 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx @@ -7,8 +7,8 @@ import { useShouldHideRecordGroup } from '@/object-record/record-group/hooks/use import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { DragAndDropLibraryLegacyReRenderBreaker } from '@/ui/drag-and-drop/components/DragAndDropReRenderBreaker'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { isDefined } from 'twenty-shared/utils'; const StyledColumn = styled.div` @@ -34,10 +34,11 @@ export const RecordBoardColumn = ({ recordBoardColumnId, recordBoardColumnIndex, }: RecordBoardColumnProps) => { - const recordGroupDefinition = useRecoilValue( - recordGroupDefinitionFamilyState(recordBoardColumnId), + const recordGroupDefinition = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + recordBoardColumnId, ); - const recordIdsByGroup = useRecoilComponentFamilyValue( + const recordIdsByGroup = useRecoilComponentFamilyValueV2( recordIndexRecordIdsByGroupComponentFamilyState, recordBoardColumnId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx index 94008c863f..f6f6041311 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader.tsx @@ -6,7 +6,7 @@ import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLo import { RecordCardBodyContainer } from '@/object-record/record-card/components/RecordCardBodyContainer'; import { RecordCardHeaderContainer } from '@/object-record/record-card/components/RecordCardHeaderContainer'; import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; const StyledSkeletonIconAndText = styled.div` @@ -41,7 +41,7 @@ export const RecordBoardColumnCardContainerSkeletonLoader = () => { const isCompactModeActive = currentView?.isCompact ?? false; - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx index 0e000e1d78..ac2015156e 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx @@ -10,7 +10,7 @@ import { RecordBoardColumnContext } from '@/object-record/record-board/record-bo import { RecordBoardColumnLoadingSkeletonCards } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnLoadingSkeletonCards'; import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; const StyledColumnCardsContainer = styled.div` display: flex; @@ -33,12 +33,12 @@ export const RecordBoardColumnCardsContainer = ({ }: RecordBoardColumnCardsContainerProps) => { const { columnDefinition } = useContext(RecordBoardColumnContext); - const recordIds = useRecoilComponentFamilyValue( + const recordIds = useRecoilComponentFamilyValueV2( recordIndexRecordIdsByGroupComponentFamilyState, recordBoardColumnId, ); - const recordBoardShouldFetchMoreInColumn = useRecoilComponentFamilyValue( + const recordBoardShouldFetchMoreInColumn = useRecoilComponentFamilyValueV2( recordBoardShouldFetchMoreInColumnComponentFamilyState, recordBoardColumnId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx index 57997e5bf5..48c99f1201 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx @@ -15,8 +15,9 @@ import { recordIndexAggregateDisplayValueForGroupValueComponentFamilyState } fro import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { Tag } from 'twenty-ui/components'; import { IconDotsVertical, IconPlus } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; @@ -91,7 +92,7 @@ export const RecordBoardColumnHeader = () => { const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords; - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, ); @@ -100,12 +101,12 @@ export const RecordBoardColumnHeader = () => { }); const recordIndexAggregateDisplayValueForGroupValue = - useRecoilComponentFamilyValue( + useRecoilComponentFamilyValueV2( recordIndexAggregateDisplayValueForGroupValueComponentFamilyState, { groupValue: columnDefinition?.value ?? '' }, ); - const recordIndexAggregateDisplayLabel = useRecoilComponentValue( + const recordIndexAggregateDisplayLabel = useRecoilComponentValueV2( recordIndexAggregateDisplayLabelComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx index eb9b13f30f..ea5334a7e6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent.tsx @@ -9,7 +9,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate'; import { isDefined } from 'twenty-shared/utils'; import { @@ -35,19 +35,19 @@ export const RecordBoardColumnHeaderAggregateDropdownFieldsContent = () => { const { getIcon } = useIcons(); - const aggregateOperation = useRecoilComponentValue( + const aggregateOperation = useRecoilComponentValueV2( aggregateOperationComponentState, ); - const availableFieldsIdsForAggregateOperation = useRecoilComponentValue( + const availableFieldsIdsForAggregateOperation = useRecoilComponentValueV2( availableFieldIdsForAggregateOperationComponentState, ); - const recordIndexGroupAggregateOperation = useRecoilComponentValue( + const recordIndexGroupAggregateOperation = useRecoilComponentValueV2( recordIndexGroupAggregateOperationComponentState, ); - const recordIndexGroupAggregateFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupAggregateFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupAggregateFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx index 6f2f2f0b53..13dd1f496a 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownOptionsContent.tsx @@ -15,8 +15,8 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate'; import isEmpty from 'lodash.isempty'; import { IconCheck, IconChevronLeft } from 'twenty-ui/display'; @@ -35,17 +35,17 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({ }, ); - const setAggregateOperation = useSetRecoilComponentState( + const setAggregateOperation = useSetRecoilComponentStateV2( aggregateOperationComponentState, ); - const setAvailableFieldsForAggregateOperation = useSetRecoilComponentState( + const setAvailableFieldsForAggregateOperation = useSetRecoilComponentStateV2( availableFieldIdsForAggregateOperationComponentState, ); const { updateViewAggregate } = useUpdateViewAggregate(); - const recordIndexGroupAggregateOperation = useRecoilComponentValue( + const recordIndexGroupAggregateOperation = useRecoilComponentValueV2( recordIndexGroupAggregateOperationComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx index 230f45f80c..a2853b6041 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx @@ -3,8 +3,8 @@ import { RecordBoardColumnContext } from '@/object-record/record-board/record-bo import { useShouldHideRecordGroup } from '@/object-record/record-group/hooks/useShouldHideRecordGroup'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { isDefined } from 'twenty-shared/utils'; type RecordBoardColumnHeaderWrapperProps = { @@ -16,11 +16,12 @@ export const RecordBoardColumnHeaderWrapper = ({ columnId, columnIndex, }: RecordBoardColumnHeaderWrapperProps) => { - const recordGroupDefinition = useRecoilValue( - recordGroupDefinitionFamilyState(columnId), + const recordGroupDefinition = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + columnId, ); - const recordIdsByGroup = useRecoilComponentFamilyValue( + const recordIdsByGroup = useRecoilComponentFamilyValueV2( recordIndexRecordIdsByGroupComponentFamilyState, columnId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx index 8349592710..cf85d7c5a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx @@ -3,7 +3,7 @@ import { RecordBoardContext } from '@/object-record/record-board/contexts/Record import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -35,7 +35,7 @@ export const RecordBoardColumnNewRecordButton = () => { const { columnDefinition } = useContext(RecordBoardColumnContext); - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/aggregateOperationComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/aggregateOperationComponentState.ts index 99c438fdd7..2e7dd5e7d3 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/aggregateOperationComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/aggregateOperationComponentState.ts @@ -1,9 +1,9 @@ import { RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext } from '@/object-record/record-board/contexts/RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const aggregateOperationComponentState = - createComponentState({ + createComponentStateV2({ key: 'aggregateOperationComponentFamilyState', defaultValue: null, componentInstanceContext: diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState.ts index ddcbd9553b..0cef6b6732 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext } from '@/object-record/record-board/contexts/RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const availableFieldIdsForAggregateOperationComponentState = - createComponentState({ + createComponentStateV2({ key: 'availableFieldIdsForAggregateOperationComponentFamilyState', defaultValue: [], componentInstanceContext: diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/activeRecordBoardCardIndexesComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/activeRecordBoardCardIndexesComponentState.ts index 9b3fe17ce0..086193aa27 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/activeRecordBoardCardIndexesComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/activeRecordBoardCardIndexesComponentState.ts @@ -1,9 +1,9 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { type BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const activeRecordBoardCardIndexesComponentState = - createComponentState({ + createComponentStateV2({ key: 'activeRecordBoardCardIndexesComponentState', defaultValue: null, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState.ts index a876ef1164..6861dd578d 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState.ts @@ -1,9 +1,9 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { type BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const focusedRecordBoardCardIndexesComponentState = - createComponentState({ + createComponentStateV2({ key: 'focusedRecordBoardCardIndexesComponentState', defaultValue: null, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardActiveComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardActiveComponentFamilyState.ts index 996cb98c5f..5781a75ee0 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardActiveComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardActiveComponentFamilyState.ts @@ -1,9 +1,9 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { type BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const isRecordBoardCardActiveComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordBoardCardActiveComponentFamilyState', defaultValue: false, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState.ts index e430aa2d9f..005a12e7a6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordBoardCardFocusActiveComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordBoardCardFocusActiveComponentState', defaultValue: false, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState.ts index d268d56b4e..116ace6d4c 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState.ts @@ -1,9 +1,9 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { type BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const isRecordBoardCardFocusedComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordBoardCardFocusedComponentFamilyState', defaultValue: false, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState.ts index 24a211c9e3..873a22707b 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState.ts @@ -1,8 +1,8 @@ +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; export const isRecordBoardCardSelectedComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordBoardCardSelectedComponentFamilyState', defaultValue: false, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState.ts index 5c10720c31..b419a397bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState.ts @@ -1,10 +1,8 @@ import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { atomFamily } from 'recoil'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const isRecordBoardFetchingRecordsByColumnFamilyState = atomFamily< - boolean, - RecordGroupDefinition['id'] ->({ - key: 'isRecordBoardFetchingRecordsByColumnFamilyState', - default: false, -}); +export const isRecordBoardFetchingRecordsByColumnFamilyState = + createFamilyStateV2({ + key: 'isRecordBoardFetchingRecordsByColumnFamilyState', + defaultValue: false, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordBoardQueryIdentifierComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordBoardQueryIdentifierComponentState.ts index 26c522751c..8f5e32a320 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordBoardQueryIdentifierComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordBoardQueryIdentifierComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const lastRecordBoardQueryIdentifierComponentState = - createComponentState({ + createComponentStateV2({ key: 'lastRecordBoardQueryIdentifierComponentState', componentInstanceContext: RecordBoardComponentInstanceContext, defaultValue: '', diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts index d9d23d6c87..09eed15cd5 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts @@ -1,7 +1,9 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const lastRecordGroupIdsComponentState = createComponentState({ +export const lastRecordGroupIdsComponentState = createComponentStateV2< + string[] +>({ key: 'lastRecordGroupIdsComponentState', componentInstanceContext: RecordBoardComponentInstanceContext, defaultValue: [], diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState.ts index b2c631f7ef..d171b787a6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordBoardCurrentGroupByQueryOffsetComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordBoardCurrentGroupByQueryOffsetComponentState', defaultValue: 0, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardIsFetchingMoreComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardIsFetchingMoreComponentState.ts index 415f080c25..a88024f359 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardIsFetchingMoreComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardIsFetchingMoreComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordBoardIsFetchingMoreComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordBoardIsFetchingMoreComponentState', defaultValue: false, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreComponentState.ts index df2dbf3c55..e76fff4af0 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreComponentState.ts @@ -1,8 +1,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordBoardShouldFetchMoreComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordBoardShouldFetchMoreComponentState', defaultValue: false, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts index 996618ef30..f0356ae6ac 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const recordBoardShouldFetchMoreInColumnComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'recordBoardShouldFetchMoreInColumnComponentFamilyState', defaultValue: true, componentInstanceContext: RecordBoardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/selectors/allCardsSelectedStatusComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-board/states/selectors/allCardsSelectedStatusComponentSelector.ts index 6d802878ec..7723e3cc62 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/selectors/allCardsSelectedStatusComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/selectors/allCardsSelectedStatusComponentSelector.ts @@ -1,26 +1,24 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; import { allRecordIdsOfAllRecordGroupsComponentSelector } from '@/object-record/record-index/states/selectors/allRecordIdsOfAllRecordGroupsComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { type AllRowsSelectedStatus } from '@/object-record/record-table/types/AllRowSelectedStatus'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; export const allCardsSelectedStatusComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'allCardsSelectedStatusComponentSelector', componentInstanceContext: RecordBoardComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { const allRecordIds = get( - allRecordIdsOfAllRecordGroupsComponentSelector.selectorFamily({ - instanceId, - }), + allRecordIdsOfAllRecordGroupsComponentSelector, + { instanceId }, ); const selectedRecordIds = get( - recordBoardSelectedRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), + recordBoardSelectedRecordIdsComponentSelector, + { instanceId }, ); const numberOfSelectedCards = selectedRecordIds.length; diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector.ts index 2779cf6fff..b9287b3eea 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector.ts @@ -1,31 +1,25 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const recordBoardSelectedRecordIdsComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'recordBoardSelectedRecordIdsSelector', componentInstanceContext: RecordBoardComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - // TODO: This selector use a context different from the one used in the snippet - // its working for now as the instanceId is the same but we should change this - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); return allRecordIds.filter( (recordId) => - get( - isRecordBoardCardSelectedComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordId, - }), - ) === true, + get(isRecordBoardCardSelectedComponentFamilyState, { + instanceId, + familyKey: recordId, + }) === true, ); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarAddNew.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarAddNew.tsx index 7f238025b9..63fb834b93 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarAddNew.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarAddNew.tsx @@ -5,10 +5,10 @@ import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/r import { recordIndexCalendarFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { type Temporal } from 'temporal-polyfill'; import { IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; @@ -40,11 +40,11 @@ export const RecordCalendarAddNew = ({ const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords; - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, ); - const recordIndexCalendarFieldMetadataId = useRecoilValue( + const recordIndexCalendarFieldMetadataId = useRecoilValueV2( recordIndexCalendarFieldMetadataIdState, ); @@ -60,10 +60,10 @@ export const RecordCalendarAddNew = ({ : false; if ( - hasAnySoftDeleteFilterOnView || - !hasObjectUpdatePermissions || - !calendarFieldMetadataItem || - isCalendarFieldReadOnly + hasAnySoftDeleteFilterOnView === true || + hasObjectUpdatePermissions === false || + calendarFieldMetadataItem === undefined || + isCalendarFieldReadOnly === true ) { return null; } diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarSSESubscribeEffect.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarSSESubscribeEffect.tsx index 61af1e42d0..5e624474a9 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarSSESubscribeEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarSSESubscribeEffect.tsx @@ -5,7 +5,7 @@ import { RecordCalendarComponentInstanceContext } from '@/object-record/record-c import { recordCalendarSelectedDateComponentState } from '@/object-record/record-calendar/states/recordCalendarSelectedDateComponentState'; import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type RecordGqlOperationOrderBy } from 'twenty-shared/types'; export const RecordCalendarSSESubscribeEffect = () => { @@ -13,7 +13,7 @@ export const RecordCalendarSSESubscribeEffect = () => { RecordCalendarComponentInstanceContext, ); const { objectMetadataItem } = useRecordCalendarContextOrThrow(); - const recordCalendarSelectedDate = useRecoilComponentValue( + const recordCalendarSelectedDate = useRecoilComponentValueV2( recordCalendarSelectedDateComponentState, ); const { dateRangeFilter } = useRecordCalendarQueryDateRangeFilter( diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarTopBar.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarTopBar.tsx index 01b58b1fb7..6f62665fc4 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarTopBar.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordCalendarTopBar.tsx @@ -8,7 +8,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { format } from 'date-fns'; @@ -52,7 +52,7 @@ export const RecordCalendarTopBar = () => { ); const [recordCalendarSelectedDate, setRecordCalendarSelectedDate] = - useRecoilComponentState(recordCalendarSelectedDateComponentState); + useRecoilComponentStateV2(recordCalendarSelectedDateComponentState); const datePickerDropdownId = `record-calendar-date-picker-${recordCalendarId}`; const { closeDropdown } = useCloseDropdown(); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarDataLoaderEffect.tsx index 91cf339577..d2d0142765 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarDataLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarDataLoaderEffect.tsx @@ -7,8 +7,9 @@ import { recordCalendarSelectedDateComponentState } from '@/object-record/record import { recordCalendarSelectedRecordIdsComponentSelector } from '@/object-record/record-calendar/states/selectors/recordCalendarSelectedRecordIdsComponentSelector'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; export const RecordIndexCalendarDataLoaderEffect = () => { @@ -16,31 +17,35 @@ export const RecordIndexCalendarDataLoaderEffect = () => { RecordCalendarComponentInstanceContext, ); - const selectedRecordIds = useRecoilComponentValue( + const selectedRecordIds = useRecoilComponentSelectorValueV2( recordCalendarSelectedRecordIdsComponentSelector, recordCalendarId, ); - const recordCalendarSelectedDate = useRecoilComponentValue( + const recordCalendarSelectedDate = useRecoilComponentValueV2( recordCalendarSelectedDateComponentState, + recordCalendarId, ); const { upsertRecordsInStore } = useUpsertRecordsInStore(); - const setContextStoreTargetedRecords = useSetRecoilComponentState( + const setContextStoreTargetedRecords = useSetRecoilComponentStateV2( contextStoreTargetedRecordsRuleComponentState, + recordCalendarId, ); - const setRecordCalendarRecordIds = useSetRecoilComponentState( + const setRecordCalendarRecordIds = useSetRecoilComponentStateV2( recordCalendarRecordIdsComponentState, + recordCalendarId, ); const { records } = useRecordCalendarGroupByRecords( recordCalendarSelectedDate, ); - const hasInitializedRecordCalendarSelectedDate = useRecoilComponentValue( + const hasInitializedRecordCalendarSelectedDate = useRecoilComponentValueV2( hasInitializedRecordCalendarSelectedDateComponentState, + recordCalendarId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarSelectedDateInitEffect.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarSelectedDateInitEffect.tsx index 6f0d012489..a75b7cbd38 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarSelectedDateInitEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/components/RecordIndexCalendarSelectedDateInitEffect.tsx @@ -1,19 +1,19 @@ import { hasInitializedRecordCalendarSelectedDateComponentState } from '@/object-record/record-calendar/states/hasInitializedRecordCalendarSelectedDateComponentState'; import { recordCalendarSelectedDateComponentState } from '@/object-record/record-calendar/states/recordCalendarSelectedDateComponentState'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useEffect } from 'react'; import { Temporal } from 'temporal-polyfill'; export const RecordIndexCalendarSelectedDateInitEffect = () => { - const [, setRecordCalendarSelectedDate] = useRecoilComponentState( + const [, setRecordCalendarSelectedDate] = useRecoilComponentStateV2( recordCalendarSelectedDateComponentState, ); const [ hasInitializedRecordCalendarSelectedDate, setHasInitializedRecordCalendarSelectedDate, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( hasInitializedRecordCalendarSelectedDateComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/hooks/useRecordCalendarGroupByRecords.ts b/packages/twenty-front/src/modules/object-record/record-calendar/hooks/useRecordCalendarGroupByRecords.ts index 46b208de1a..3cba96e7d1 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/hooks/useRecordCalendarGroupByRecords.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/hooks/useRecordCalendarGroupByRecords.ts @@ -10,8 +10,8 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { buildGroupByFieldObject } from '@/page-layout/widgets/graph/utils/buildGroupByFieldObject'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; import { useQuery } from '@apollo/client'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; import { type Temporal } from 'temporal-polyfill'; import { ObjectRecordGroupByDateGranularity, @@ -26,7 +26,7 @@ export const useRecordCalendarGroupByRecords = ( const { userTimezone } = useUserTimezone(); - const recordIndexCalendarFieldMetadataId = useRecoilValue( + const recordIndexCalendarFieldMetadataId = useRecoilValueV2( recordIndexCalendarFieldMetadataIdState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonth.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonth.tsx index 46798c9743..81b0a18411 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonth.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonth.tsx @@ -6,7 +6,7 @@ import { recordCalendarSelectedDateComponentState } from '@/object-record/record import { useEndRecordDrag } from '@/object-record/record-drag/hooks/useEndRecordDrag'; import { useProcessCalendarCardDrop } from '@/object-record/record-drag/hooks/useProcessCalendarCardDrop'; import { useStartRecordDrag } from '@/object-record/record-drag/hooks/useStartRecordDrag'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { DragDropContext, @@ -23,7 +23,7 @@ const StyledContainer = styled.div` `; export const RecordCalendarMonth = () => { - const recordCalendarSelectedDate = useRecoilComponentValue( + const recordCalendarSelectedDate = useRecoilComponentValueV2( recordCalendarSelectedDateComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonthBodyDay.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonthBodyDay.tsx index 5f6276f925..4c81459c5d 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonthBodyDay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/month/components/RecordCalendarMonthBodyDay.tsx @@ -2,8 +2,8 @@ import { RecordCalendarCardDraggableContainer } from '@/object-record/record-cal import { recordCalendarSelectedDateComponentState } from '@/object-record/record-calendar/states/recordCalendarSelectedDateComponentState'; import { calendarDayRecordIdsComponentFamilySelector } from '@/object-record/record-calendar/states/selectors/calendarDayRecordsComponentFamilySelector'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { Droppable } from '@hello-pangea/dnd'; @@ -108,13 +108,13 @@ export const RecordCalendarMonthBodyDay = ({ }: RecordCalendarMonthBodyDayProps) => { const { userTimezone } = useUserTimezone(); - const recordCalendarSelectedDate = useRecoilComponentValue( + const recordCalendarSelectedDate = useRecoilComponentValueV2( recordCalendarSelectedDateComponentState, ); const dayKey = day.toString(); - const recordIds = useRecoilComponentFamilyValue( + const recordIds = useRecoilComponentFamilySelectorValueV2( calendarDayRecordIdsComponentFamilySelector, { day: day, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/month/components/__stories__/RecordCalendarMonth.stories.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/month/components/__stories__/RecordCalendarMonth.stories.tsx index 24e8cec3c1..0b667509dc 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/month/components/__stories__/RecordCalendarMonth.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/month/components/__stories__/RecordCalendarMonth.stories.tsx @@ -1,4 +1,5 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; +import { useEffect, useMemo, useState } from 'react'; import { type TaskGroups } from '@/activities/tasks/components/TaskGroups'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; @@ -7,7 +8,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; @@ -38,7 +39,7 @@ const meta: Meta = { )!; const instanceId = companyObjectMetadataItem.id; - const setCurrentRecordFields = useSetRecoilComponentState( + const setCurrentRecordFields = useSetRecoilComponentStateV2( currentRecordFieldsComponentState, instanceId, ); @@ -47,27 +48,40 @@ const meta: Meta = { const mockCoreView = mockedCoreViewsData[0]; - setCoreViews([mockCoreView]); - - const setCurrentViewId = useSetRecoilComponentState( + const setCurrentViewId = useSetRecoilComponentStateV2( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - setCurrentViewId(mockCoreView.id); - - const columns = companyObjectMetadataItem.fields.map( - (fieldMetadataItem, index) => - ({ - id: fieldMetadataItem.id, - fieldMetadataItemId: fieldMetadataItem.id, - isVisible: true, - position: index, - size: 100, - }) satisfies RecordField, + const columns = useMemo( + () => + companyObjectMetadataItem.fields.map( + (fieldMetadataItem, index) => + ({ + id: fieldMetadataItem.id, + fieldMetadataItemId: fieldMetadataItem.id, + isVisible: true, + position: index, + size: 100, + }) satisfies RecordField, + ), + [companyObjectMetadataItem.fields], ); - setCurrentRecordFields(columns); + const [isLoaded, setIsLoaded] = useState(false); + + useEffect(() => { + setCoreViews([mockCoreView]); + setCurrentViewId(mockCoreView.id); + setCurrentRecordFields(columns); + setIsLoaded(true); + }, [ + setCoreViews, + setCurrentViewId, + setCurrentRecordFields, + mockCoreView, + columns, + ]); const { fieldDefinitionByFieldMetadataItemId, @@ -79,6 +93,10 @@ const meta: Meta = { instanceId, ); + if (!isLoaded) { + return <>; + } + return ( { const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); if (!currentWorkspaceMember) { throw new Error('Current workspace member not found'); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx index ce074ccb89..d469ad8874 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx @@ -7,7 +7,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { t } from '@lingui/core/macro'; import { type Temporal } from 'temporal-polyfill'; @@ -25,7 +25,8 @@ const DATE_RANGE_FILTER_BEFORE_ID = 'DATE_RANGE_FILTER_BEFORE_ID'; export const useRecordCalendarQueryDateRangeFilter = ( selectedDate: Temporal.PlainDate, ) => { - const { objectMetadataItem } = useRecordCalendarContextOrThrow(); + const { objectMetadataItem, viewBarInstanceId } = + useRecordCalendarContextOrThrow(); const { firstDayOfFirstWeek, lastDayOfLastWeek } = useRecordCalendarMonthDaysRange(selectedDate); @@ -33,18 +34,21 @@ export const useRecordCalendarQueryDateRangeFilter = ( const { currentView } = useGetCurrentViewOnly(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + viewBarInstanceId, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + viewBarInstanceId, ); const { filterValueDependencies } = useFilterValueDependencies(); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, + viewBarInstanceId, ); if ( diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellEditModePortal.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellEditModePortal.tsx index fe97cef244..b8675b9cf8 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellEditModePortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellEditModePortal.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar/contexts/RecordCalendarContext'; import { RecordCalendarCardInputContextProvider } from '@/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardInputContextProvider'; @@ -19,7 +19,7 @@ export const RecordCalendarCardCellEditModePortal = ({ }: RecordCalendarCardCellEditModePortalProps) => { const { objectMetadataItem } = useRecordCalendarContextOrThrow(); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordCalendarCardEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortal.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortal.tsx index 0caf0733a9..322cd50283 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortal.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar/contexts/RecordCalendarContext'; import { RecordCalendarCardCellHoveredPortalContent } from '@/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortalContent'; @@ -18,7 +18,7 @@ export const RecordCalendarCardCellHoveredPortal = ({ }: RecordCalendarCardCellHoveredPortalProps) => { const { objectMetadataItem } = useRecordCalendarContextOrThrow(); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordCalendarCardHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortalContent.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortalContent.tsx index 37d75a06b9..051f192135 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortalContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortalContent.tsx @@ -10,8 +10,8 @@ import { RecordInlineCellDisplayMode } from '@/object-record/record-inline-cell/ import { RecordInlineCellHoveredPortalContent } from '@/object-record/record-inline-cell/components/RecordInlineCellHoveredPortalContent'; import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext } from 'react'; export const RecordCalendarCardCellHoveredPortalContent = () => { @@ -32,9 +32,9 @@ export const RecordCalendarCardCellHoveredPortalContent = () => { !isRecordFieldReadOnly && !editModeContentOnly; const [recordCalendarCardHoverPosition, setRecordCalendarCardHoverPosition] = - useRecoilComponentState(recordCalendarCardHoverPositionComponentState); + useRecoilComponentStateV2(recordCalendarCardHoverPositionComponentState); - const setRecordCalendarCardEditModePosition = useSetRecoilComponentState( + const setRecordCalendarCardEditModePosition = useSetRecoilComponentStateV2( recordCalendarCardEditModePositionComponentState, ); const { openFieldInput } = useOpenFieldInputEditMode(); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardInputContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardInputContextProvider.tsx index 300bc31dca..d375c92713 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardInputContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardInputContextProvider.tsx @@ -10,7 +10,7 @@ import { import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { currentFocusIdSelector } from '@/ui/utilities/focus/states/currentFocusIdSelector'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useStore } from 'jotai'; import { useCallback } from 'react'; @@ -23,7 +23,7 @@ export const RecordCalendarCardInputContextProvider = ({ }: RecordCalendarCardInputContextProviderProps) => { const store = useStore(); const { closeInlineCell } = useInlineCell(); - const setRecordCalendarCardEditModePosition = useSetRecoilComponentState( + const setRecordCalendarCardEditModePosition = useSetRecoilComponentStateV2( recordCalendarCardEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCard.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCard.tsx index 0555744bb4..d092fcc28b 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCard.tsx @@ -14,8 +14,8 @@ import { RecordCard } from '@/object-record/record-card/components/RecordCard'; import { RecordFieldsScopeContextProvider } from '@/object-record/record-field-list/contexts/RecordFieldsScopeContext'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import styled from '@emotion/styled'; import { AnimatedEaseInOut } from 'twenty-ui/utilities'; @@ -37,7 +37,7 @@ export const RecordCalendarCard = ({ recordId }: RecordCalendarCardProps) => { const isCompactModeActive = currentView?.isCompact ?? false; const [isCurrentCardSelected, setIsCurrentCardSelected] = - useRecoilComponentFamilyState( + useRecoilComponentFamilyStateV2( isRecordCalendarCardSelectedComponentFamilyState, recordId, ); @@ -51,7 +51,7 @@ export const RecordCalendarCard = ({ recordId }: RecordCalendarCardProps) => { const actionMenuDropdownId = getActionMenuDropdownIdFromActionMenuId(actionMenuId); - const setActionMenuDropdownPosition = useSetRecoilComponentState( + const setActionMenuDropdownPosition = useSetRecoilComponentStateV2( recordIndexActionMenuDropdownPositionComponentState, actionMenuDropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx index 5bd85d27e0..daf1ac26d7 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx @@ -15,8 +15,8 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-fiel import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; const StyledRecordCardBodyContainer = styled(RecordCardBodyContainer)` @@ -54,7 +54,7 @@ export const RecordCalendarCardBody = ({ fieldDefinitionByFieldMetadataItemId, } = useRecordIndexContextOrThrow(); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); @@ -63,7 +63,7 @@ export const RecordCalendarCardBody = ({ recordField.fieldMetadataItemId !== labelIdentifierFieldMetadataItem?.id, ); - const setRecordCalendarCardHoverPosition = useSetRecoilComponentState( + const setRecordCalendarCardHoverPosition = useSetRecoilComponentStateV2( recordCalendarCardHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardDraggableContainer.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardDraggableContainer.tsx index 1575c4e37a..12765cc683 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardDraggableContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardDraggableContainer.tsx @@ -8,7 +8,7 @@ import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar import { RecordCalendarCard } from '@/object-record/record-calendar/record-calendar-card/components/RecordCalendarCard'; import { RecordCalendarCardComponentInstanceContext } from '@/object-record/record-calendar/record-calendar-card/states/contexts/RecordCalendarCardComponentInstanceContext'; import { recordIndexCalendarFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; const StyledDraggableContainer = styled.div` @@ -36,7 +36,7 @@ export const RecordCalendarCardDraggableContainer = ({ objectMetadataItem.id, ); - const recordIndexCalendarFieldMetadataId = useRecoilValue( + const recordIndexCalendarFieldMetadataId = useRecoilValueV2( recordIndexCalendarFieldMetadataIdState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx index 9f80132266..d0e45e46f9 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx @@ -5,11 +5,11 @@ import { RecordCardHeaderContainer } from '@/object-record/record-card/component import { isDraggingRecordComponentState } from '@/object-record/record-drag/states/isDraggingRecordComponentState'; import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { ChipVariant } from 'twenty-ui/components'; import { Checkbox, CheckboxVariant } from 'twenty-ui/input'; @@ -38,19 +38,19 @@ export const RecordCalendarCardHeader = ({ recordId, }: RecordCalendarCardHeaderProps) => { const { objectMetadataItem } = useRecordCalendarContextOrThrow(); - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const { openRecordFromIndexView } = useOpenRecordFromIndexView(); const { currentView } = useGetCurrentViewOnly(); const isCompactModeActive = currentView?.isCompact ?? false; - const isDraggingRecord = useRecoilComponentValue( + const isDraggingRecord = useRecoilComponentValueV2( isDraggingRecordComponentState, ); const [isCurrentCardSelected, setIsCurrentCardSelected] = - useRecoilComponentFamilyState( + useRecoilComponentFamilyStateV2( isRecordCalendarCardSelectedComponentFamilyState, recordId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/hooks/useRecordCalendarCardMetadataFromPosition.ts b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/hooks/useRecordCalendarCardMetadataFromPosition.ts index 4242dc2675..9d07cdb83c 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/hooks/useRecordCalendarCardMetadataFromPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/hooks/useRecordCalendarCardMetadataFromPosition.ts @@ -3,21 +3,22 @@ import { recordCalendarCardEditModePositionComponentState } from '@/object-recor import { recordCalendarCardHoverPositionComponentState } from '@/object-record/record-calendar/record-calendar-card/states/recordCalendarCardHoverPositionComponentState'; import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useRecordCalendarCardMetadataFromPosition = () => { const { objectMetadataItem } = useRecordCalendarContextOrThrow(); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordCalendarCardHoverPositionComponentState, ); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordCalendarCardEditModePositionComponentState, ); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState.ts index 1b13cce073..0ac3958216 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState.ts @@ -1,8 +1,8 @@ -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext'; export const isRecordCalendarCardSelectedComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordCalendarCardSelectedComponentFamilyState', defaultValue: false, componentInstanceContext: RecordCalendarComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardEditModePositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardEditModePositionComponentState.ts index bf43d7a97a..15a0a5a09d 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardEditModePositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardEditModePositionComponentState.ts @@ -1,8 +1,8 @@ import { RecordCalendarCardComponentInstanceContext } from '@/object-record/record-calendar/record-calendar-card/states/contexts/RecordCalendarCardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordCalendarCardEditModePositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordCalendarCardEditModePositionComponentState', defaultValue: null, componentInstanceContext: RecordCalendarCardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardHoverPositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardHoverPositionComponentState.ts index 45313e219a..91d864085a 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardHoverPositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/states/recordCalendarCardHoverPositionComponentState.ts @@ -1,8 +1,8 @@ import { RecordCalendarCardComponentInstanceContext } from '@/object-record/record-calendar/record-calendar-card/states/contexts/RecordCalendarCardComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordCalendarCardHoverPositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordCalendarCardHoverPositionComponentState', defaultValue: null, componentInstanceContext: RecordCalendarCardComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/states/hasInitializedRecordCalendarSelectedDateComponentState.ts b/packages/twenty-front/src/modules/object-record/record-calendar/states/hasInitializedRecordCalendarSelectedDateComponentState.ts index d0a65c1bc9..ef72476cfb 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/states/hasInitializedRecordCalendarSelectedDateComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/states/hasInitializedRecordCalendarSelectedDateComponentState.ts @@ -1,8 +1,8 @@ import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const hasInitializedRecordCalendarSelectedDateComponentState = - createComponentState({ + createComponentStateV2({ key: 'hasInitializedRecordCalendarSelectedDateComponentState', defaultValue: false, componentInstanceContext: RecordCalendarComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarRecordIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarRecordIdsComponentState.ts index d01469a59e..73d54c3413 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarRecordIdsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarRecordIdsComponentState.ts @@ -1,7 +1,7 @@ import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const recordCalendarRecordIdsComponentState = createComponentState< +export const recordCalendarRecordIdsComponentState = createComponentStateV2< string[] >({ key: 'recordCalendarRecordIdsComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarSelectedDateComponentState.ts b/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarSelectedDateComponentState.ts index 0ce34c030d..6d0b894c70 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarSelectedDateComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/states/recordCalendarSelectedDateComponentState.ts @@ -1,9 +1,9 @@ import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { Temporal } from 'temporal-polyfill'; export const recordCalendarSelectedDateComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordCalendarSelectedDateComponentState', defaultValue: Temporal.Now.plainDateISO(), componentInstanceContext: RecordCalendarComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/calendarDayRecordsComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/calendarDayRecordsComponentFamilySelector.ts index aa6b3d02c3..7b717c55d8 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/calendarDayRecordsComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/calendarDayRecordsComponentFamilySelector.ts @@ -6,7 +6,7 @@ import { RecordCalendarComponentInstanceContext } from '@/object-record/record-c import { recordCalendarRecordIdsComponentState } from '@/object-record/record-calendar/states/recordCalendarRecordIdsComponentState'; import { recordIndexCalendarFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; import { isNonEmptyString } from '@sniptt/guards'; import { Temporal } from 'temporal-polyfill'; @@ -14,7 +14,7 @@ import { isDefined, isSamePlainDate } from 'twenty-shared/utils'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const calendarDayRecordIdsComponentFamilySelector = - createComponentFamilySelector< + createComponentFamilySelectorV2< string[], { day: Temporal.PlainDate; timeZone: string } >({ @@ -23,8 +23,8 @@ export const calendarDayRecordIdsComponentFamilySelector = get: ({ instanceId, familyKey: { day, timeZone } }) => ({ get }) => { - const calendarFieldMetadataId = get( - recordIndexCalendarFieldMetadataIdState, + const calendarFieldMetadataId = jotaiStore.get( + recordIndexCalendarFieldMetadataIdState.atom, ); const objectMetadataItems = jotaiStore.get( @@ -51,14 +51,14 @@ export const calendarDayRecordIdsComponentFamilySelector = return []; } - const allRecordIds = get( - recordCalendarRecordIdsComponentState.atomFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordCalendarRecordIdsComponentState, { + instanceId, + }); const recordIds = allRecordIds.filter((recordId) => { - const record = get(recordStoreFamilyState(recordId)); + const record = jotaiStore.get( + recordStoreFamilyState.atomFamily(recordId), + ); const recordDate = record?.[fieldMetadataItem.name]; if (!isNonEmptyString(recordDate)) { @@ -80,8 +80,12 @@ export const calendarDayRecordIdsComponentFamilySelector = hasObjectMetadataItemPositionField(objectMetadataItem) ) { return recordIds.sort((a, b) => { - const recordA = get(recordStoreFamilyState(a)); - const recordB = get(recordStoreFamilyState(b)); + const recordA = jotaiStore.get( + recordStoreFamilyState.atomFamily(a), + ); + const recordB = jotaiStore.get( + recordStoreFamilyState.atomFamily(b), + ); const positionA = recordA?.position; const positionB = recordB?.position; diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/recordCalendarSelectedRecordIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/recordCalendarSelectedRecordIdsComponentSelector.ts index eeb00bf83c..cef408bb83 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/recordCalendarSelectedRecordIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/recordCalendarSelectedRecordIdsComponentSelector.ts @@ -1,29 +1,25 @@ -import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; import { isRecordCalendarCardSelectedComponentFamilyState } from '@/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState'; +import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext'; export const recordCalendarSelectedRecordIdsComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'recordCalendarSelectedRecordIdsSelector', componentInstanceContext: RecordCalendarComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); return allRecordIds.filter( - (recordId) => - get( - isRecordCalendarCardSelectedComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordId, - }), - ) === true, + (recordId: string) => + get(isRecordCalendarCardSelectedComponentFamilyState, { + instanceId, + familyKey: recordId, + }) === true, ); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/useRecordCalendarSelection.ts b/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/useRecordCalendarSelection.ts index 8c06145ccc..c56cdd493a 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/useRecordCalendarSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-calendar/states/selectors/useRecordCalendarSelection.ts @@ -1,11 +1,12 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; import { isRecordCalendarCardSelectedComponentFamilyState } from '@/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState'; import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext'; import { recordCalendarSelectedRecordIdsComponentSelector } from './recordCalendarSelectedRecordIdsComponentSelector'; @@ -17,44 +18,39 @@ export const useRecordCalendarSelection = (recordCalendarId?: string) => { ); const isRecordCalendarCardSelectedFamilyState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( isRecordCalendarCardSelectedComponentFamilyState, recordCalendarId, ); - const recordCalendarSelectedRecordIdsSelector = - useRecoilComponentCallbackState( + const recordCalendarSelectedRecordIdsAtom = + useRecoilComponentSelectorCallbackStateV2( recordCalendarSelectedRecordIdsComponentSelector, recordCalendarId, ); const { closeDropdown } = useCloseDropdown(); + const store = useStore(); const dropdownId = getActionMenuDropdownIdFromActionMenuId( getActionMenuIdFromRecordIndexId(instanceIdFromProps), ); - const resetRecordSelection = useRecoilCallback( - ({ snapshot, set }) => - () => { - closeDropdown(dropdownId); + const resetRecordSelection = useCallback(() => { + closeDropdown(dropdownId); - const recordIds = getSnapshotValue( - snapshot, - recordCalendarSelectedRecordIdsSelector, - ); + const recordIds = store.get(recordCalendarSelectedRecordIdsAtom); - for (const recordId of recordIds) { - set(isRecordCalendarCardSelectedFamilyState(recordId), false); - } - }, - [ - closeDropdown, - dropdownId, - recordCalendarSelectedRecordIdsSelector, - isRecordCalendarCardSelectedFamilyState, - ], - ); + for (const recordId of recordIds) { + store.set(isRecordCalendarCardSelectedFamilyState(recordId), false); + } + }, [ + closeDropdown, + dropdownId, + recordCalendarSelectedRecordIdsAtom, + isRecordCalendarCardSelectedFamilyState, + store, + ]); return { resetRecordSelection, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useEndRecordDrag.test.tsx b/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useEndRecordDrag.test.tsx index eb1aeaff25..cff7e5d1a2 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useEndRecordDrag.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useEndRecordDrag.test.tsx @@ -6,7 +6,7 @@ import { draggedRecordIdsComponentState } from '@/object-record/record-drag/stat import { isMultiDragActiveComponentState } from '@/object-record/record-drag/states/isMultiDragActiveComponentState'; import { originalDragSelectionComponentState } from '@/object-record/record-drag/states/originalDragSelectionComponentState'; import { primaryDraggedRecordIdComponentState } from '@/object-record/record-drag/states/primaryDraggedRecordIdComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; describe('useEndRecordDrag', () => { @@ -16,17 +16,16 @@ describe('useEndRecordDrag', () => { const { result } = renderHook( () => { const [isMultiDragActive, setIsMultiDragActive] = - useRecoilComponentState(isMultiDragActiveComponentState); + useRecoilComponentStateV2(isMultiDragActiveComponentState); - const [draggedRecordIds, setDraggedRecordIds] = useRecoilComponentState( - draggedRecordIdsComponentState, - ); + const [draggedRecordIds, setDraggedRecordIds] = + useRecoilComponentStateV2(draggedRecordIdsComponentState); const [primaryDraggedRecordId, setPrimaryDraggedRecordId] = - useRecoilComponentState(primaryDraggedRecordIdComponentState); + useRecoilComponentStateV2(primaryDraggedRecordIdComponentState); const [originalSelection, setOriginalSelection] = - useRecoilComponentState(originalDragSelectionComponentState); + useRecoilComponentStateV2(originalDragSelectionComponentState); const { endRecordDrag } = useEndRecordDrag(); diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useStartRecordDrag.test.tsx b/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useStartRecordDrag.test.tsx index a2b1d1eb29..79b36aab49 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useStartRecordDrag.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/__tests__/useStartRecordDrag.test.tsx @@ -7,7 +7,7 @@ import { draggedRecordIdsComponentState } from '@/object-record/record-drag/stat import { isMultiDragActiveComponentState } from '@/object-record/record-drag/states/isMultiDragActiveComponentState'; import { originalDragSelectionComponentState } from '@/object-record/record-drag/states/originalDragSelectionComponentState'; import { primaryDraggedRecordIdComponentState } from '@/object-record/record-drag/states/primaryDraggedRecordIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; const createDragStart = (draggableId: string, index: number): DragStart => ({ @@ -26,16 +26,16 @@ describe('useStartRecordDrag', () => { it('should set single drag state when dragged record is not in selection', () => { const { result } = renderHook( () => { - const isMultiDragActive = useRecoilComponentValue( + const isMultiDragActive = useRecoilComponentValueV2( isMultiDragActiveComponentState, ); - const draggedRecordIds = useRecoilComponentValue( + const draggedRecordIds = useRecoilComponentValueV2( draggedRecordIdsComponentState, ); - const primaryDraggedRecordId = useRecoilComponentValue( + const primaryDraggedRecordId = useRecoilComponentValueV2( primaryDraggedRecordIdComponentState, ); - const originalSelection = useRecoilComponentValue( + const originalSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); @@ -68,16 +68,16 @@ describe('useStartRecordDrag', () => { it('should set single drag state when only one record is selected', () => { const { result } = renderHook( () => { - const isMultiDragActive = useRecoilComponentValue( + const isMultiDragActive = useRecoilComponentValueV2( isMultiDragActiveComponentState, ); - const draggedRecordIds = useRecoilComponentValue( + const draggedRecordIds = useRecoilComponentValueV2( draggedRecordIdsComponentState, ); - const primaryDraggedRecordId = useRecoilComponentValue( + const primaryDraggedRecordId = useRecoilComponentValueV2( primaryDraggedRecordIdComponentState, ); - const originalSelection = useRecoilComponentValue( + const originalSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); @@ -110,16 +110,16 @@ describe('useStartRecordDrag', () => { it('should set multi drag state when multiple records are selected', () => { const { result } = renderHook( () => { - const isMultiDragActive = useRecoilComponentValue( + const isMultiDragActive = useRecoilComponentValueV2( isMultiDragActiveComponentState, ); - const draggedRecordIds = useRecoilComponentValue( + const draggedRecordIds = useRecoilComponentValueV2( draggedRecordIdsComponentState, ); - const primaryDraggedRecordId = useRecoilComponentValue( + const primaryDraggedRecordId = useRecoilComponentValueV2( primaryDraggedRecordIdComponentState, ); - const originalSelection = useRecoilComponentValue( + const originalSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); @@ -160,16 +160,16 @@ describe('useStartRecordDrag', () => { it('should handle empty selection', () => { const { result } = renderHook( () => { - const isMultiDragActive = useRecoilComponentValue( + const isMultiDragActive = useRecoilComponentValueV2( isMultiDragActiveComponentState, ); - const draggedRecordIds = useRecoilComponentValue( + const draggedRecordIds = useRecoilComponentValueV2( draggedRecordIdsComponentState, ); - const primaryDraggedRecordId = useRecoilComponentValue( + const primaryDraggedRecordId = useRecoilComponentValueV2( primaryDraggedRecordIdComponentState, ); - const originalSelection = useRecoilComponentValue( + const originalSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); @@ -202,16 +202,16 @@ describe('useStartRecordDrag', () => { it('should set single drag state when dragged record is not in selection', () => { const { result } = renderHook( () => { - const isMultiDragActive = useRecoilComponentValue( + const isMultiDragActive = useRecoilComponentValueV2( isMultiDragActiveComponentState, ); - const draggedRecordIds = useRecoilComponentValue( + const draggedRecordIds = useRecoilComponentValueV2( draggedRecordIdsComponentState, ); - const primaryDraggedRecordId = useRecoilComponentValue( + const primaryDraggedRecordId = useRecoilComponentValueV2( primaryDraggedRecordIdComponentState, ); - const originalSelection = useRecoilComponentValue( + const originalSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); @@ -244,16 +244,16 @@ describe('useStartRecordDrag', () => { it('should set multi drag state when multiple records are selected', () => { const { result } = renderHook( () => { - const isMultiDragActive = useRecoilComponentValue( + const isMultiDragActive = useRecoilComponentValueV2( isMultiDragActiveComponentState, ); - const draggedRecordIds = useRecoilComponentValue( + const draggedRecordIds = useRecoilComponentValueV2( draggedRecordIdsComponentState, ); - const primaryDraggedRecordId = useRecoilComponentValue( + const primaryDraggedRecordId = useRecoilComponentValueV2( primaryDraggedRecordIdComponentState, ); - const originalSelection = useRecoilComponentValue( + const originalSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useEndRecordDrag.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useEndRecordDrag.ts index 710497921c..b537812b48 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useEndRecordDrag.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useEndRecordDrag.ts @@ -1,6 +1,8 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isMultiDragActiveComponentState } from '@/object-record/record-drag/states/isMultiDragActiveComponentState'; @@ -10,101 +12,95 @@ import { isRecordIdPrimaryDragMultipleComponentFamilyState } from '@/object-reco import { isRecordIdSecondaryDragMultipleComponentFamilyState } from '@/object-record/record-drag/states/isRecordIdSecondaryDragMultipleComponentFamilyState'; import { originalDragSelectionComponentState } from '@/object-record/record-drag/states/originalDragSelectionComponentState'; import { primaryDraggedRecordIdComponentState } from '@/object-record/record-drag/states/primaryDraggedRecordIdComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { isDefined } from 'twenty-shared/utils'; export const useEndRecordDrag = (contextStoreInstanceId?: string) => { - const isMultiDragActiveCallbackState = useRecoilComponentCallbackState( + const store = useStore(); + const isMultiDragActiveCallbackState = useRecoilComponentStateCallbackStateV2( isMultiDragActiveComponentState, contextStoreInstanceId, ); - const draggedRecordIdsCallbackState = useRecoilComponentCallbackState( + const draggedRecordIdsCallbackState = useRecoilComponentStateCallbackStateV2( draggedRecordIdsComponentState, contextStoreInstanceId, ); - const primaryDraggedRecordIdCallbackState = useRecoilComponentCallbackState( - primaryDraggedRecordIdComponentState, - contextStoreInstanceId, - ); + const primaryDraggedRecordIdCallbackState = + useRecoilComponentStateCallbackStateV2( + primaryDraggedRecordIdComponentState, + contextStoreInstanceId, + ); - const originalSelectionCallbackState = useRecoilComponentCallbackState( + const originalSelectionAtom = useRecoilComponentStateCallbackStateV2( originalDragSelectionComponentState, contextStoreInstanceId, ); const isRecordIdPrimaryDragMultipleCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( isRecordIdPrimaryDragMultipleComponentFamilyState, contextStoreInstanceId, ); const isRecordIdSecondaryDragMultipleCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( isRecordIdSecondaryDragMultipleComponentFamilyState, contextStoreInstanceId, ); - const isDraggingRecordCallbackState = useRecoilComponentCallbackState( + const isDraggingRecordAtom = useRecoilComponentStateCallbackStateV2( isDraggingRecordComponentState, contextStoreInstanceId, ); - const endRecordDrag = useRecoilCallback( - ({ snapshot, set }) => - () => { - set(isDraggingRecordCallbackState, false); + const endRecordDrag = useCallback(() => { + store.set(isDraggingRecordAtom, false); - const currentlyDraggedRecordIds = getSnapshotValue( - snapshot, - draggedRecordIdsCallbackState, - ); + const currentlyDraggedRecordIds = store.get(draggedRecordIdsCallbackState); - const primaryDraggedRecordId = getSnapshotValue( - snapshot, - primaryDraggedRecordIdCallbackState, - ); - - if (currentlyDraggedRecordIds.length > 0) { - const secondaryDraggedIds = currentlyDraggedRecordIds.filter( - (recordIdToFilter) => recordIdToFilter !== primaryDraggedRecordId, - ); - - for (const secondaryDraggedId of secondaryDraggedIds) { - set( - isRecordIdSecondaryDragMultipleCallbackState({ - recordId: secondaryDraggedId, - }), - false, - ); - } - } - - if (isDefined(primaryDraggedRecordId)) { - set( - isRecordIdPrimaryDragMultipleCallbackState({ - recordId: primaryDraggedRecordId, - }), - false, - ); - } - - set(isMultiDragActiveCallbackState, false); - set(draggedRecordIdsCallbackState, []); - set(primaryDraggedRecordIdCallbackState, null); - set(originalSelectionCallbackState, []); - }, - [ - isMultiDragActiveCallbackState, - draggedRecordIdsCallbackState, + const primaryDraggedRecordId = store.get( primaryDraggedRecordIdCallbackState, - originalSelectionCallbackState, - isRecordIdPrimaryDragMultipleCallbackState, - isRecordIdSecondaryDragMultipleCallbackState, - isDraggingRecordCallbackState, - ], - ); + ); + + if (currentlyDraggedRecordIds.length > 0) { + const secondaryDraggedIds = currentlyDraggedRecordIds.filter( + (recordIdToFilter) => recordIdToFilter !== primaryDraggedRecordId, + ); + + for (const secondaryDraggedId of secondaryDraggedIds) { + store.set( + isRecordIdSecondaryDragMultipleCallbackState({ + recordId: secondaryDraggedId, + }), + false, + ); + } + } + + if (isDefined(primaryDraggedRecordId)) { + store.set( + isRecordIdPrimaryDragMultipleCallbackState({ + recordId: primaryDraggedRecordId, + }), + false, + ); + } + + store.set(isMultiDragActiveCallbackState, false); + store.set(draggedRecordIdsCallbackState, []); + store.set(primaryDraggedRecordIdCallbackState, null); + store.set(originalSelectionAtom, []); + }, [ + store, + isMultiDragActiveCallbackState, + draggedRecordIdsCallbackState, + primaryDraggedRecordIdCallbackState, + originalSelectionAtom, + isRecordIdPrimaryDragMultipleCallbackState, + isRecordIdSecondaryDragMultipleCallbackState, + isDraggingRecordAtom, + ]); return { endRecordDrag }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessBoardCardDrop.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessBoardCardDrop.ts index 96a1fdb632..932a0bf400 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessBoardCardDrop.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessBoardCardDrop.ts @@ -1,44 +1,45 @@ import { type DropResult } from '@hello-pangea/dnd'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { processGroupDrop } from '@/object-record/record-drag/utils/processGroupDrop'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { useUpdateDroppedRecordOnBoard } from '@/object-record/record-drag/hooks/useUpdateDroppedRecordOnBoard'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useContext } from 'react'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; export const useProcessBoardCardDrop = () => { + const store = useStore(); const { selectFieldMetadataItem } = useContext(RecordBoardContext); const recordIndexRecordIdsByGroupCallbackFamilyState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); const { updateDroppedRecordOnBoard } = useUpdateDroppedRecordOnBoard(); - const processBoardCardDrop = useRecoilCallback( - ({ snapshot }) => - (boardCardDropResult: DropResult, selectedRecordIds: string[]) => { - if (!selectFieldMetadataItem) return; + const processBoardCardDrop = useCallback( + (boardCardDropResult: DropResult, selectedRecordIds: string[]) => { + if (!selectFieldMetadataItem) return; - processGroupDrop({ - groupDropResult: boardCardDropResult, - snapshot, - selectedRecordIds, - recordIdsByGroupFamilyState: - recordIndexRecordIdsByGroupCallbackFamilyState, - onUpdateRecord: ({ recordId, position }, targetRecordGroupValue) => { - updateDroppedRecordOnBoard( - { recordId, position }, - targetRecordGroupValue, - ); - }, - }); - }, + processGroupDrop({ + groupDropResult: boardCardDropResult, + store, + selectedRecordIds, + recordIdsByGroupFamilyState: + recordIndexRecordIdsByGroupCallbackFamilyState, + onUpdateRecord: ({ recordId, position }, targetRecordGroupValue) => { + updateDroppedRecordOnBoard( + { recordId, position }, + targetRecordGroupValue, + ); + }, + }); + }, [ + store, selectFieldMetadataItem, recordIndexRecordIdsByGroupCallbackFamilyState, updateDroppedRecordOnBoard, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessCalendarCardDrop.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessCalendarCardDrop.ts index b59859fc26..ecb57903ef 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessCalendarCardDrop.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessCalendarCardDrop.ts @@ -1,5 +1,6 @@ import { type DropResult } from '@hello-pangea/dnd'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar/contexts/RecordCalendarContext'; @@ -9,133 +10,136 @@ import { extractRecordPositions } from '@/object-record/record-drag/utils/extrac import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { computeNewPositionOfDraggedRecord } from '@/object-record/utils/computeNewPositionOfDraggedRecord'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentFamilySelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { Temporal } from 'temporal-polyfill'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const useProcessCalendarCardDrop = () => { + const store = useStore(); const { objectMetadataItem } = useRecordCalendarContextOrThrow(); const { currentView } = useGetCurrentViewOnly(); const { updateOneRecord } = useUpdateOneRecord(); const { userTimezone } = useUserTimezone(); - const calendarDayRecordIdsSelector = useRecoilComponentCallbackState( - calendarDayRecordIdsComponentFamilySelector, - ); + const calendarDayRecordIdsSelector = + useRecoilComponentFamilySelectorCallbackStateV2( + calendarDayRecordIdsComponentFamilySelector, + ); - const processCalendarCardDrop = useRecoilCallback( - ({ snapshot }) => - async (calendarCardDropResult: DropResult) => { - if ( - !calendarCardDropResult.destination || - !currentView?.calendarFieldMetadataId - ) - return; + const processCalendarCardDrop = useCallback( + async (calendarCardDropResult: DropResult) => { + if ( + !calendarCardDropResult.destination || + !currentView?.calendarFieldMetadataId + ) + return; - const { draggableId: recordId } = calendarCardDropResult; - const destinationDate = calendarCardDropResult.destination.droppableId; - const destinationIndex = calendarCardDropResult.destination.index; + const { draggableId: recordId } = calendarCardDropResult; + const destinationDate = calendarCardDropResult.destination.droppableId; + const destinationIndex = calendarCardDropResult.destination.index; - const destinationPlainDate = Temporal.PlainDate.from(destinationDate); + const destinationPlainDate = Temporal.PlainDate.from(destinationDate); - const record = snapshot - .getLoadable(recordStoreFamilyState(recordId)) - .getValue(); + const record = store.get(recordStoreFamilyState.atomFamily(recordId)) as + | Record + | null + | undefined; - if (!record) return; + if (!record) return; - const calendarFieldMetadata = objectMetadataItem.fields.find( - (field) => field.id === currentView.calendarFieldMetadataId, + const calendarFieldMetadata = objectMetadataItem.fields.find( + (field) => field.id === currentView.calendarFieldMetadataId, + ); + + if (!calendarFieldMetadata) return; + + const destinationRecordIds = store.get( + calendarDayRecordIdsSelector({ + day: destinationPlainDate, + timeZone: userTimezone, + }), + ) as string[]; + + const targetDayIsEmpty = destinationRecordIds.length === 0; + + let newPosition: number; + + if (targetDayIsEmpty) { + newPosition = 1; + } else { + const recordsWithPosition = extractRecordPositions( + destinationRecordIds, + store, ); + const droppedRecordIsFromAnotherList = !recordsWithPosition + .map((recordWithPosition) => recordWithPosition.id) + .includes(recordId); - if (!calendarFieldMetadata) return; + const isDroppedAfterList = + (recordsWithPosition.length === 2 && + destinationIndex === 1 && + !droppedRecordIsFromAnotherList) || + destinationIndex === recordsWithPosition.length; - const destinationRecordIds = snapshot - .getLoadable( - calendarDayRecordIdsSelector({ - day: destinationPlainDate, - timeZone: userTimezone, - }), - ) - .getValue() as string[]; + const targetRecord = isDroppedAfterList + ? recordsWithPosition.at(-1) + : recordsWithPosition.at(destinationIndex); - const targetDayIsEmpty = destinationRecordIds.length === 0; - - let newPosition: number; - - if (targetDayIsEmpty) { - newPosition = 1; - } else { - const recordsWithPosition = extractRecordPositions( - destinationRecordIds, - snapshot, + if (!isDefined(targetRecord)) { + throw new Error( + `targetRecord cannot be found in passed recordsWithPosition, this should not happen.`, ); - const droppedRecordIsFromAnotherList = !recordsWithPosition - .map((recordWithPosition) => recordWithPosition.id) - .includes(recordId); + } - const isDroppedAfterList = - (recordsWithPosition.length === 2 && - destinationIndex === 1 && - !droppedRecordIsFromAnotherList) || - destinationIndex === recordsWithPosition.length; + newPosition = computeNewPositionOfDraggedRecord({ + arrayOfRecordsWithPosition: recordsWithPosition, + idOfItemToMove: recordId, + idOfTargetItem: targetRecord.id, + isDroppedAfterList, + }); + } - const targetRecord = isDroppedAfterList - ? recordsWithPosition.at(-1) - : recordsWithPosition.at(destinationIndex); + const currentFieldValue = record[calendarFieldMetadata.name] as + | string + | undefined; - if (!isDefined(targetRecord)) { - throw new Error( - `targetRecord cannot be found in passed recordsWithPosition, this should not happen.`, + if (calendarFieldMetadata.type === FieldMetadataType.DATE) { + await updateOneRecord({ + objectNameSingular: objectMetadataItem.nameSingular, + idToUpdate: recordId, + updateOneRecordInput: { + [calendarFieldMetadata.name]: destinationPlainDate.toString(), + position: newPosition, + }, + }); + } else if (calendarFieldMetadata.type === FieldMetadataType.DATE_TIME) { + const newDate = isDefined(currentFieldValue) + ? Temporal.Instant.from(currentFieldValue) + .toZonedDateTimeISO(userTimezone) + .with({ + day: destinationPlainDate.day, + month: destinationPlainDate.month, + year: destinationPlainDate.year, + }) + : Temporal.PlainDate.from(destinationPlainDate).toZonedDateTime( + userTimezone, ); - } - newPosition = computeNewPositionOfDraggedRecord({ - arrayOfRecordsWithPosition: recordsWithPosition, - idOfItemToMove: recordId, - idOfTargetItem: targetRecord.id, - isDroppedAfterList, - }); - } - - const currentFieldValue = record[calendarFieldMetadata.name]; - - if (calendarFieldMetadata.type === FieldMetadataType.DATE) { - await updateOneRecord({ - objectNameSingular: objectMetadataItem.nameSingular, - idToUpdate: recordId, - updateOneRecordInput: { - [calendarFieldMetadata.name]: destinationPlainDate.toString(), - position: newPosition, - }, - }); - } else if (calendarFieldMetadata.type === FieldMetadataType.DATE_TIME) { - const newDate = isDefined(currentFieldValue) - ? Temporal.Instant.from(currentFieldValue) - .toZonedDateTimeISO(userTimezone) - .with({ - day: destinationPlainDate.day, - month: destinationPlainDate.month, - year: destinationPlainDate.year, - }) - : Temporal.PlainDate.from(destinationPlainDate).toZonedDateTime( - userTimezone, - ); - - await updateOneRecord({ - objectNameSingular: objectMetadataItem.nameSingular, - idToUpdate: recordId, - updateOneRecordInput: { - [calendarFieldMetadata.name]: newDate.toInstant().toString(), - position: newPosition, - }, - }); - } - }, + await updateOneRecord({ + objectNameSingular: objectMetadataItem.nameSingular, + idToUpdate: recordId, + updateOneRecordInput: { + [calendarFieldMetadata.name]: newDate.toInstant().toString(), + position: newPosition, + }, + }); + } + }, [ + store, currentView, objectMetadataItem.nameSingular, objectMetadataItem.fields, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithGroupRecordDrop.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithGroupRecordDrop.ts index e572e7aa52..b2dd31286b 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithGroupRecordDrop.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithGroupRecordDrop.ts @@ -1,5 +1,6 @@ import { type DropResult } from '@hello-pangea/dnd'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; @@ -11,14 +12,18 @@ import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-ind import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useProcessTableWithGroupRecordDrop = () => { + const store = useStore(); + const { recordIndexId } = useRecordIndexContextOrThrow(); const { objectNameSingular, objectMetadataItem, recordTableId } = useRecordTableContextOrThrow(); @@ -26,101 +31,98 @@ export const useProcessTableWithGroupRecordDrop = () => { const { openModal } = useModal(); - const recordIdsByGroupFamilyState = useRecoilComponentCallbackState( - recordIndexRecordIdsByGroupComponentFamilyState, - ); + const recordIdsByGroupFamilyState = + useRecoilComponentFamilyStateCallbackStateV2( + recordIndexRecordIdsByGroupComponentFamilyState, + ); - const currentRecordSortsCallbackState = useRecoilComponentCallbackState( + const currentRecordSortsAtom = useRecoilComponentStateCallbackStateV2( currentRecordSortsComponentState, + recordTableId, ); - const selectedRowIdsSelector = useRecoilComponentCallbackState( + const selectedRowIdsAtom = useRecoilComponentSelectorCallbackStateV2( selectedRowIdsComponentSelector, recordTableId, ); - const isDraggingRecordCallbackState = useRecoilComponentCallbackState( + const isDraggingRecordAtom = useRecoilComponentStateCallbackStateV2( isDraggingRecordComponentState, + recordIndexId, ); - const originalDragSelectionCallbackState = useRecoilComponentCallbackState( + const originalDragSelectionAtom = useRecoilComponentStateCallbackStateV2( originalDragSelectionComponentState, + recordIndexId, ); - const groupFieldMetadata = useRecoilComponentValue( + const groupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); - const processTableWithGroupRecordDrop = useRecoilCallback( - ({ snapshot }) => - (result: DropResult) => { - if (!result.destination) return; + const processTableWithGroupRecordDrop = useCallback( + (result: DropResult) => { + if (!result.destination) return; - const destinationRecordGroupId = result.destination.droppableId; - const destinationRecordGroup = getSnapshotValue( - snapshot, - recordGroupDefinitionFamilyState(destinationRecordGroupId), - ); + const destinationRecordGroupId = result.destination.droppableId; + const destinationRecordGroup = store.get( + recordGroupDefinitionFamilyState.atomFamily(destinationRecordGroupId), + ); - if (!isDefined(destinationRecordGroup)) { - throw new Error('Record group is not defined'); - } + if (!isDefined(destinationRecordGroup)) { + throw new Error('Record group is not defined'); + } - const fieldMetadata = objectMetadataItem.fields.find( - (field) => field.id === groupFieldMetadata?.id, - ); + const fieldMetadata = objectMetadataItem.fields.find( + (field) => field.id === groupFieldMetadata?.id, + ); - if (!isDefined(fieldMetadata)) { - throw new Error('Field metadata is not defined'); - } + if (!isDefined(fieldMetadata)) { + throw new Error('Field metadata is not defined'); + } - const originalDragSelection = getSnapshotValue( - snapshot, - originalDragSelectionCallbackState, - ); + const originalDragSelection = store.get( + originalDragSelectionAtom, + ) as string[]; - const isDraggingRecord = getSnapshotValue( - snapshot, - isDraggingRecordCallbackState, - ); + const isDraggingRecord = store.get(isDraggingRecordAtom); - const selectedRecordIds = isDraggingRecord - ? originalDragSelection - : getSnapshotValue(snapshot, selectedRowIdsSelector); + const selectedRecordIds = isDraggingRecord + ? originalDragSelection + : (store.get(selectedRowIdsAtom) as string[]); - const currentRecordSorts = snapshot - .getLoadable(currentRecordSortsCallbackState) - .getValue(); + const currentRecordSorts = store.get(currentRecordSortsAtom); - if (currentRecordSorts.length > 0) { - openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID); - return; - } + if (currentRecordSorts.length > 0) { + openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID); + return; + } - processGroupDrop({ - groupDropResult: result, - snapshot, - selectedRecordIds, - recordIdsByGroupFamilyState: recordIdsByGroupFamilyState, - onUpdateRecord: ({ recordId, position }) => { - updateOneRecord({ - objectNameSingular, - idToUpdate: recordId, - updateOneRecordInput: { - position, - [fieldMetadata.name]: destinationRecordGroup.value, - }, - }); - }, - }); - }, + processGroupDrop({ + groupDropResult: result, + store, + selectedRecordIds, + recordIdsByGroupFamilyState, + onUpdateRecord: ({ recordId, position }) => { + updateOneRecord({ + objectNameSingular, + idToUpdate: recordId, + updateOneRecordInput: { + position, + [fieldMetadata.name]: destinationRecordGroup.value, + }, + }); + }, + }); + }, [ + currentRecordSortsAtom, + store, objectNameSingular, objectMetadataItem.fields, - originalDragSelectionCallbackState, - isDraggingRecordCallbackState, - selectedRowIdsSelector, - currentRecordSortsCallbackState, + originalDragSelectionAtom, + isDraggingRecordAtom, + selectedRowIdsAtom, recordIdsByGroupFamilyState, groupFieldMetadata?.id, openModal, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithoutGroupRecordDrop.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithoutGroupRecordDrop.ts index 1af82c8e5b..46776e4075 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithoutGroupRecordDrop.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useProcessTableWithoutGroupRecordDrop.ts @@ -10,34 +10,42 @@ import { processSingleDrag } from '@/object-record/record-drag/utils/processSing import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-index/constants/RecordIndexRemoveSortingModalId'; import { allRecordIdsWithoutGroupsComponentSelector } from '@/object-record/record-index/states/selectors/allRecordIdsWithoutGroupsComponentSelector'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; +import { useStore } from 'jotai'; + import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; import { type RecordWithPosition } from '@/object-record/utils/computeNewPositionOfDraggedRecord'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useProcessTableWithoutGroupRecordDrop = () => { + const store = useStore(); + const { recordIndexId } = useRecordIndexContextOrThrow(); const { objectNameSingular } = useRecordTableContextOrThrow(); const { updateOneRecord } = useUpdateOneRecord(); - const allRecordIdsWithoutGroupCallbackSelector = - useRecoilComponentCallbackState(allRecordIdsWithoutGroupsComponentSelector); + const allRecordIdsWithoutGroupAtom = + useRecoilComponentSelectorCallbackStateV2( + allRecordIdsWithoutGroupsComponentSelector, + ); - const selectedRowIdsSelector = useRecoilComponentCallbackState( + const selectedRowIdsAtom = useRecoilComponentSelectorCallbackStateV2( selectedRowIdsComponentSelector, ); - const originalDragSelectionCallbackState = useRecoilComponentCallbackState( + const originalDragSelectionAtom = useRecoilComponentStateCallbackStateV2( originalDragSelectionComponentState, + recordIndexId, ); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); @@ -46,128 +54,124 @@ export const useProcessTableWithoutGroupRecordDrop = () => { const { triggerTableWithoutGroupDragAndDropOptimisticUpdate } = useTriggerTableWithoutGroupDragAndDropOptimisticUpdate(); - const processTableWithoutGroupRecordDrop = useRecoilCallback( - ({ snapshot }) => - async (tableRecordDropResult: DropResult) => { - if (!tableRecordDropResult.destination) return; + const processTableWithoutGroupRecordDrop = useCallback( + async (tableRecordDropResult: DropResult) => { + if (!tableRecordDropResult.destination) return; - if (currentRecordSorts.length > 0) { - openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID); + if (currentRecordSorts.length > 0) { + openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID); + return; + } + + const allSparseRecordIds = store.get( + allRecordIdsWithoutGroupAtom, + ) as string[]; + + const draggedRecordId = tableRecordDropResult.draggableId; + const selectedRecordIds = store.get(selectedRowIdsAtom) as string[]; + + const isDroppedAfterList = + tableRecordDropResult.destination.index + 1 >= + allSparseRecordIds.length; + + const recordsWithPosition: RecordWithPosition[] = allSparseRecordIds + .filter((recordId): recordId is string => isDefined(recordId)) + .map((recordId: string) => { + const record = store.get( + recordStoreFamilyState.atomFamily(recordId), + ) as { position?: number } | null | undefined; + return { + id: recordId, + position: record?.position ?? 0, + }; + }); + + const contiguousRecordsWithPosition = + recordsWithPosition.filter(isDefined); + + const dragOperationType = getDragOperationType({ + draggedRecordId, + selectedRecordIds, + }); + + if (dragOperationType === 'single') { + const targetRecordId = allSparseRecordIds.at( + tableRecordDropResult.destination.index, + ); + + if (!isDefined(targetRecordId)) { + throw new Error( + `Target record id cannot be found, this should not happen`, + ); + } + + const singleDragResult = processSingleDrag({ + sourceRecordId: draggedRecordId, + targetRecordId: targetRecordId ?? '', + recordsWithPosition: contiguousRecordsWithPosition, + isDroppedAfterList, + }); + + if (!isDefined(singleDragResult.position)) { return; } - const allSparseRecordIds = getSnapshotValue( - snapshot, - allRecordIdsWithoutGroupCallbackSelector, + triggerTableWithoutGroupDragAndDropOptimisticUpdate([singleDragResult]); + + updateOneRecord({ + objectNameSingular, + idToUpdate: singleDragResult.id, + updateOneRecordInput: { + position: singleDragResult.position, + }, + }); + } else { + const targetRecordId = allSparseRecordIds.at( + tableRecordDropResult.destination.index, ); - const draggedRecordId = tableRecordDropResult.draggableId; - const selectedRecordIds = getSnapshotValue( - snapshot, - selectedRowIdsSelector, - ); + if (!isDefined(targetRecordId)) { + throw new Error( + `Target record id cannot be found, this should not happen`, + ); + } - const isDroppedAfterList = - tableRecordDropResult.destination.index + 1 >= - allSparseRecordIds.length; + const originalDragSelection = store.get( + originalDragSelectionAtom, + ) as string[]; - const recordsWithPosition: RecordWithPosition[] = allSparseRecordIds - .filter(isDefined) - .map((recordId) => ({ - id: recordId, - position: - getSnapshotValue(snapshot, recordStoreFamilyState(recordId)) - ?.position ?? null, - })); - - const contiguousRecordsWithPosition = - recordsWithPosition.filter(isDefined); - - const dragOperationType = getDragOperationType({ + const multiDragResult = processMultiDrag({ draggedRecordId, - selectedRecordIds, + targetRecordId: targetRecordId ?? '', + selectedRecordIds: originalDragSelection, + recordsWithPosition: contiguousRecordsWithPosition, + isDroppedAfterList, }); - if (dragOperationType === 'single') { - const targetRecordId = allSparseRecordIds.at( - tableRecordDropResult.destination.index, - ); - - if (!isDefined(targetRecordId)) { - throw new Error( - `Target record id cannot be found, this should not happen`, - ); - } - - const singleDragResult = processSingleDrag({ - sourceRecordId: draggedRecordId, - targetRecordId: targetRecordId ?? '', - recordsWithPosition: contiguousRecordsWithPosition, - isDroppedAfterList, - }); - - if (!isDefined(singleDragResult.position)) { - return; - } - - triggerTableWithoutGroupDragAndDropOptimisticUpdate([ - singleDragResult, - ]); + triggerTableWithoutGroupDragAndDropOptimisticUpdate( + multiDragResult.recordUpdates, + ); + for (const update of multiDragResult.recordUpdates) { updateOneRecord({ objectNameSingular, - idToUpdate: singleDragResult.id, + idToUpdate: update.id, updateOneRecordInput: { - position: singleDragResult.position, + position: update.position, }, }); - } else { - const targetRecordId = allSparseRecordIds.at( - tableRecordDropResult.destination.index, - ); - - if (!isDefined(targetRecordId)) { - throw new Error( - `Target record id cannot be found, this should not happen`, - ); - } - - const originalDragSelection = getSnapshotValue( - snapshot, - originalDragSelectionCallbackState, - ); - - const multiDragResult = processMultiDrag({ - draggedRecordId, - targetRecordId: targetRecordId ?? '', - selectedRecordIds: originalDragSelection, - recordsWithPosition: contiguousRecordsWithPosition, - isDroppedAfterList, - }); - - triggerTableWithoutGroupDragAndDropOptimisticUpdate( - multiDragResult.recordUpdates, - ); - - for (const update of multiDragResult.recordUpdates) { - updateOneRecord({ - objectNameSingular, - idToUpdate: update.id, - updateOneRecordInput: { - position: update.position, - }, - }); - } } - }, + } + }, [ objectNameSingular, - selectedRowIdsSelector, + selectedRowIdsAtom, + store, updateOneRecord, openModal, currentRecordSorts, - originalDragSelectionCallbackState, - allRecordIdsWithoutGroupCallbackSelector, + originalDragSelectionAtom, + allRecordIdsWithoutGroupAtom, triggerTableWithoutGroupDragAndDropOptimisticUpdate, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useStartRecordDrag.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useStartRecordDrag.ts index 7506b73720..095f1619f4 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useStartRecordDrag.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useStartRecordDrag.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { draggedRecordIdsComponentState } from '@/object-record/record-drag/states/draggedRecordIdsComponentState'; import { isDraggingRecordComponentState } from '@/object-record/record-drag/states/isDraggingRecordComponentState'; import { isMultiDragActiveComponentState } from '@/object-record/record-drag/states/isMultiDragActiveComponentState'; @@ -7,98 +10,100 @@ import { originalDragSelectionComponentState } from '@/object-record/record-drag import { primaryDraggedRecordIdComponentState } from '@/object-record/record-drag/states/primaryDraggedRecordIdComponentState'; import { getDragOperationType } from '@/object-record/record-drag/utils/getDragOperationType'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { type DragStart } from '@hello-pangea/dnd'; -import { useRecoilCallback } from 'recoil'; export const useStartRecordDrag = (contextStoreInstanceId?: string) => { - const isMultiDragActiveCallbackState = useRecoilComponentCallbackState( + const store = useStore(); + const isMultiDragActiveCallbackState = useRecoilComponentStateCallbackStateV2( isMultiDragActiveComponentState, contextStoreInstanceId, ); - const draggedRecordIdsCallbackState = useRecoilComponentCallbackState( + const draggedRecordIdsCallbackState = useRecoilComponentStateCallbackStateV2( draggedRecordIdsComponentState, contextStoreInstanceId, ); const isRecordIdPrimaryDragMultipleCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( isRecordIdPrimaryDragMultipleComponentFamilyState, contextStoreInstanceId, ); const isRecordIdSecondaryDragMultipleCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( isRecordIdSecondaryDragMultipleComponentFamilyState, contextStoreInstanceId, ); - const primaryDraggedRecordIdCallbackState = useRecoilComponentCallbackState( - primaryDraggedRecordIdComponentState, - contextStoreInstanceId, - ); + const primaryDraggedRecordIdCallbackState = + useRecoilComponentStateCallbackStateV2( + primaryDraggedRecordIdComponentState, + contextStoreInstanceId, + ); - const originalSelectionCallbackState = useRecoilComponentCallbackState( + const originalSelectionAtom = useRecoilComponentStateCallbackStateV2( originalDragSelectionComponentState, contextStoreInstanceId, ); - const isDraggingRecordCallbackState = useRecoilComponentCallbackState( + const isDraggingRecordAtom = useRecoilComponentStateCallbackStateV2( isDraggingRecordComponentState, contextStoreInstanceId, ); - const startRecordDrag = useRecoilCallback( - ({ set }) => - (start: DragStart, selectedRecordIds: string[]) => { - set(isDraggingRecordCallbackState, true); + const startRecordDrag = useCallback( + (start: DragStart, selectedRecordIds: string[]) => { + store.set(isDraggingRecordAtom, true); - const draggedRecordId = start.draggableId; + const draggedRecordId = start.draggableId; - const dragOperationType = getDragOperationType({ - draggedRecordId, - selectedRecordIds, - }); + const dragOperationType = getDragOperationType({ + draggedRecordId, + selectedRecordIds, + }); - if (dragOperationType === 'multi') { - set(isMultiDragActiveCallbackState, true); - set(draggedRecordIdsCallbackState, selectedRecordIds); - set(primaryDraggedRecordIdCallbackState, draggedRecordId); - set(originalSelectionCallbackState, selectedRecordIds); + if (dragOperationType === 'multi') { + store.set(isMultiDragActiveCallbackState, true); + store.set(draggedRecordIdsCallbackState, selectedRecordIds); + store.set(primaryDraggedRecordIdCallbackState, draggedRecordId); + store.set(originalSelectionAtom, selectedRecordIds); - set( - isRecordIdPrimaryDragMultipleCallbackState({ - recordId: draggedRecordId, + store.set( + isRecordIdPrimaryDragMultipleCallbackState({ + recordId: draggedRecordId, + }), + true, + ); + + const secondaryDraggedIds = selectedRecordIds.filter( + (recordIdToFilter) => recordIdToFilter !== draggedRecordId, + ); + + for (const secondaryDraggedId of secondaryDraggedIds) { + store.set( + isRecordIdSecondaryDragMultipleCallbackState({ + recordId: secondaryDraggedId, }), true, ); - - const secondaryDraggedIds = selectedRecordIds.filter( - (recordIdToFilter) => recordIdToFilter !== draggedRecordId, - ); - - for (const secondaryDraggedId of secondaryDraggedIds) { - set( - isRecordIdSecondaryDragMultipleCallbackState({ - recordId: secondaryDraggedId, - }), - true, - ); - } - } else { - set(isMultiDragActiveCallbackState, true); - set(draggedRecordIdsCallbackState, [draggedRecordId]); - set(primaryDraggedRecordIdCallbackState, draggedRecordId); - set(originalSelectionCallbackState, [draggedRecordId]); } - }, + } else { + store.set(isMultiDragActiveCallbackState, true); + store.set(draggedRecordIdsCallbackState, [draggedRecordId]); + store.set(primaryDraggedRecordIdCallbackState, draggedRecordId); + store.set(originalSelectionAtom, [draggedRecordId]); + } + }, [ + store, isMultiDragActiveCallbackState, draggedRecordIdsCallbackState, primaryDraggedRecordIdCallbackState, - originalSelectionCallbackState, - isDraggingRecordCallbackState, + originalSelectionAtom, + isDraggingRecordAtom, isRecordIdSecondaryDragMultipleCallbackState, isRecordIdPrimaryDragMultipleCallbackState, ], diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useTriggerTableWithoutGroupDragAndDropOptimisticUpdate.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useTriggerTableWithoutGroupDragAndDropOptimisticUpdate.ts index 30ec19f5bf..f27042652e 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useTriggerTableWithoutGroupDragAndDropOptimisticUpdate.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useTriggerTableWithoutGroupDragAndDropOptimisticUpdate.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useLoadRecordsToVirtualRows } from '@/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows'; import { lastScrollPositionComponentState } from '@/object-record/record-table/virtualization/states/lastScrollPositionComponentState'; @@ -7,120 +10,106 @@ import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/ import { getVirtualizationOverscanWindow } from '@/object-record/record-table/virtualization/utils/getVirtualizationOverscanWindow'; import { type RecordWithPosition } from '@/object-record/utils/computeNewPositionOfDraggedRecord'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilySelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2'; import { findById, isDefined } from 'twenty-shared/utils'; import { sortByProperty } from '~/utils/array/sortByProperty'; -// TODO: does not work when scrolling while dragging and does not work if not paired with a network refetch right after -// But it's sufficient right now for the main use case export const useTriggerTableWithoutGroupDragAndDropOptimisticUpdate = () => { + const store = useStore(); const recordIdByRealIndexCallbackSelector = - useRecoilComponentFamilyCallbackState( + useRecoilComponentFamilySelectorCallbackStateV2( recordIdByRealIndexComponentFamilySelector, ); - const lastScrollPositionCallbackState = useRecoilComponentCallbackState( - lastScrollPositionComponentState, - ); + const lastScrollPositionCallbackState = + useRecoilComponentStateCallbackStateV2(lastScrollPositionComponentState); const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement(); const totalNumberOfRecordsToVirtualizeCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( totalNumberOfRecordsToVirtualizeComponentState, ); const { loadRecordsToVirtualRows } = useLoadRecordsToVirtualRows(); - const triggerTableWithoutGroupDragAndDropOptimisticUpdate = useRecoilCallback( - ({ snapshot }) => - (updatedRecords: RecordWithPosition[]) => { - const tableScrollWrapperHeight = - scrollWrapperHTMLElement?.clientHeight ?? 0; + const triggerTableWithoutGroupDragAndDropOptimisticUpdate = useCallback( + (updatedRecords: RecordWithPosition[]) => { + const tableScrollWrapperHeight = + scrollWrapperHTMLElement?.clientHeight ?? 0; - const lastScrollPosition = getSnapshotValue( - snapshot, - lastScrollPositionCallbackState, - ); + const lastScrollPosition = store.get(lastScrollPositionCallbackState); - const totalNumberOfRecordsToVirtualize = - getSnapshotValue( - snapshot, - totalNumberOfRecordsToVirtualizeCallbackState, - ) ?? 0; + const totalNumberOfRecordsToVirtualize = + store.get(totalNumberOfRecordsToVirtualizeCallbackState) ?? 0; - const { - firstRealIndexInOverscanWindow, - lastRealIndexInOverscanWindow, - } = getVirtualizationOverscanWindow( + const { firstRealIndexInOverscanWindow, lastRealIndexInOverscanWindow } = + getVirtualizationOverscanWindow( lastScrollPosition, tableScrollWrapperHeight, totalNumberOfRecordsToVirtualize, ); - const recordsInOverscanWindowToReorder: RecordWithPosition[] = []; + const recordsInOverscanWindowToReorder: RecordWithPosition[] = []; - for ( - let realIndex = firstRealIndexInOverscanWindow; - realIndex <= lastRealIndexInOverscanWindow; - realIndex++ + for ( + let realIndex = firstRealIndexInOverscanWindow; + realIndex <= lastRealIndexInOverscanWindow; + realIndex++ + ) { + const recordIdAtRealIndex = store.get( + recordIdByRealIndexCallbackSelector(realIndex), + ); + + if (!isDefined(recordIdAtRealIndex)) { + continue; + } + + const correspondingRecordInStore = store.get( + recordStoreFamilyState.atomFamily(recordIdAtRealIndex), + ) as { id: string; position?: number } | null | undefined; + + if ( + isDefined(correspondingRecordInStore) && + isDefined(correspondingRecordInStore.position) ) { - const recordIdAtRealIndex = getSnapshotValue( - snapshot, - recordIdByRealIndexCallbackSelector(realIndex), + const correspondingDraggedRecord = updatedRecords.find( + findById(correspondingRecordInStore.id), ); - if (!isDefined(recordIdAtRealIndex)) { - continue; - } + const hasRecordBeenDragged = isDefined(correspondingDraggedRecord); - const correspondingRecordInStore = getSnapshotValue( - snapshot, - recordStoreFamilyState(recordIdAtRealIndex), - ); + const positionToUse = hasRecordBeenDragged + ? correspondingDraggedRecord.position + : correspondingRecordInStore.position; - if ( - isDefined(correspondingRecordInStore) && - isDefined(correspondingRecordInStore.position) - ) { - const correspondingDraggedRecord = updatedRecords.find( - findById(correspondingRecordInStore.id), - ); - - const hasRecordBeenDragged = isDefined(correspondingDraggedRecord); - - const positionToUse = hasRecordBeenDragged - ? correspondingDraggedRecord.position - : correspondingRecordInStore.position; - - recordsInOverscanWindowToReorder.push({ - id: correspondingRecordInStore.id, - position: positionToUse, - }); - } + recordsInOverscanWindowToReorder.push({ + id: correspondingRecordInStore.id, + position: positionToUse, + }); } + } - const shouldReorderRecordsInOverscanWindow = - recordsInOverscanWindowToReorder.length > 0; + const shouldReorderRecordsInOverscanWindow = + recordsInOverscanWindowToReorder.length > 0; - if (!shouldReorderRecordsInOverscanWindow) { - return; - } + if (!shouldReorderRecordsInOverscanWindow) { + return; + } - const reorderedRecordsWithPosition = - recordsInOverscanWindowToReorder.toSorted(sortByProperty('position')); + const reorderedRecordsWithPosition = + recordsInOverscanWindowToReorder.toSorted(sortByProperty('position')); - loadRecordsToVirtualRows({ - records: reorderedRecordsWithPosition as any[], - startingRealIndex: firstRealIndexInOverscanWindow, - }); - }, + loadRecordsToVirtualRows({ + records: reorderedRecordsWithPosition as any[], + startingRealIndex: firstRealIndexInOverscanWindow, + }); + }, [ lastScrollPositionCallbackState, loadRecordsToVirtualRows, recordIdByRealIndexCallbackSelector, scrollWrapperHTMLElement?.clientHeight, + store, totalNumberOfRecordsToVirtualizeCallbackState, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useUpdateDroppedRecordOnBoard.ts b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useUpdateDroppedRecordOnBoard.ts index 29e9e9132d..74c0171ebb 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/hooks/useUpdateDroppedRecordOnBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/hooks/useUpdateDroppedRecordOnBoard.ts @@ -1,3 +1,6 @@ +import { useStore } from 'jotai'; + +import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { extractRecordPositions } from '@/object-record/record-drag/utils/extractRecordPositions'; import { recordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector'; @@ -5,162 +8,159 @@ import { type RecordGroupDefinition } from '@/object-record/record-group/types/R import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useCallback, useContext } from 'react'; import { findByProperty, isDefined } from 'twenty-shared/utils'; import { sortByProperty } from '~/utils/array/sortByProperty'; export const useUpdateDroppedRecordOnBoard = () => { + const store = useStore(); const { updateOneRecord, selectFieldMetadataItem } = useContext(RecordBoardContext); const recordIndexRecordIdsByGroupCallbackFamilyState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); - const recordGroupDefinitions = useRecoilComponentValue( + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, ); const { upsertRecordsInStore } = useUpsertRecordsInStore(); - const updateDroppedRecordOnBoard = useRecoilCallback( - ({ snapshot, set }) => - ( - { - recordId, - position: newPosition, - }: { recordId: string; position?: number }, - targetRecordGroupValue: RecordGroupDefinition['value'], - ) => { - const initialRecord = getSnapshotValue( - snapshot, - recordStoreFamilyState(recordId), + const updateDroppedRecordOnBoard = useCallback( + ( + { + recordId, + position: newPosition, + }: { recordId: string; position?: number }, + targetRecordGroupValue: RecordGroupDefinition['value'], + ) => { + const initialRecord = store.get( + recordStoreFamilyState.atomFamily(recordId), + ) as Record | null | undefined; + + if (!isDefined(newPosition)) { + return; + } + + if (!isDefined(initialRecord)) { + return; + } + + const initialRecordGroupValue = initialRecord[ + selectFieldMetadataItem.name + ] as string | undefined; + + const initialRecordGroup = recordGroupDefinitions.find( + findByProperty('value', initialRecordGroupValue), + ); + + if (!isDefined(initialRecordGroup)) { + return; + } + + const targetRecordGroup = recordGroupDefinitions.find( + findByProperty('value', targetRecordGroupValue), + ); + + if (!isDefined(targetRecordGroup)) { + return; + } + + const initialRecordGroupId = initialRecordGroup.id; + const targetRecordGroupId = targetRecordGroup.id; + + const movingInsideSameRecordGroup = + initialRecordGroupId === targetRecordGroupId; + + const isSamePosition = initialRecord.position === newPosition; + + if (movingInsideSameRecordGroup && isSamePosition) { + return; + } + + const currentRecordIdsInInitialRecordGroup = store.get( + recordIndexRecordIdsByGroupCallbackFamilyState(initialRecordGroupId), + ) as string[]; + + const positionOfDroppedRecordInInitialRecordIds = + currentRecordIdsInInitialRecordGroup.findIndex((id) => id === recordId); + + let currentRecordIdsInTargetRecordGroup = store.get( + recordIndexRecordIdsByGroupCallbackFamilyState(targetRecordGroupId), + ) as string[]; + + if (positionOfDroppedRecordInInitialRecordIds === -1) { + throw new Error( + `Cannot find record id in initial record group ids on drop, this should not happen`, + ); + } + + const newInitialGroupRecordIds = + currentRecordIdsInInitialRecordGroup.toSpliced( + positionOfDroppedRecordInInitialRecordIds, + 1, ); - if (!isDefined(newPosition)) { - return; - } - - if (!isDefined(initialRecord)) { - return; - } - - const initialRecordGroupValue = - initialRecord[selectFieldMetadataItem.name]; - - const initialRecordGroup = recordGroupDefinitions.find( - findByProperty('value', initialRecordGroupValue), - ); - - if (!isDefined(initialRecordGroup)) { - return; - } - - const targetRecordGroup = recordGroupDefinitions.find( - findByProperty('value', targetRecordGroupValue), - ); - - if (!isDefined(targetRecordGroup)) { - return; - } - - const initialRecordGroupId = initialRecordGroup.id; - const targetRecordGroupId = targetRecordGroup.id; - - const movingInsideSameRecordGroup = - initialRecordGroupId === targetRecordGroupId; - - const isSamePosition = initialRecord.position === newPosition; - - if (movingInsideSameRecordGroup && isSamePosition) { - return; - } - - const currentRecordIdsInInitialRecordGroup = getSnapshotValue( - snapshot, + if (movingInsideSameRecordGroup) { + currentRecordIdsInTargetRecordGroup = newInitialGroupRecordIds; + } else { + store.set( recordIndexRecordIdsByGroupCallbackFamilyState(initialRecordGroupId), + newInitialGroupRecordIds, ); + } - const positionOfDroppedRecordInInitialRecordIds = - currentRecordIdsInInitialRecordGroup.findIndex( - (id) => id === recordId, - ); + const targetGroupRecordsWithIds = extractRecordPositions( + currentRecordIdsInTargetRecordGroup, + store, + ); - let currentRecordIdsInTargetRecordGroup = getSnapshotValue( - snapshot, - recordIndexRecordIdsByGroupCallbackFamilyState(targetRecordGroupId), - ); + const newTargetRecordGroupWithIds = [ + ...targetGroupRecordsWithIds, + { + id: recordId, + position: newPosition, + }, + ]; - if (positionOfDroppedRecordInInitialRecordIds === -1) { - throw new Error( - `Cannot find record id in initial record group ids on drop, this should not happen`, - ); - } + newTargetRecordGroupWithIds.sort(sortByProperty('position', 'asc')); - const newInitialGroupRecordIds = - currentRecordIdsInInitialRecordGroup.toSpliced( - positionOfDroppedRecordInInitialRecordIds, - 1, - ); + store.set( + recordIndexRecordIdsByGroupCallbackFamilyState(targetRecordGroupId), + newTargetRecordGroupWithIds.map((record) => record.id), + ); - if (movingInsideSameRecordGroup) { - currentRecordIdsInTargetRecordGroup = newInitialGroupRecordIds; - } else { - set( - recordIndexRecordIdsByGroupCallbackFamilyState( - initialRecordGroupId, - ), - newInitialGroupRecordIds, - ); - } - - const targetGroupRecordsWithIds = extractRecordPositions( - currentRecordIdsInTargetRecordGroup, - snapshot, - ); - - const newTargetRecordGroupWithIds = [ - ...targetGroupRecordsWithIds, + upsertRecordsInStore({ + partialRecords: [ { + ...initialRecord, id: recordId, - position: newPosition, - }, - ]; - - newTargetRecordGroupWithIds.sort(sortByProperty('position', 'asc')); - - set( - recordIndexRecordIdsByGroupCallbackFamilyState(targetRecordGroupId), - newTargetRecordGroupWithIds.map((record) => record.id), - ); - - upsertRecordsInStore({ - partialRecords: [ - { - ...initialRecord, - [selectFieldMetadataItem.name]: targetRecordGroupValue, - position: newPosition, - }, - ], - }); - - updateOneRecord({ - idToUpdate: initialRecord.id, - updateOneRecordInput: { + __typename: + (initialRecord as { __typename?: string })?.__typename ?? + 'Record', [selectFieldMetadataItem.name]: targetRecordGroupValue, position: newPosition, - }, - }); - }, + } as ObjectRecord, + ], + }); + + updateOneRecord({ + idToUpdate: recordId, + updateOneRecordInput: { + [selectFieldMetadataItem.name]: targetRecordGroupValue, + position: newPosition, + }, + }); + }, [ recordGroupDefinitions, recordIndexRecordIdsByGroupCallbackFamilyState, selectFieldMetadataItem, + store, upsertRecordsInStore, updateOneRecord, ], diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/draggedRecordIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/draggedRecordIdsComponentState.ts index 1271f24fd4..cd7885c9ec 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/draggedRecordIdsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/draggedRecordIdsComponentState.ts @@ -1,7 +1,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const draggedRecordIdsComponentState = createComponentState({ +export const draggedRecordIdsComponentState = createComponentStateV2({ key: 'draggedRecordIdsComponentState', defaultValue: [], componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/isDraggingRecordComponentState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/isDraggingRecordComponentState.ts index a148ed084f..5c032ebc3f 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/isDraggingRecordComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/isDraggingRecordComponentState.ts @@ -1,7 +1,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const isDraggingRecordComponentState = createComponentState({ +export const isDraggingRecordComponentState = createComponentStateV2({ key: 'isDraggingRecordComponentState', defaultValue: false, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/isMultiDragActiveComponentState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/isMultiDragActiveComponentState.ts index 7a07ae233c..608928e2e7 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/isMultiDragActiveComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/isMultiDragActiveComponentState.ts @@ -1,7 +1,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const isMultiDragActiveComponentState = createComponentState({ +export const isMultiDragActiveComponentState = createComponentStateV2({ key: 'isMultiDragActiveComponentState', defaultValue: false, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdPrimaryDragMultipleComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdPrimaryDragMultipleComponentFamilyState.ts index a31530d205..1928e7394c 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdPrimaryDragMultipleComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdPrimaryDragMultipleComponentFamilyState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const isRecordIdPrimaryDragMultipleComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordIdPrimaryDragMultipleComponentFamilyState', defaultValue: false, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdSecondaryDragMultipleComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdSecondaryDragMultipleComponentFamilyState.ts index eee3d560df..554dcd58ad 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdSecondaryDragMultipleComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/isRecordIdSecondaryDragMultipleComponentFamilyState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const isRecordIdSecondaryDragMultipleComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordIdSecondaryDragMultipleComponentFamilyState', defaultValue: false, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/originalDragSelectionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/originalDragSelectionComponentState.ts index e1854577ff..4447cfe96b 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/originalDragSelectionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/originalDragSelectionComponentState.ts @@ -1,7 +1,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const originalDragSelectionComponentState = createComponentState< +export const originalDragSelectionComponentState = createComponentStateV2< string[] >({ key: 'originalDragSelectionComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-drag/states/primaryDraggedRecordIdComponentState.ts b/packages/twenty-front/src/modules/object-record/record-drag/states/primaryDraggedRecordIdComponentState.ts index 00443ff98b..0f143a0068 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/states/primaryDraggedRecordIdComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/states/primaryDraggedRecordIdComponentState.ts @@ -1,7 +1,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const primaryDraggedRecordIdComponentState = createComponentState< +export const primaryDraggedRecordIdComponentState = createComponentStateV2< string | null >({ key: 'primaryDraggedRecordIdComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-drag/utils/__tests__/extractRecordPositions.test.ts b/packages/twenty-front/src/modules/object-record/record-drag/utils/__tests__/extractRecordPositions.test.ts index 212a750e59..405b757e97 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/utils/__tests__/extractRecordPositions.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/utils/__tests__/extractRecordPositions.test.ts @@ -1,39 +1,32 @@ +import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { extractRecordPositions } from '@/object-record/record-drag/utils/extractRecordPositions'; -import { type Snapshot } from 'recoil'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { isDefined } from 'twenty-shared/utils'; +const setMockRecordData = ( + recordData: Record>, +) => { + for (const [recordId, record] of Object.entries(recordData)) { + jotaiStore.set(recordStoreFamilyState.atomFamily(recordId), { + ...record, + id: recordId, + __typename: 'Record', + } as ObjectRecord); + } +}; describe('extractRecordPositions', () => { - const createMockSnapshot = (recordData: Record): Snapshot => { - return { - getLoadable: (atom: any) => { - const match = atom.key.match(/recordStoreFamilyState__"([^"]+)"/); - const recordId = match ? match[1] : atom.key; - if (isDefined(recordData[recordId])) { - return { - getValue: () => recordData[recordId], - state: 'hasValue', - }; - } - return { - getValue: () => undefined, - state: 'hasValue', - }; - }, - } as unknown as Snapshot; - }; - - it('should extract position data from records in snapshot', () => { - const mockRecordData = { + it('should extract position data from records in store', () => { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: 1, name: 'Record 1' }, 'record-2': { id: 'record-2', position: 2, name: 'Record 2' }, 'record-3': { id: 'record-3', position: 3, name: 'Record 3' }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-1', 'record-2', 'record-3']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ { id: 'record-1', position: 1 }, @@ -43,61 +36,60 @@ describe('extractRecordPositions', () => { }); it('should handle records with undefined positions', () => { - const mockRecordData = { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: 1 }, 'record-2': { id: 'record-2' }, 'record-3': { id: 'record-3', position: undefined }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-1', 'record-2', 'record-3']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ { id: 'record-1', position: 1 }, - { id: 'record-2', position: undefined }, - { id: 'record-3', position: undefined }, + { id: 'record-2', position: 0 }, + { id: 'record-3', position: 0 }, ]); }); it('should handle non-existent records', () => { - const mockRecordData = { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: 1 }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-1', 'record-2', 'non-existent']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ { id: 'record-1', position: 1 }, - { id: 'record-2', position: undefined }, - { id: 'non-existent', position: undefined }, + { id: 'record-2', position: 0 }, + { id: 'non-existent', position: 0 }, ]); }); it('should handle empty record list', () => { - const snapshot = createMockSnapshot({}); const allRecordIds: string[] = []; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([]); }); it('should preserve order of input record IDs', () => { - const mockRecordData = { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: 100 }, 'record-2': { id: 'record-2', position: 50 }, 'record-3': { id: 'record-3', position: 75 }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-3', 'record-1', 'record-2']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ { id: 'record-3', position: 75 }, @@ -107,32 +99,32 @@ describe('extractRecordPositions', () => { }); it('should handle null positions', () => { - const mockRecordData = { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: null }, 'record-2': { id: 'record-2', position: 2 }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-1', 'record-2']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ - { id: 'record-1', position: null }, + { id: 'record-1', position: 0 }, { id: 'record-2', position: 2 }, ]); }); it('should handle negative positions', () => { - const mockRecordData = { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: -5 }, 'record-2': { id: 'record-2', position: -10 }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-1', 'record-2']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ { id: 'record-1', position: -5 }, @@ -141,15 +133,15 @@ describe('extractRecordPositions', () => { }); it('should handle decimal positions', () => { - const mockRecordData = { + const mockRecordData: Record> = { 'record-1': { id: 'record-1', position: 1.5 }, 'record-2': { id: 'record-2', position: 2.75 }, }; - const snapshot = createMockSnapshot(mockRecordData); + setMockRecordData(mockRecordData); const allRecordIds = ['record-1', 'record-2']; - const result = extractRecordPositions(allRecordIds, snapshot); + const result = extractRecordPositions(allRecordIds, jotaiStore); expect(result).toEqual([ { id: 'record-1', position: 1.5 }, diff --git a/packages/twenty-front/src/modules/object-record/record-drag/utils/extractRecordPositions.ts b/packages/twenty-front/src/modules/object-record/record-drag/utils/extractRecordPositions.ts index abbcf5160e..d1e6f84122 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/utils/extractRecordPositions.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/utils/extractRecordPositions.ts @@ -1,19 +1,21 @@ +import type { Store } from 'jotai/vanilla/store'; + import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type RecordWithPosition } from '@/object-record/utils/computeNewPositionOfDraggedRecord'; -import { type Snapshot } from 'recoil'; export const extractRecordPositions = ( recordIds: string[], - snapshot: Snapshot, + store: Store, ): RecordWithPosition[] => { return recordIds.map((recordId) => { - const record = snapshot - .getLoadable(recordStoreFamilyState(recordId)) - .getValue(); + const record = store.get(recordStoreFamilyState.atomFamily(recordId)) as + | { position?: number } + | null + | undefined; return { id: recordId, - position: record?.position, + position: record?.position ?? 0, }; }); }; diff --git a/packages/twenty-front/src/modules/object-record/record-drag/utils/processGroupDrop.ts b/packages/twenty-front/src/modules/object-record/record-drag/utils/processGroupDrop.ts index 4169237287..9a432dd71a 100644 --- a/packages/twenty-front/src/modules/object-record/record-drag/utils/processGroupDrop.ts +++ b/packages/twenty-front/src/modules/object-record/record-drag/utils/processGroupDrop.ts @@ -1,11 +1,9 @@ import { type DropResult } from '@hello-pangea/dnd'; -import { type Snapshot } from 'recoil'; +import type { Store } from 'jotai/vanilla/store'; import { isDefined } from 'twenty-shared/utils'; -import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; - import { processSingleDrag } from '@/object-record/record-drag/utils/processSingleDrag'; +import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; import { extractRecordPositions } from './extractRecordPositions'; import { getDragOperationType } from './getDragOperationType'; @@ -13,7 +11,7 @@ import { processMultiDrag } from './processMultiDrag'; type ProcessGroupDropParams = { groupDropResult: DropResult; - snapshot: Snapshot; + store: Store; selectedRecordIds: string[]; recordIdsByGroupFamilyState: any; onUpdateRecord: ( @@ -24,7 +22,7 @@ type ProcessGroupDropParams = { export const processGroupDrop = ({ groupDropResult, - snapshot, + store, selectedRecordIds, recordIdsByGroupFamilyState, onUpdateRecord, @@ -35,17 +33,15 @@ export const processGroupDrop = ({ const destinationGroupId = groupDropResult.destination.droppableId; - const recordGroup = getSnapshotValue( - snapshot, - recordGroupDefinitionFamilyState(destinationGroupId), + const recordGroup = store.get( + recordGroupDefinitionFamilyState.atomFamily(destinationGroupId), ); if (!isDefined(recordGroup)) { throw new Error('Record group is not defined'); } - const destinationRecordIds = getSnapshotValue( - snapshot, + const destinationRecordIds = store.get( recordIdsByGroupFamilyState(destinationGroupId), ) as string[]; @@ -84,7 +80,7 @@ export const processGroupDrop = ({ const recordsWithPosition = extractRecordPositions( destinationRecordIds, - snapshot, + store, ); const destinationIndex = groupDropResult.destination.index; diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellEditModePortal.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellEditModePortal.tsx index 9e9a098caa..3b1fc9afbd 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellEditModePortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellEditModePortal.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { RecordFieldListInputContextProvider } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider'; @@ -24,7 +24,7 @@ export const RecordFieldListCellEditModePortal = ({ RecordFieldListComponentInstanceContext, ); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordFieldListCellEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortal.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortal.tsx index a58692d2a0..e3f477dd27 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortal.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { RecordFieldListCellHoveredPortalContent } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortalContent'; @@ -23,7 +23,7 @@ export const RecordFieldListCellHoveredPortal = ({ RecordFieldListComponentInstanceContext, ); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordFieldListHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortalContent.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortalContent.tsx index 868bfdfb16..38b1c9f0d5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortalContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortalContent.tsx @@ -11,8 +11,8 @@ import { RecordInlineCellHoveredPortalContent } from '@/object-record/record-inl import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext } from 'react'; export const RecordFieldListCellHoveredPortalContent = () => { @@ -36,9 +36,9 @@ export const RecordFieldListCellHoveredPortalContent = () => { !isRecordFieldReadOnly && !editModeContentOnly; const [recordFieldListHoverPosition, setRecordFieldListHoverPosition] = - useRecoilComponentState(recordFieldListHoverPositionComponentState); + useRecoilComponentStateV2(recordFieldListHoverPositionComponentState); - const setRecordFieldListCellEditModePosition = useSetRecoilComponentState( + const setRecordFieldListCellEditModePosition = useSetRecoilComponentStateV2( recordFieldListCellEditModePositionComponentState, ); const { openFieldInput } = useOpenFieldInputEditMode(); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider.tsx index ce41f4f801..8edd449eb3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider.tsx @@ -13,7 +13,7 @@ import { import { useOpenFieldInputEditMode } from '@/object-record/record-field/ui/hooks/useOpenFieldInputEditMode'; import { currentFocusIdSelector } from '@/ui/utilities/focus/states/currentFocusIdSelector'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useStore } from 'jotai'; import { useCallback } from 'react'; @@ -39,7 +39,7 @@ export const RecordFieldListInputContextProvider = ({ const { closeFieldInput } = useOpenFieldInputEditMode(); - const setRecordFieldListCellEditModePosition = useSetRecoilComponentState( + const setRecordFieldListCellEditModePosition = useSetRecoilComponentStateV2( recordFieldListCellEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/components/RecordFieldList.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/components/RecordFieldList.tsx index 37e910044c..54a4662776 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/components/RecordFieldList.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/components/RecordFieldList.tsx @@ -24,7 +24,7 @@ import { useRecordShowContainerActions } from '@/object-record/record-show/hooks import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { FieldMetadataType } from 'twenty-shared/types'; type RecordFieldListProps = { @@ -66,7 +66,7 @@ export const RecordFieldList = ({ objectMetadataId: objectMetadataItem.id, }); - const setRecordFieldListHoverPosition = useSetRecoilComponentState( + const setRecordFieldListHoverPosition = useSetRecoilComponentStateV2( recordFieldListHoverPositionComponentState, instanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/hooks/useFieldListFieldMetadataFromPosition.ts b/packages/twenty-front/src/modules/object-record/record-field-list/hooks/useFieldListFieldMetadataFromPosition.ts index 07ae279b97..01e7fb5086 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/hooks/useFieldListFieldMetadataFromPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-field-list/hooks/useFieldListFieldMetadataFromPosition.ts @@ -1,7 +1,7 @@ import { useFieldListFieldMetadataItems } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems'; import { recordFieldListCellEditModePositionComponentState } from '@/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState'; import { recordFieldListHoverPositionComponentState } from '@/object-record/record-field-list/states/recordFieldListHoverPositionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; type UseFieldListFieldMetadataFromPositionProps = { @@ -11,11 +11,11 @@ type UseFieldListFieldMetadataFromPositionProps = { export const useFieldListFieldMetadataFromPosition = ({ objectNameSingular, }: UseFieldListFieldMetadataFromPositionProps) => { - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordFieldListHoverPositionComponentState, ); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordFieldListCellEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx index 81f24fd403..6db47369b0 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownManyToOne.tsx @@ -17,7 +17,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { IconForbid, IconPencil } from 'twenty-ui/display'; @@ -70,12 +70,12 @@ export const RecordDetailMorphRelationSectionDropdownManyToOne = ({ dropdownId, ); - const setSingleRecordPickerSearchFilter = useSetRecoilComponentState( + const setSingleRecordPickerSearchFilter = useSetRecoilComponentStateV2( singleRecordPickerSearchFilterComponentState, dropdownId, ); - const setSingleRecordPickerSelectedId = useSetRecoilComponentState( + const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx index 29e408ed5b..bf436b1517 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdownOneToMany.tsx @@ -19,7 +19,7 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { CustomError, isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; @@ -73,18 +73,19 @@ export const RecordDetailMorphRelationSectionDropdownOneToMany = ({ dropdownId, ); - const setMultipleRecordPickerSearchFilter = useSetRecoilComponentState( + const setMultipleRecordPickerSearchFilter = useSetRecoilComponentStateV2( multipleRecordPickerSearchFilterComponentState, dropdownId, ); - const setMultipleRecordPickerPickableMorphItems = useSetRecoilComponentState( - multipleRecordPickerPickableMorphItemsComponentState, - dropdownId, - ); + const setMultipleRecordPickerPickableMorphItems = + useSetRecoilComponentStateV2( + multipleRecordPickerPickableMorphItemsComponentState, + dropdownId, + ); const setMultipleRecordPickerSearchableObjectMetadataItems = - useSetRecoilComponentState( + useSetRecoilComponentStateV2( multipleRecordPickerSearchableObjectMetadataItemsComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx index a9247ed34b..3fae5bd650 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx @@ -29,7 +29,7 @@ import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDrop import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { t } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; import { createPortal } from 'react-dom'; @@ -162,7 +162,7 @@ export const RecordDetailRelationRecordsListItem = ({ recordId, instanceId: scopeInstanceId, }); - const setSingleRecordPickerSelectedId = useSetRecoilComponentState( + const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx index 3ea018fd8e..45911641d1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx @@ -1,5 +1,4 @@ import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; @@ -16,7 +15,7 @@ import { import { usePersistField } from '@/object-record/record-field/ui/hooks/usePersistField'; import { type FieldRelationMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; @@ -82,9 +81,10 @@ export const RecordDetailRelationSection = ({ ); } - const fieldValue = useRecoilValue< - ({ id: string } & Record) | ObjectRecord[] | null - >(recordStoreFamilySelector({ recordId, fieldName })); + const fieldValue = useFamilySelectorValueV2(recordStoreFamilySelectorV2, { + recordId, + fieldName, + }) as ({ id: string } & Record) | ObjectRecord[] | null; // TODO: use new relation type const isToOneObject = relationType === RelationType.MANY_TO_ONE; diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx index a233f8dc2d..c8fd9c020a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToMany.tsx @@ -1,5 +1,4 @@ import { type ReactNode, useCallback, useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; @@ -16,13 +15,14 @@ import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-r import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState'; import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState'; import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { CustomError, isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; @@ -71,9 +71,10 @@ export const RecordDetailRelationSectionDropdownToMany = ({ ); } - const fieldValue = useRecoilValue< - ({ id: string } & Record) | ObjectRecord[] | null - >(recordStoreFamilySelector({ recordId, fieldName })); + const fieldValue = useFamilySelectorValueV2(recordStoreFamilySelectorV2, { + recordId, + fieldName, + }) as ({ id: string } & Record) | ObjectRecord[] | null; const relationRecords: ObjectRecord[] = (fieldValue as ObjectRecord[]) ?? []; @@ -90,18 +91,19 @@ export const RecordDetailRelationSectionDropdownToMany = ({ dropdownId, ); - const setMultipleRecordPickerSearchFilter = useSetRecoilComponentState( + const setMultipleRecordPickerSearchFilter = useSetRecoilComponentStateV2( multipleRecordPickerSearchFilterComponentState, dropdownId, ); - const setMultipleRecordPickerPickableMorphItems = useSetRecoilComponentState( - multipleRecordPickerPickableMorphItemsComponentState, - dropdownId, - ); + const setMultipleRecordPickerPickableMorphItems = + useSetRecoilComponentStateV2( + multipleRecordPickerPickableMorphItemsComponentState, + dropdownId, + ); const setMultipleRecordPickerSearchableObjectMetadataItems = - useSetRecoilComponentState( + useSetRecoilComponentStateV2( multipleRecordPickerSearchableObjectMetadataItemsComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx index a24cbc614a..8c614b4f5f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSectionDropdownToOne.tsx @@ -1,5 +1,4 @@ import { type ReactNode, useCallback, useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -13,13 +12,14 @@ import { singleRecordPickerSearchFilterComponentState } from '@/object-record/re import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { getFieldMetadataItemById } from '@/object-metadata/utils/getFieldMetadataItemById'; @@ -80,9 +80,10 @@ export const RecordDetailRelationSectionDropdownToOne = ({ ); } - const fieldValue = useRecoilValue< - ({ id: string } & Record) | ObjectRecord[] | null - >(recordStoreFamilySelector({ recordId, fieldName })); + const fieldValue = useFamilySelectorValueV2(recordStoreFamilySelectorV2, { + recordId, + fieldName, + }) as ({ id: string } & Record) | ObjectRecord[] | null; const relationRecords: ObjectRecord[] = fieldValue ? [fieldValue as ObjectRecord] @@ -101,12 +102,12 @@ export const RecordDetailRelationSectionDropdownToOne = ({ dropdownId, ); - const setSingleRecordPickerSearchFilter = useSetRecoilComponentState( + const setSingleRecordPickerSearchFilter = useSetRecoilComponentStateV2( singleRecordPickerSearchFilterComponentState, dropdownId, ); - const setSingleRecordPickerSelectedId = useSetRecoilComponentState( + const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/hooks/useGetMorphRelationRelatedRecordsWithObjectNameSingular.ts b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/hooks/useGetMorphRelationRelatedRecordsWithObjectNameSingular.ts index f3b1f00aad..32a8ecaeb7 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/hooks/useGetMorphRelationRelatedRecordsWithObjectNameSingular.ts +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/hooks/useGetMorphRelationRelatedRecordsWithObjectNameSingular.ts @@ -1,6 +1,6 @@ import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation'; -import { recordStoreMorphOneToManyValueWithObjectNameFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector'; -import { useRecoilValue } from 'recoil'; +import { recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { CustomError, isNonEmptyArray } from 'twenty-shared/utils'; export const useGetMorphRelationRelatedRecordsWithObjectNameSingular = ({ @@ -10,11 +10,9 @@ export const useGetMorphRelationRelatedRecordsWithObjectNameSingular = ({ recordId: string; morphRelations: FieldMetadataItemRelation[]; }) => { - const morphRelationObjectNameSingularWithValues = useRecoilValue( - recordStoreMorphOneToManyValueWithObjectNameFamilySelector({ - recordId, - morphRelations, - }), + const morphRelationObjectNameSingularWithValues = useFamilySelectorValueV2( + recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2, + { recordId, morphRelations }, ); if (morphRelations.length < 1) { diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState.ts index d784a2eaa7..14e889d805 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState.ts @@ -1,8 +1,8 @@ import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordFieldListCellEditModePositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordFieldListCellEditModePositionComponentState', defaultValue: null, componentInstanceContext: RecordFieldListComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListHoverPositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListHoverPositionComponentState.ts index f949c84804..121524d7c0 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListHoverPositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field-list/states/recordFieldListHoverPositionComponentState.ts @@ -1,10 +1,9 @@ import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const recordFieldListHoverPositionComponentState = createComponentState< - number | null ->({ - key: 'recordFieldListHoverPositionComponentState', - defaultValue: null, - componentInstanceContext: RecordFieldListComponentInstanceContext, -}); +export const recordFieldListHoverPositionComponentState = + createComponentStateV2({ + key: 'recordFieldListHoverPositionComponentState', + defaultValue: null, + componentInstanceContext: RecordFieldListComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useChangeRecordFieldVisibility.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useChangeRecordFieldVisibility.ts index 32eb9c9208..58d9e5f82f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useChangeRecordFieldVisibility.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useChangeRecordFieldVisibility.ts @@ -2,7 +2,7 @@ import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpda import { useUpsertRecordField } from '@/object-record/record-field/hooks/useUpsertRecordField'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields'; import { mapRecordFieldToViewField } from '@/views/utils/mapRecordFieldToViewField'; import { isDefined } from 'twenty-shared/utils'; @@ -12,7 +12,7 @@ import { sortByProperty } from '~/utils/array/sortByProperty'; export const useChangeRecordFieldVisibility = ( recordFieldComponentInstanceId?: string, ) => { - const currentRecordFields = useRecoilComponentValue( + const currentRecordFields = useRecoilComponentValueV2( currentRecordFieldsComponentState, recordFieldComponentInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts index 6d86bb1fed..a7b60ac984 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useMoveRecordField.ts @@ -1,13 +1,14 @@ import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields'; import { mapRecordFieldToViewField } from '@/views/utils/mapRecordFieldToViewField'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { sortByProperty } from '~/utils/array/sortByProperty'; export const useMoveRecordField = (recordTableId?: string) => { - const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + const currentRecordFieldsAtom = useRecoilComponentStateCallbackStateV2( currentRecordFieldsComponentState, recordTableId, ); @@ -16,76 +17,71 @@ export const useMoveRecordField = (recordTableId?: string) => { const { updateRecordField } = useUpdateRecordField(recordTableId); - // TODO: fix this we want to move left and right of VISIBLE record fields, - // because otherwise it will just do nothing while moving left and right of non visible record fields - const moveRecordField = useRecoilCallback( - ({ snapshot }) => - async ({ - direction, - fieldMetadataItemIdToMove, - }: { - direction: 'before' | 'after'; - fieldMetadataItemIdToMove: string; - }) => { - const currentRecordFields = snapshot - .getLoadable(currentRecordFieldsCallbackState) - .getValue(); + const moveRecordField = useCallback( + async ({ + direction, + fieldMetadataItemIdToMove, + }: { + direction: 'before' | 'after'; + fieldMetadataItemIdToMove: string; + }) => { + const currentRecordFields = jotaiStore.get(currentRecordFieldsAtom); - const sortedRecordFields = currentRecordFields.toSorted( - sortByProperty('position'), - ); + const sortedRecordFields = currentRecordFields.toSorted( + sortByProperty('position'), + ); - const indexOfRecordFieldToMove = sortedRecordFields.findIndex( - (recordField) => - recordField.fieldMetadataItemId === fieldMetadataItemIdToMove, - ); + const indexOfRecordFieldToMove = sortedRecordFields.findIndex( + (recordField) => + recordField.fieldMetadataItemId === fieldMetadataItemIdToMove, + ); - if (indexOfRecordFieldToMove === -1) { - return; - } + if (indexOfRecordFieldToMove === -1) { + return; + } - const newRecordFields = [...sortedRecordFields]; + const newRecordFields = [...sortedRecordFields]; - const targetArrayIndex = - direction === 'before' - ? indexOfRecordFieldToMove - 1 - : indexOfRecordFieldToMove + 1; + const targetArrayIndex = + direction === 'before' + ? indexOfRecordFieldToMove - 1 + : indexOfRecordFieldToMove + 1; - const targetArraySize = newRecordFields.length - 1; + const targetArraySize = newRecordFields.length - 1; - if ( - indexOfRecordFieldToMove >= 0 && - targetArrayIndex >= 0 && - indexOfRecordFieldToMove <= targetArraySize && - targetArrayIndex <= targetArraySize - ) { - const currentRecordField = newRecordFields[indexOfRecordFieldToMove]; - const targetRecordField = newRecordFields[targetArrayIndex]; + if ( + indexOfRecordFieldToMove >= 0 && + targetArrayIndex >= 0 && + indexOfRecordFieldToMove <= targetArraySize && + targetArrayIndex <= targetArraySize + ) { + const currentRecordField = newRecordFields[indexOfRecordFieldToMove]; + const targetRecordField = newRecordFields[targetArrayIndex]; - const targetRecordFieldNewPosition = currentRecordField.position; - const currentRecordFieldNewPosition = targetRecordField.position; + const targetRecordFieldNewPosition = currentRecordField.position; + const currentRecordFieldNewPosition = targetRecordField.position; - updateRecordField(targetRecordField.fieldMetadataItemId, { + updateRecordField(targetRecordField.fieldMetadataItemId, { + position: targetRecordFieldNewPosition, + }); + + updateRecordField(currentRecordField.fieldMetadataItemId, { + position: currentRecordFieldNewPosition, + }); + + await saveViewFields([ + mapRecordFieldToViewField({ + ...targetRecordField, position: targetRecordFieldNewPosition, - }); - - updateRecordField(currentRecordField.fieldMetadataItemId, { + }), + mapRecordFieldToViewField({ + ...currentRecordField, position: currentRecordFieldNewPosition, - }); - - await saveViewFields([ - mapRecordFieldToViewField({ - ...targetRecordField, - position: targetRecordFieldNewPosition, - }), - mapRecordFieldToViewField({ - ...currentRecordField, - position: currentRecordFieldNewPosition, - }), - ]); - } - }, - [currentRecordFieldsCallbackState, saveViewFields, updateRecordField], + }), + ]); + } + }, + [currentRecordFieldsAtom, saveViewFields, updateRecordField], ); return { moveRecordField }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields.ts index 97f5fc4173..ce9b65b880 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields.ts @@ -8,7 +8,7 @@ import { generateActivityTargetGqlFields } from '@/object-record/graphql/record- import { generateDepthRecordGqlFieldsFromFields } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromFields'; import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isDefined } from 'twenty-shared/utils'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -22,7 +22,7 @@ export const useRecordsFieldVisibleGqlFields = ({ objectMetadataItem, additionalFieldMetadataId, }: UseRecordsFieldVisibleGqlFields) => { - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderVisibleRecordFields.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderVisibleRecordFields.ts index c9bda7a5f1..706f2f03e7 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderVisibleRecordFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useReorderVisibleRecordFields.ts @@ -3,63 +3,55 @@ import { currentRecordFieldsComponentState } from '@/object-record/record-field/ import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; import { computeNewPositionOfDraggedRecord } from '@/object-record/utils/computeNewPositionOfDraggedRecord'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useCallback } from 'react'; export const useReorderVisibleRecordFields = (recordTableId: string) => { - const visibleRecordFieldsCallbackState = useRecoilComponentCallbackState( + const visibleRecordFieldsAtom = useRecoilComponentSelectorCallbackStateV2( visibleRecordFieldsComponentSelector, recordTableId, ); - const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + const currentRecordFieldsAtom = useRecoilComponentStateCallbackStateV2( currentRecordFieldsComponentState, recordTableId, ); const { updateRecordField } = useUpdateRecordField(recordTableId); - const reorderVisibleRecordFields = useRecoilCallback( - ({ snapshot }) => - ({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => { - const visibleRecordFields = snapshot - .getLoadable(visibleRecordFieldsCallbackState) - .getValue(); + const reorderVisibleRecordFields = useCallback( + ({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => { + const visibleRecordFields = jotaiStore.get(visibleRecordFieldsAtom); + const currentRecordFields = jotaiStore.get(currentRecordFieldsAtom); - const currentRecordFields = snapshot - .getLoadable(currentRecordFieldsCallbackState) - .getValue(); + const idOfRecordToMove = visibleRecordFields[fromIndex].id; + const idOfTargetRecord = visibleRecordFields[toIndex].id; - const idOfRecordToMove = visibleRecordFields[fromIndex].id; - const idOfTargetRecord = visibleRecordFields[toIndex].id; + const recordToMove = visibleRecordFields[fromIndex]; - const recordToMove = visibleRecordFields[fromIndex]; + const isDroppedAfterList = toIndex >= visibleRecordFields.length; - const isDroppedAfterList = toIndex >= visibleRecordFields.length; + const newPositionOfTargetRecord = computeNewPositionOfDraggedRecord({ + arrayOfRecordsWithPosition: currentRecordFields, + idOfItemToMove: idOfRecordToMove, + idOfTargetItem: idOfTargetRecord, + isDroppedAfterList, + }); - const newPositionOfTargetRecord = computeNewPositionOfDraggedRecord({ - arrayOfRecordsWithPosition: currentRecordFields, - idOfItemToMove: idOfRecordToMove, - idOfTargetItem: idOfTargetRecord, - isDroppedAfterList, - }); + updateRecordField(recordToMove.fieldMetadataItemId, { + position: newPositionOfTargetRecord, + }); - updateRecordField(recordToMove.fieldMetadataItemId, { - position: newPositionOfTargetRecord, - }); + const updatedRecordField: RecordField = { + ...recordToMove, + position: newPositionOfTargetRecord, + }; - const updatedRecordField: RecordField = { - ...recordToMove, - position: newPositionOfTargetRecord, - }; - - return updatedRecordField; - }, - [ - currentRecordFieldsCallbackState, - visibleRecordFieldsCallbackState, - updateRecordField, - ], + return updatedRecordField; + }, + [currentRecordFieldsAtom, visibleRecordFieldsAtom, updateRecordField], ); return { reorderVisibleRecordFields }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts index 3a805d81ee..7e2fb0e0f1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpdateRecordField.ts @@ -1,64 +1,60 @@ import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useUpdateRecordField = ( recordFieldComponentInstanceId?: string, ) => { - const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + const currentRecordFieldsAtom = useRecoilComponentStateCallbackStateV2( currentRecordFieldsComponentState, recordFieldComponentInstanceId, ); - const updateRecordField = useRecoilCallback( - ({ set, snapshot }) => - ( - fieldMetadataItemId: string, - partialRecordField: Partial< - Pick - >, - ) => { - const currentRecordFields = getSnapshotValue( - snapshot, - currentRecordFieldsCallbackState, - ); + const updateRecordField = useCallback( + ( + fieldMetadataItemId: string, + partialRecordField: Partial< + Pick + >, + ) => { + const currentRecordFields = jotaiStore.get(currentRecordFieldsAtom); - const foundRecordFieldInCurrentRecordFields = currentRecordFields.find( + const foundRecordFieldInCurrentRecordFields = currentRecordFields.find( + (existingRecordField) => + existingRecordField.fieldMetadataItemId === fieldMetadataItemId, + ); + + if (!isDefined(foundRecordFieldInCurrentRecordFields)) { + throw new Error( + `Cannot find record field to update with field metadata item id : ${fieldMetadataItemId}`, + ); + } + + jotaiStore.set(currentRecordFieldsAtom, (currentRecordFields) => { + const newCurrentRecordFields = [...currentRecordFields]; + + const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex( (existingRecordField) => existingRecordField.fieldMetadataItemId === fieldMetadataItemId, ); - if (!isDefined(foundRecordFieldInCurrentRecordFields)) { - throw new Error( - `Cannot find record field to update with field metadata item id : ${fieldMetadataItemId}`, - ); - } else { - set(currentRecordFieldsCallbackState, (currentRecordFields) => { - const newCurrentRecordFields = [...currentRecordFields]; + newCurrentRecordFields[indexOfRecordFieldToUpdate] = { + ...newCurrentRecordFields[indexOfRecordFieldToUpdate], + ...partialRecordField, + }; - const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex( - (existingRecordField) => - existingRecordField.fieldMetadataItemId === fieldMetadataItemId, - ); + return newCurrentRecordFields; + }); - newCurrentRecordFields[indexOfRecordFieldToUpdate] = { - ...newCurrentRecordFields[indexOfRecordFieldToUpdate], - ...partialRecordField, - }; - - return newCurrentRecordFields; - }); - - return { - ...foundRecordFieldInCurrentRecordFields, - ...partialRecordField, - } satisfies RecordField as RecordField; - } - }, - [currentRecordFieldsCallbackState], + return { + ...foundRecordFieldInCurrentRecordFields, + ...partialRecordField, + } satisfies RecordField as RecordField; + }, + [currentRecordFieldsAtom], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts index 4a0e8bf848..07b02d6027 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useUpsertRecordField.ts @@ -1,51 +1,47 @@ import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useCallback } from 'react'; export const useUpsertRecordField = (recordTableId?: string) => { - const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + const currentRecordFieldsAtom = useRecoilComponentStateCallbackStateV2( currentRecordFieldsComponentState, recordTableId, ); - const upsertRecordField = useRecoilCallback( - ({ set, snapshot }) => - (recordFieldToUpsert: RecordField) => { - const currentRecordFields = getSnapshotValue( - snapshot, - currentRecordFieldsCallbackState, - ); + const upsertRecordField = useCallback( + (recordFieldToUpsert: RecordField) => { + const currentRecordFields = jotaiStore.get(currentRecordFieldsAtom); - const foundRecordFieldInCurrentRecordFields = currentRecordFields.some( - (existingRecordField) => - existingRecordField.id === recordFieldToUpsert.id, - ); + const foundRecordFieldInCurrentRecordFields = currentRecordFields.some( + (existingRecordField) => + existingRecordField.id === recordFieldToUpsert.id, + ); - if (!foundRecordFieldInCurrentRecordFields) { - set(currentRecordFieldsCallbackState, [ - ...currentRecordFields, - recordFieldToUpsert, - ]); - } else { - set(currentRecordFieldsCallbackState, (currentRecordFields) => { - const newCurrentRecordFields = [...currentRecordFields]; + if (!foundRecordFieldInCurrentRecordFields) { + jotaiStore.set(currentRecordFieldsAtom, [ + ...currentRecordFields, + recordFieldToUpsert, + ]); + } else { + jotaiStore.set(currentRecordFieldsAtom, (currentRecordFields) => { + const newCurrentRecordFields = [...currentRecordFields]; - const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex( - (existingRecordField) => - existingRecordField.id === recordFieldToUpsert.id, - ); + const indexOfRecordFieldToUpdate = newCurrentRecordFields.findIndex( + (existingRecordField) => + existingRecordField.id === recordFieldToUpsert.id, + ); - newCurrentRecordFields[indexOfRecordFieldToUpdate] = { - ...recordFieldToUpsert, - }; + newCurrentRecordFields[indexOfRecordFieldToUpdate] = { + ...recordFieldToUpsert, + }; - return newCurrentRecordFields; - }); - } - }, - [currentRecordFieldsCallbackState], + return newCurrentRecordFields; + }); + } + }, + [currentRecordFieldsAtom], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts index 8c4d539863..4646857074 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/states/currentRecordFieldsComponentState.ts @@ -1,8 +1,8 @@ import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const currentRecordFieldsComponentState = createComponentState< +export const currentRecordFieldsComponentState = createComponentStateV2< RecordField[] >({ key: 'currentRecordFieldsComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/visibleRecordFieldsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-field/states/visibleRecordFieldsComponentSelector.ts index 614efb8ae9..f00baae8bf 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/states/visibleRecordFieldsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/states/visibleRecordFieldsComponentSelector.ts @@ -1,75 +1,86 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { isActiveFieldMetadataItem } from '@/object-metadata/utils/isActiveFieldMetadataItem'; import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { findById } from 'twenty-shared/utils'; import { sortByProperty } from '~/utils/array/sortByProperty'; -export const visibleRecordFieldsComponentSelector = createComponentSelector({ +export const visibleRecordFieldsComponentSelector = createComponentSelectorV2< + RecordField[] +>({ key: 'visibleRecordFieldsComponentSelector', componentInstanceContext: RecordFieldsComponentInstanceContext, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { const currentRecordFields = get( - currentRecordFieldsComponentState.atomFamily({ - instanceId, - }), + currentRecordFieldsComponentState, + componentStateKey, ); - const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); + const objectMetadataItems = get(objectMetadataItemsState); - const filteredVisibleAndReadableRecordFields = currentRecordFields.filter( - (recordFieldToFilter) => { - if (!recordFieldToFilter.isVisible) { - return false; - } - - const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.fields.some( - (fieldMetadataItem) => - fieldMetadataItem.id === - recordFieldToFilter.fieldMetadataItemId, - ), - ); - - if (!objectMetadataItem) { - return false; - } - - const fieldMetadataItem = objectMetadataItem.fields.find( - (fieldMetadataItem) => - fieldMetadataItem.id === recordFieldToFilter.fieldMetadataItemId, - ); - - if (!fieldMetadataItem) { - return false; - } - - const isLabelIdentifier = - fieldMetadataItem.id === - objectMetadataItem.labelIdentifierFieldMetadataId; - - const isActive = - isLabelIdentifier || - isActiveFieldMetadataItem({ - objectNameSingular: objectMetadataItem.nameSingular, - fieldMetadata: fieldMetadataItem, - }); - - const isReadable = objectMetadataItem.readableFields.some( - findById(fieldMetadataItem.id), - ); - - return isReadable && isActive; - }, - ); - - return [...filteredVisibleAndReadableRecordFields].sort( - sortByProperty('position'), + return filterVisibleAndReadableRecordFields( + currentRecordFields, + objectMetadataItems, ); }, }); + +const filterVisibleAndReadableRecordFields = ( + currentRecordFields: RecordField[], + objectMetadataItems: ObjectMetadataItem[], +): RecordField[] => { + const filteredVisibleAndReadableRecordFields = currentRecordFields.filter( + (recordFieldToFilter) => { + if (!recordFieldToFilter.isVisible) { + return false; + } + + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.fields.some( + (fieldMetadataItem) => + fieldMetadataItem.id === recordFieldToFilter.fieldMetadataItemId, + ), + ); + + if (!objectMetadataItem) { + return false; + } + + const fieldMetadataItem = objectMetadataItem.fields.find( + (fieldMetadataItem) => + fieldMetadataItem.id === recordFieldToFilter.fieldMetadataItemId, + ); + + if (!fieldMetadataItem) { + return false; + } + + const isLabelIdentifier = + fieldMetadataItem.id === + objectMetadataItem.labelIdentifierFieldMetadataId; + + const isActive = + isLabelIdentifier || + isActiveFieldMetadataItem({ + objectNameSingular: objectMetadataItem.nameSingular, + fieldMetadata: fieldMetadataItem, + }); + + const isReadable = objectMetadataItem.readableFields.some( + findById(fieldMetadataItem.id), + ); + + return isReadable && isActive; + }, + ); + + return [...filteredVisibleAndReadableRecordFields].sort( + sortByProperty('position'), + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx index 06f3d3074a..dc93f0be0e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx @@ -12,7 +12,7 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; @@ -116,7 +116,7 @@ export const FormSingleRecordPicker = ({ const { closeDropdown } = useCloseDropdown(); - const setRecordPickerSearchFilter = useSetRecoilComponentState( + const setRecordPickerSearchFilter = useSetRecoilComponentStateV2( singleRecordPickerSearchFilterComponentState, dropdownId, ); @@ -148,7 +148,7 @@ export const FormSingleRecordPicker = ({ onClear?.(); }; - const setRecordPickerSelectedId = useSetRecoilComponentState( + const setRecordPickerSelectedId = useSetRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, dropdownId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/__tests__/useIsFieldEmpty.test.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/__tests__/useIsFieldEmpty.test.tsx index 5206b3178c..2efebed25e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/__tests__/useIsFieldEmpty.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/__tests__/useIsFieldEmpty.test.tsx @@ -1,33 +1,39 @@ import { act, renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { type ReactNode } from 'react'; -import { RecoilRoot, useSetRecoilState } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { phonesFieldDefinition } from '@/object-record/record-field/ui/__mocks__/fieldDefinitions'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useIsFieldEmpty } from '@/object-record/record-field/ui/hooks/useIsFieldEmpty'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; const recordId = 'recordId'; const Wrapper = ({ children }: { children: ReactNode }) => ( - - {children} - + + + {children} + + ); describe('useIsFieldEmpty', () => { it('should work as expected', () => { const { result } = renderHook( () => { - const setFieldState = useSetRecoilState( - recordStoreFamilyState(recordId), + const setFieldState = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + recordId, ); return { setFieldState, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useClearField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useClearField.ts index 3d82cfc9f9..6a8b20f84a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useClearField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useClearField.ts @@ -1,9 +1,9 @@ -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useContext } from 'react'; +import { useStore } from 'jotai'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFieldValue'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; @@ -11,6 +11,7 @@ import { getForeignKeyNameFromRelationFieldName } from '@/object-record/utils/ge import { FieldMetadataType, RelationType } from 'twenty-shared/types'; export const useClearField = () => { + const store = useStore(); const { recordId, fieldDefinition, @@ -19,78 +20,75 @@ export const useClearField = () => { const [updateRecord] = useUpdateRecord(); - const clearField = useRecoilCallback( - ({ set }) => - () => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + const clearField = useCallback(() => { + const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); - const foundObjectMetadataItem = objectMetadataItems.find( - (item) => - item.nameSingular === - fieldDefinition.metadata.objectMetadataNameSingular, - ); + const foundObjectMetadataItem = objectMetadataItems.find( + (item) => + item.nameSingular === + fieldDefinition.metadata.objectMetadataNameSingular, + ); - const foundFieldMetadataItem = foundObjectMetadataItem?.fields.find( - (field) => field.name === fieldDefinition.metadata.fieldName, - ); + const foundFieldMetadataItem = foundObjectMetadataItem?.fields.find( + (field) => field.name === fieldDefinition.metadata.fieldName, + ); - if (!foundObjectMetadataItem || !foundFieldMetadataItem) { - throw new Error('Field metadata item cannot be found'); - } + if (!foundObjectMetadataItem || !foundFieldMetadataItem) { + throw new Error('Field metadata item cannot be found'); + } - const isRelation = - foundFieldMetadataItem.type === FieldMetadataType.RELATION || - foundFieldMetadataItem.type === FieldMetadataType.MORPH_RELATION; + const isRelation = + foundFieldMetadataItem.type === FieldMetadataType.RELATION || + foundFieldMetadataItem.type === FieldMetadataType.MORPH_RELATION; - const shouldSkipClearingBecauseInvolvesMultipleRecords = - isRelation && - foundFieldMetadataItem.settings?.relationType === - RelationType.ONE_TO_MANY; + const shouldSkipClearingBecauseInvolvesMultipleRecords = + isRelation && + foundFieldMetadataItem.settings?.relationType === + RelationType.ONE_TO_MANY; - if (shouldSkipClearingBecauseInvolvesMultipleRecords) { - return; - } + if (shouldSkipClearingBecauseInvolvesMultipleRecords) { + return; + } - const fieldName = fieldDefinition.metadata.fieldName; + const fieldName = fieldDefinition.metadata.fieldName; - const emptyFieldValue = generateEmptyFieldValue({ - fieldMetadataItem: foundFieldMetadataItem, - }); + const emptyFieldValue = generateEmptyFieldValue({ + fieldMetadataItem: foundFieldMetadataItem, + }); - set( - recordStoreFamilySelector({ recordId, fieldName }), - emptyFieldValue, - ); + store.set( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + emptyFieldValue, + ); - const isManyToOneRelation = - isRelation && - foundFieldMetadataItem.settings?.relationType === - RelationType.MANY_TO_ONE; + const isManyToOneRelation = + isRelation && + foundFieldMetadataItem.settings?.relationType === + RelationType.MANY_TO_ONE; - const updateFieldName = isManyToOneRelation - ? getForeignKeyNameFromRelationFieldName(fieldName) - : fieldName; + const updateFieldName = isManyToOneRelation + ? getForeignKeyNameFromRelationFieldName(fieldName) + : fieldName; - if (isManyToOneRelation) { - set( - recordStoreFamilySelector({ recordId, fieldName: updateFieldName }), - emptyFieldValue, - ); - } + if (isManyToOneRelation) { + store.set( + recordStoreFamilySelectorV2.selectorFamily({ + recordId, + fieldName: updateFieldName, + }), + emptyFieldValue, + ); + } - updateRecord?.({ - variables: { - where: { id: recordId }, - updateOneRecordInput: { - [updateFieldName]: emptyFieldValue, - }, - }, - }); + updateRecord?.({ + variables: { + where: { id: recordId }, + updateOneRecordInput: { + [updateFieldName]: emptyFieldValue, + }, }, - [recordId, fieldDefinition, updateRecord], - ); + }); + }, [recordId, fieldDefinition, store, updateRecord]); return clearField; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useInitDraftValue.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useInitDraftValue.ts index 6f79b2de41..aab258f7a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useInitDraftValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useInitDraftValue.ts @@ -1,5 +1,6 @@ import { isUndefined } from '@sniptt/guards'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { FIELD_NOT_OVERWRITTEN_AT_DRAFT } from '@/object-record/constants/FieldsNotOverwrittenAtDraft'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; @@ -7,56 +8,56 @@ import { type FieldDefinition } from '@/object-record/record-field/ui/types/Fiel import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { computeDraftValueFromFieldValue } from '@/object-record/record-field/ui/utils/computeDraftValueFromFieldValue'; import { computeDraftValueFromString } from '@/object-record/record-field/ui/utils/computeDraftValueFromString'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; export const useInitDraftValue = () => { - return useRecoilCallback( - ({ set, snapshot }) => - ({ - value, - recordId, - fieldDefinition, - fieldComponentInstanceId, - }: { - value?: string; - recordId: string; - fieldDefinition: FieldDefinition; - fieldComponentInstanceId: string; - }) => { - const recordFieldValue = snapshot - .getLoadable( - recordStoreFamilySelector({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - }), - ) - .getValue(); + const store = useStore(); - if ( - isUndefined(value) || - FIELD_NOT_OVERWRITTEN_AT_DRAFT.includes(fieldDefinition.type) - ) { - set( - recordFieldInputDraftValueComponentState.atomFamily({ - instanceId: fieldComponentInstanceId, - }), - computeDraftValueFromFieldValue({ - fieldValue: recordFieldValue, - fieldDefinition, - }), - ); - } else { - set( - recordFieldInputDraftValueComponentState.atomFamily({ - instanceId: fieldComponentInstanceId, - }), - computeDraftValueFromString({ - value, - fieldDefinition, - }), - ); - } - }, - [], + return useCallback( + ({ + value, + recordId, + fieldDefinition, + fieldComponentInstanceId, + }: { + value?: string; + recordId: string; + fieldDefinition: FieldDefinition; + fieldComponentInstanceId: string; + }) => { + const recordFieldValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ + recordId, + fieldName: fieldDefinition.metadata.fieldName, + }), + ) as FieldValue; + + const draftValueAtom = + recordFieldInputDraftValueComponentState.atomFamily({ + instanceId: fieldComponentInstanceId, + }); + + if ( + isUndefined(value) || + FIELD_NOT_OVERWRITTEN_AT_DRAFT.includes(fieldDefinition.type) + ) { + store.set( + draftValueAtom, + computeDraftValueFromFieldValue({ + fieldValue: recordFieldValue, + fieldDefinition, + }), + ); + } else { + store.set( + draftValueAtom, + computeDraftValueFromString({ + value, + fieldDefinition, + }), + ); + } + }, + [store], ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useIsRecordDeleted.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useIsRecordDeleted.ts index f772efc823..34088b8f4f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useIsRecordDeleted.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useIsRecordDeleted.ts @@ -1,6 +1,6 @@ -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilValue } from 'recoil'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; type UseIsRecordReadOnlyParams = { @@ -10,12 +10,10 @@ type UseIsRecordReadOnlyParams = { export const useIsRecordDeleted = ({ recordId, }: UseIsRecordReadOnlyParams): boolean => { - const recordDeletedAt = useRecoilValue( - recordStoreFamilySelector({ - recordId, - fieldName: 'deletedAt', - }), - ); + const recordDeletedAt = useFamilySelectorValueV2( + recordStoreFamilySelectorV2, + { recordId, fieldName: 'deletedAt' }, + ) as ObjectRecord | null; return isDefined(recordDeletedAt); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts index d8ff8733d4..35f47758af 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts @@ -28,16 +28,17 @@ import { isFieldRelationManyToOne } from '@/object-record/record-field/ui/types/ import { isFieldRelationOneToMany } from '@/object-record/record-field/ui/types/guards/isFieldRelationOneToMany'; import { hasJunctionConfig } from '@/object-record/record-field/ui/utils/junction/hasJunctionConfig'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useOpenFieldInputEditMode = () => { + const store = useStore(); const { openRelationToOneFieldInput } = useOpenRelationToOneFieldInput(); const { openRelationFromManyFieldInput } = useOpenRelationFromManyFieldInput(); @@ -60,184 +61,171 @@ export const useOpenFieldInputEditMode = () => { const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); - const openFieldInput = useRecoilCallback( - ({ snapshot }) => - ({ - fieldDefinition, - recordId, - prefix, - }: { - fieldDefinition: FieldDefinition; - recordId: string; - prefix?: string; - }) => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, + const openFieldInput = useCallback( + ({ + fieldDefinition, + recordId, + prefix, + }: { + fieldDefinition: FieldDefinition; + recordId: string; + prefix?: string; + }) => { + const objectMetadataItems = store.get(objectMetadataItemsState.atom); + + const currentWorkspace = store.get(currentWorkspaceState.atom); + + const isJunctionRelationsEnabled = + currentWorkspace?.featureFlags?.find( + (flag) => (flag.key as string) === 'IS_JUNCTION_RELATIONS_ENABLED', + )?.value ?? false; + + const isOneToMany = isFieldRelationOneToMany(fieldDefinition); + const fieldHasJunctionConfig = hasJunctionConfig( + fieldDefinition.metadata.settings, + ); + + // Handle Files field with custom behavior for empty state + if (isFieldFiles(fieldDefinition)) { + const objectMetadataItem = objectMetadataItems.find( + (item) => + item.nameSingular === + fieldDefinition.metadata.objectMetadataNameSingular, ); - const currentWorkspace = jotaiStore.get(currentWorkspaceState.atom); - - const isJunctionRelationsEnabled = - currentWorkspace?.featureFlags?.find( - (flag) => (flag.key as string) === 'IS_JUNCTION_RELATIONS_ENABLED', - )?.value ?? false; - - const isOneToMany = isFieldRelationOneToMany(fieldDefinition); - const fieldHasJunctionConfig = hasJunctionConfig( - fieldDefinition.metadata.settings, - ); - - // Handle Files field with custom behavior for empty state - if (isFieldFiles(fieldDefinition)) { - const objectMetadataItem = objectMetadataItems.find( - (item) => - item.nameSingular === - fieldDefinition.metadata.objectMetadataNameSingular, - ); - - if (isDefined(objectMetadataItem)) { - openFilesFieldInput({ - fieldName: fieldDefinition.metadata.fieldName, - fieldMetadataId: fieldDefinition.fieldMetadataId, - recordId, - prefix, - updateRecord: (updateInput) => { - updateOneRecord({ - objectNameSingular: objectMetadataItem.nameSingular, - idToUpdate: recordId, - updateOneRecordInput: updateInput, - }); - }, - fieldDefinition: { - metadata: { - settings: fieldDefinition.metadata.settings ?? undefined, - }, - }, - }); - return; - } - } - - if ( - isJunctionRelationsEnabled && - isOneToMany && - fieldHasJunctionConfig - ) { - openJunctionRelationFieldInput({ - fieldDefinition: - fieldDefinition as FieldDefinition, - recordId, - prefix, - }); - return; - } - - // Backward compatibility: hardcoded taskTarget/noteTarget check - // TODO: Remove this once taskTarget/noteTarget are migrated to use junction configuration - if ( - isFieldRelationOneToMany(fieldDefinition) && - ['taskTarget', 'noteTarget'].includes( - fieldDefinition.metadata.relationObjectMetadataNameSingular, - ) - ) { - const fieldValue = snapshot - .getLoadable>( - recordStoreFamilySelector({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - }), - ) - .getValue(); - - const activity = snapshot - .getLoadable(recordStoreFamilyState(recordId)) - .getValue(); - - const activityTargetObjectRecords = getActivityTargetObjectRecords({ - activityRecord: activity as Task | Note, - objectMetadataItems, - activityTargets: fieldValue as NoteTarget[] | TaskTarget[], - }); - - openActivityTargetCellEditMode({ - recordPickerInstanceId: getRecordFieldInputInstanceId({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - prefix, - }), - activityTargetObjectRecords, - }); - return; - } - - if (isFieldRelationManyToOne(fieldDefinition)) { - openRelationToOneFieldInput({ + if (isDefined(objectMetadataItem)) { + openFilesFieldInput({ fieldName: fieldDefinition.metadata.fieldName, + fieldMetadataId: fieldDefinition.fieldMetadataId, recordId, prefix, - }); - - return; - } - - if (isFieldMorphRelationOneToMany(fieldDefinition)) { - if (!isFieldMorphRelation(fieldDefinition)) { - throw new Error('Field is not a morph relation one to many'); - } - - openMorphRelationOneToManyFieldInput({ - recordId, - prefix, - fieldDefinition, + updateRecord: (updateInput) => { + updateOneRecord({ + objectNameSingular: objectMetadataItem.nameSingular, + idToUpdate: recordId, + updateOneRecordInput: updateInput, + }); + }, + fieldDefinition: { + metadata: { + settings: fieldDefinition.metadata.settings ?? undefined, + }, + }, }); return; } + } - if (isFieldRelationOneToMany(fieldDefinition)) { - if ( - isDefined( - fieldDefinition.metadata.relationObjectMetadataNameSingular, - ) - ) { - openRelationFromManyFieldInput({ - fieldName: fieldDefinition.metadata.fieldName, - objectNameSingular: - fieldDefinition.metadata.relationObjectMetadataNameSingular, - recordId, - prefix, - }); - return; - } - } + if (isJunctionRelationsEnabled && isOneToMany && fieldHasJunctionConfig) { + openJunctionRelationFieldInput({ + fieldDefinition: + fieldDefinition as FieldDefinition, + recordId, + prefix, + }); + return; + } - if (isFieldMorphRelationManyToOne(fieldDefinition)) { - openMorphRelationManyToOneFieldInput({ + // Backward compatibility: hardcoded taskTarget/noteTarget check + // TODO: Remove this once taskTarget/noteTarget are migrated to use junction configuration + if ( + isFieldRelationOneToMany(fieldDefinition) && + ['taskTarget', 'noteTarget'].includes( + fieldDefinition.metadata.relationObjectMetadataNameSingular, + ) + ) { + const fieldValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, - prefix, - fieldDefinition, - }); - return; - } + fieldName: fieldDefinition.metadata.fieldName, + }), + ) as FieldRelationValue; - pushFocusItemToFocusStack({ - focusId: getRecordFieldInputInstanceId({ + const activity = store.get(recordStoreFamilyState.atomFamily(recordId)); + + const activityTargetObjectRecords = getActivityTargetObjectRecords({ + activityRecord: activity as Task | Note, + objectMetadataItems, + activityTargets: fieldValue as NoteTarget[] | TaskTarget[], + }); + + openActivityTargetCellEditMode({ + recordPickerInstanceId: getRecordFieldInputInstanceId({ recordId, fieldName: fieldDefinition.metadata.fieldName, prefix, }), - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, - instanceId: getRecordFieldInputInstanceId({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - prefix, - }), - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, + activityTargetObjectRecords, }); - }, + return; + } + + if (isFieldRelationManyToOne(fieldDefinition)) { + openRelationToOneFieldInput({ + fieldName: fieldDefinition.metadata.fieldName, + recordId, + prefix, + }); + + return; + } + + if (isFieldMorphRelationOneToMany(fieldDefinition)) { + if (!isFieldMorphRelation(fieldDefinition)) { + throw new Error('Field is not a morph relation one to many'); + } + + openMorphRelationOneToManyFieldInput({ + recordId, + prefix, + fieldDefinition, + }); + return; + } + + if (isFieldRelationOneToMany(fieldDefinition)) { + if ( + isDefined(fieldDefinition.metadata.relationObjectMetadataNameSingular) + ) { + openRelationFromManyFieldInput({ + fieldName: fieldDefinition.metadata.fieldName, + objectNameSingular: + fieldDefinition.metadata.relationObjectMetadataNameSingular, + recordId, + prefix, + }); + return; + } + } + + if (isFieldMorphRelationManyToOne(fieldDefinition)) { + openMorphRelationManyToOneFieldInput({ + recordId, + prefix, + fieldDefinition, + }); + return; + } + + pushFocusItemToFocusStack({ + focusId: getRecordFieldInputInstanceId({ + recordId, + fieldName: fieldDefinition.metadata.fieldName, + prefix, + }), + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId: getRecordFieldInputInstanceId({ + recordId, + fieldName: fieldDefinition.metadata.fieldName, + prefix, + }), + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, [ openActivityTargetCellEditMode, openFilesFieldInput, @@ -247,6 +235,7 @@ export const useOpenFieldInputEditMode = () => { openRelationFromManyFieldInput, openRelationToOneFieldInput, pushFocusItemToFocusStack, + store, updateOneRecord, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenJunctionRelationFieldInput.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenJunctionRelationFieldInput.ts index fa69a5370a..6ea741b210 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenJunctionRelationFieldInput.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenJunctionRelationFieldInput.ts @@ -14,132 +14,129 @@ import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-pic import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState'; import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useOpenJunctionRelationFieldInput = () => { const { performSearch } = useMultipleRecordPickerPerformSearch(); const { openMultipleRecordPicker } = useMultipleRecordPickerOpen(); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); + const store = useStore(); - const openJunctionRelationFieldInput = useRecoilCallback( - ({ set, snapshot }) => - ({ - fieldDefinition, + const openJunctionRelationFieldInput = useCallback( + ({ + fieldDefinition, + recordId, + prefix, + }: { + fieldDefinition: FieldDefinition; + recordId: string; + prefix?: string; + }) => { + const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); + + const sourceObjectMetadataId = objectMetadataItems.find( + (item) => + item.nameSingular === + fieldDefinition.metadata.objectMetadataNameSingular, + )?.id; + + const junctionConfig = getJunctionConfig({ + settings: fieldDefinition.metadata.settings, + relationObjectMetadataId: + fieldDefinition.metadata.relationObjectMetadataId, + sourceObjectMetadataId, + objectMetadataItems, + }); + + if (!isDefined(junctionConfig)) { + return; + } + + const { targetFields } = junctionConfig; + + if (targetFields.length === 0) { + return; + } + + const recordPickerInstanceId = getRecordFieldInputInstanceId({ recordId, + fieldName: fieldDefinition.metadata.fieldName, prefix, - }: { - fieldDefinition: FieldDefinition; - recordId: string; - prefix?: string; - }) => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + }); - const sourceObjectMetadataId = objectMetadataItems.find( - (item) => - item.nameSingular === - fieldDefinition.metadata.objectMetadataNameSingular, - )?.id; - - const junctionConfig = getJunctionConfig({ - settings: fieldDefinition.metadata.settings, - relationObjectMetadataId: - fieldDefinition.metadata.relationObjectMetadataId, - sourceObjectMetadataId, - objectMetadataItems, - }); - - if (!isDefined(junctionConfig)) { - return; - } - - const { targetFields } = junctionConfig; - - if (targetFields.length === 0) { - return; - } - - const recordPickerInstanceId = getRecordFieldInputInstanceId({ + const junctionRecords = jotaiStore.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName: fieldDefinition.metadata.fieldName, - prefix, - }); + }), + ) as FieldRelationValue; - const junctionRecords = snapshot - .getLoadable>( - recordStoreFamilySelector({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - }), - ) - .getValue(); + const selectedTargetRecords = extractTargetRecordsFromJunction({ + junctionRecords, + targetFields, + objectMetadataItems, + }); - const selectedTargetRecords = extractTargetRecordsFromJunction({ - junctionRecords, - targetFields, - objectMetadataItems, - }); + const searchableObjectMetadataItems = getSearchableObjectMetadataItems( + targetFields, + objectMetadataItems, + ); - const searchableObjectMetadataItems = getSearchableObjectMetadataItems( - targetFields, - objectMetadataItems, - ); + const pickableMorphItems = selectedTargetRecords.map((record) => ({ + recordId: record.recordId, + objectMetadataId: record.objectMetadataId, + isSelected: true, + isMatchingSearchFilter: true, + })); - const pickableMorphItems = selectedTargetRecords.map((record) => ({ - recordId: record.recordId, - objectMetadataId: record.objectMetadataId, - isSelected: true, - isMatchingSearchFilter: true, - })); + store.set( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ + instanceId: recordPickerInstanceId, + }), + pickableMorphItems, + ); - set( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId: recordPickerInstanceId, - }), - pickableMorphItems, - ); + store.set( + multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( + { instanceId: recordPickerInstanceId }, + ), + searchableObjectMetadataItems, + ); - set( - multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( - { instanceId: recordPickerInstanceId }, - ), - searchableObjectMetadataItems, - ); + store.set( + multipleRecordPickerSearchFilterComponentState.atomFamily({ + instanceId: recordPickerInstanceId, + }), + '', + ); - set( - multipleRecordPickerSearchFilterComponentState.atomFamily({ - instanceId: recordPickerInstanceId, - }), - '', - ); + openMultipleRecordPicker(recordPickerInstanceId); - openMultipleRecordPicker(recordPickerInstanceId); + performSearch({ + multipleRecordPickerInstanceId: recordPickerInstanceId, + forceSearchFilter: '', + forceSearchableObjectMetadataItems: searchableObjectMetadataItems, + forcePickableMorphItems: pickableMorphItems, + }); - performSearch({ - multipleRecordPickerInstanceId: recordPickerInstanceId, - forceSearchFilter: '', - forceSearchableObjectMetadataItems: searchableObjectMetadataItems, - forcePickableMorphItems: pickableMorphItems, - }); - - pushFocusItemToFocusStack({ - focusId: recordPickerInstanceId, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: recordPickerInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - }, - [openMultipleRecordPicker, performSearch, pushFocusItemToFocusStack], + pushFocusItemToFocusStack({ + focusId: recordPickerInstanceId, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: recordPickerInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, + [openMultipleRecordPicker, performSearch, pushFocusItemToFocusStack, store], ); return { openJunctionRelationFieldInput }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/usePersistField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/usePersistField.ts index 29ea0aaf83..272dfb2f97 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/usePersistField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/usePersistField.ts @@ -1,4 +1,5 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { @@ -24,7 +25,7 @@ import { isFieldRawJson } from '@/object-record/record-field/ui/types/guards/isF import { isFieldRawJsonValue } from '@/object-record/record-field/ui/types/guards/isFieldRawJsonValue'; import { isFieldSelect } from '@/object-record/record-field/ui/types/guards/isFieldSelect'; import { isFieldSelectValue } from '@/object-record/record-field/ui/types/guards/isFieldSelectValue'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode'; @@ -67,211 +68,212 @@ export const usePersistField = ({ const { updateOneRecord } = useUpdateOneRecord(); + const store = useStore(); const { upsertRecordsInStore } = useUpsertRecordsInStore(); - const persistField = useRecoilCallback( - ({ set, snapshot }) => - async ({ - recordId, - fieldDefinition, - valueToPersist, - }: { - recordId: string; - fieldDefinition: FieldDefinition; - valueToPersist: unknown; - }) => { - const fieldIsRelationManyToOne = - isFieldRelationManyToOne( - fieldDefinition as FieldDefinition, - ) && isFieldRelationManyToOneValue(valueToPersist); + const persistField = useCallback( + async ({ + recordId, + fieldDefinition, + valueToPersist, + }: { + recordId: string; + fieldDefinition: FieldDefinition; + valueToPersist: unknown; + }) => { + const fieldIsRelationManyToOne = + isFieldRelationManyToOne( + fieldDefinition as FieldDefinition, + ) && isFieldRelationManyToOneValue(valueToPersist); - const fieldIsMorphRelationManyToOne = - isFieldMorphRelationManyToOne( - fieldDefinition as FieldDefinition, - ) && isFieldRelationManyToOneValue(valueToPersist); + const fieldIsMorphRelationManyToOne = + isFieldMorphRelationManyToOne( + fieldDefinition as FieldDefinition, + ) && isFieldRelationManyToOneValue(valueToPersist); - const fieldIsText = - isFieldText(fieldDefinition) && isFieldTextValue(valueToPersist); + const fieldIsText = + isFieldText(fieldDefinition) && isFieldTextValue(valueToPersist); - const fieldIsEmails = - isFieldEmails(fieldDefinition) && isFieldEmailsValue(valueToPersist); + const fieldIsEmails = + isFieldEmails(fieldDefinition) && isFieldEmailsValue(valueToPersist); - const fieldIsDateTime = - isFieldDateTime(fieldDefinition) && - isFieldDateTimeValue(valueToPersist); + const fieldIsDateTime = + isFieldDateTime(fieldDefinition) && + isFieldDateTimeValue(valueToPersist); - const fieldIsDate = - isFieldDate(fieldDefinition) && isFieldDateValue(valueToPersist); + const fieldIsDate = + isFieldDate(fieldDefinition) && isFieldDateValue(valueToPersist); - const fieldIsLinks = - isFieldLinks(fieldDefinition) && isFieldLinksValue(valueToPersist); + const fieldIsLinks = + isFieldLinks(fieldDefinition) && isFieldLinksValue(valueToPersist); - const fieldIsBoolean = - isFieldBoolean(fieldDefinition) && - isFieldBooleanValue(valueToPersist); + const fieldIsBoolean = + isFieldBoolean(fieldDefinition) && isFieldBooleanValue(valueToPersist); - const fieldIsRating = - isFieldRating(fieldDefinition) && isFieldRatingValue(valueToPersist); + const fieldIsRating = + isFieldRating(fieldDefinition) && isFieldRatingValue(valueToPersist); - const fieldIsNumber = - isFieldNumber(fieldDefinition) && isFieldNumberValue(valueToPersist); + const fieldIsNumber = + isFieldNumber(fieldDefinition) && isFieldNumberValue(valueToPersist); - const fieldIsCurrency = - isFieldCurrency(fieldDefinition) && - isFieldCurrencyValue(valueToPersist); + const fieldIsCurrency = + isFieldCurrency(fieldDefinition) && + isFieldCurrencyValue(valueToPersist); - const fieldIsFullName = - isFieldFullName(fieldDefinition) && - isFieldFullNameValue(valueToPersist); + const fieldIsFullName = + isFieldFullName(fieldDefinition) && + isFieldFullNameValue(valueToPersist); - const fieldIsPhones = - isFieldPhones(fieldDefinition) && isFieldPhonesValue(valueToPersist); + const fieldIsPhones = + isFieldPhones(fieldDefinition) && isFieldPhonesValue(valueToPersist); - const fieldIsSelect = - isFieldSelect(fieldDefinition) && isFieldSelectValue(valueToPersist); + const fieldIsSelect = + isFieldSelect(fieldDefinition) && isFieldSelectValue(valueToPersist); - const fieldIsMultiSelect = - isFieldMultiSelect(fieldDefinition) && - isFieldMultiSelectValue(valueToPersist); + const fieldIsMultiSelect = + isFieldMultiSelect(fieldDefinition) && + isFieldMultiSelectValue(valueToPersist); - const fieldIsAddress = - isFieldAddress(fieldDefinition) && - isFieldAddressValue(valueToPersist); + const fieldIsAddress = + isFieldAddress(fieldDefinition) && isFieldAddressValue(valueToPersist); - const fieldIsRawJson = - isFieldRawJson(fieldDefinition) && - isFieldRawJsonValue(valueToPersist); + const fieldIsRawJson = + isFieldRawJson(fieldDefinition) && isFieldRawJsonValue(valueToPersist); - const fieldIsRichText = - isFieldRichText(fieldDefinition) && - isFieldRichTextValue(valueToPersist); + const fieldIsRichText = + isFieldRichText(fieldDefinition) && + isFieldRichTextValue(valueToPersist); - const fieldIsRichTextV2 = - isFieldRichTextV2(fieldDefinition) && - isFieldRichTextV2Value(valueToPersist); + const fieldIsRichTextV2 = + isFieldRichTextV2(fieldDefinition) && + isFieldRichTextV2Value(valueToPersist); - const fieldIsArray = - isFieldArray(fieldDefinition) && isFieldArrayValue(valueToPersist); + const fieldIsArray = + isFieldArray(fieldDefinition) && isFieldArrayValue(valueToPersist); - const fieldIsFiles = - isFieldFiles(fieldDefinition) && isFieldFilesValue(valueToPersist); + const fieldIsFiles = + isFieldFiles(fieldDefinition) && isFieldFilesValue(valueToPersist); - const fieldIsUIReadOnly = - fieldDefinition.metadata.isUIReadOnly ?? false; + const fieldIsUIReadOnly = fieldDefinition.metadata.isUIReadOnly ?? false; - if (fieldIsRawJson && fieldIsUIReadOnly) { - return; - } + if (fieldIsRawJson && fieldIsUIReadOnly) { + return; + } - const isValuePersistable = - fieldIsMorphRelationManyToOne || - fieldIsRelationManyToOne || - fieldIsText || - fieldIsBoolean || - fieldIsEmails || - fieldIsRating || - fieldIsNumber || - fieldIsDateTime || - fieldIsDate || - fieldIsPhones || - fieldIsLinks || - fieldIsCurrency || - fieldIsFullName || - fieldIsSelect || - fieldIsMultiSelect || - fieldIsAddress || - fieldIsRawJson || - fieldIsArray || - fieldIsFiles || - fieldIsRichText || - fieldIsRichTextV2; + const isValuePersistable = + fieldIsMorphRelationManyToOne || + fieldIsRelationManyToOne || + fieldIsText || + fieldIsBoolean || + fieldIsEmails || + fieldIsRating || + fieldIsNumber || + fieldIsDateTime || + fieldIsDate || + fieldIsPhones || + fieldIsLinks || + fieldIsCurrency || + fieldIsFullName || + fieldIsSelect || + fieldIsMultiSelect || + fieldIsAddress || + fieldIsRawJson || + fieldIsArray || + fieldIsFiles || + fieldIsRichText || + fieldIsRichTextV2; - if (isValuePersistable) { - const fieldName = fieldDefinition.metadata.fieldName; + if (isValuePersistable) { + const fieldName = fieldDefinition.metadata.fieldName; - const currentValue: any = snapshot - .getLoadable(recordStoreFamilySelector({ recordId, fieldName })) - .getValue(); + const currentValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + ) as { id?: string } | null | undefined; - if (fieldIsRelationManyToOne) { - if (valueToPersist?.id === currentValue?.id) { - return; - } - - const newRecord = await updateOneRecord({ - objectNameSingular: objectMetadataItem.nameSingular, - idToUpdate: recordId, - updateOneRecordInput: { - [getForeignKeyNameFromRelationFieldName(fieldName)]: - valueToPersist?.id ?? null, - }, - }); - - upsertRecordsInStore({ - partialRecords: [ - getRecordFromRecordNode({ - recordNode: newRecord, - }), - ], - recordGqlFields: { - [getForeignKeyNameFromRelationFieldName(fieldName)]: true, - }, - }); + if (fieldIsRelationManyToOne) { + if (valueToPersist?.id === currentValue?.id) { return; } - if (fieldIsMorphRelationManyToOne) { - if (valueToPersist?.id === currentValue?.id) { - return; - } - - const newRecord = await updateOneRecord({ - objectNameSingular: objectMetadataItem.nameSingular, - idToUpdate: recordId, - updateOneRecordInput: { - [getForeignKeyNameFromRelationFieldName(fieldName)]: - valueToPersist?.id ?? null, - }, - }); - - upsertRecordsInStore({ - partialRecords: [ - getRecordFromRecordNode({ - recordNode: newRecord, - }), - ], - }); - - return; - } - - if (isDeeplyEqual(valueToPersist, currentValue)) { - return; - } - - updateOneRecord({ + const newRecord = await updateOneRecord({ objectNameSingular: objectMetadataItem.nameSingular, idToUpdate: recordId, updateOneRecordInput: { - [fieldName]: valueToPersist, + [getForeignKeyNameFromRelationFieldName(fieldName)]: + valueToPersist?.id ?? null, }, }); - set( - recordStoreFamilySelector({ recordId, fieldName }), - valueToPersist, - ); - } else { - throw new Error( - `Invalid value to persist: ${JSON.stringify( - valueToPersist, - )} for type : ${ - fieldDefinition.type - }, type may not be implemented in usePersistField.`, - ); + upsertRecordsInStore({ + partialRecords: [ + getRecordFromRecordNode({ + recordNode: newRecord, + }), + ], + recordGqlFields: { + [getForeignKeyNameFromRelationFieldName(fieldName)]: true, + }, + }); + return; } - }, - [objectMetadataItem?.nameSingular, updateOneRecord, upsertRecordsInStore], + + if (fieldIsMorphRelationManyToOne) { + if (valueToPersist?.id === currentValue?.id) { + return; + } + + const newRecord = await updateOneRecord({ + objectNameSingular: objectMetadataItem.nameSingular, + idToUpdate: recordId, + updateOneRecordInput: { + [getForeignKeyNameFromRelationFieldName(fieldName)]: + valueToPersist?.id ?? null, + }, + }); + + upsertRecordsInStore({ + partialRecords: [ + getRecordFromRecordNode({ + recordNode: newRecord, + }), + ], + }); + + return; + } + + if (isDeeplyEqual(valueToPersist, currentValue)) { + return; + } + + updateOneRecord({ + objectNameSingular: objectMetadataItem.nameSingular, + idToUpdate: recordId, + updateOneRecordInput: { + [fieldName]: valueToPersist, + }, + }); + + store.set( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + valueToPersist, + ); + } else { + throw new Error( + `Invalid value to persist: ${JSON.stringify( + valueToPersist, + )} for type : ${ + fieldDefinition.type + }, type may not be implemented in usePersistField.`, + ); + } + }, + [ + objectMetadataItem?.nameSingular, + store, + updateOneRecord, + upsertRecordsInStore, + ], ); return persistField; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useRecordFieldInput.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useRecordFieldInput.ts index 3e7d1b2117..eaa3af651d 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useRecordFieldInput.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useRecordFieldInput.ts @@ -1,18 +1,21 @@ import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; import { type FieldInputDraftValue } from '@/object-record/record-field/ui/types/FieldInputDraftValue'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useRecordFieldInput = () => { - const recordFieldInputDraftValueCallbackState = - useRecoilComponentCallbackState(recordFieldInputDraftValueComponentState); + const recordFieldInputDraftValueAtom = useRecoilComponentStateCallbackStateV2( + recordFieldInputDraftValueComponentState, + ); - const setDraftValue = useRecoilCallback( - ({ set }) => - (newValue: unknown) => { - set(recordFieldInputDraftValueCallbackState, newValue); - }, - [recordFieldInputDraftValueCallbackState], + const store = useStore(); + + const setDraftValue = useCallback( + (newValue: unknown) => { + store.set(recordFieldInputDraftValueAtom, newValue); + }, + [store, recordFieldInputDraftValueAtom], ); const isDraftValueEmpty = ( diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useToggleEditOnlyInput.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useToggleEditOnlyInput.ts index 0401970444..30191daa60 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useToggleEditOnlyInput.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useToggleEditOnlyInput.ts @@ -1,12 +1,12 @@ -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; - -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { useCallback, useContext } from 'react'; +import { useStore } from 'jotai'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { isFieldBoolean } from '@/object-record/record-field/ui/types/guards/isFieldBoolean'; export const useToggleEditOnlyInput = () => { + const store = useStore(); const { recordId, fieldDefinition, @@ -15,38 +15,34 @@ export const useToggleEditOnlyInput = () => { const [updateRecord] = useUpdateRecord(); - const toggleField = useRecoilCallback( - ({ set, snapshot }) => - () => { - const fieldIsBoolean = isFieldBoolean(fieldDefinition); + const toggleField = useCallback(() => { + const fieldIsBoolean = isFieldBoolean(fieldDefinition); - if (fieldIsBoolean) { - const fieldName = fieldDefinition.metadata.fieldName; - const oldValue = snapshot - .getLoadable(recordStoreFamilySelector({ recordId, fieldName })) - .getValue(); - const valueToPersist = !oldValue; - set( - recordStoreFamilySelector({ recordId, fieldName }), - valueToPersist, - ); + if (fieldIsBoolean) { + const fieldName = fieldDefinition.metadata.fieldName; + const oldValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + ) as boolean; + const valueToPersist = !oldValue; + store.set( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + valueToPersist, + ); - updateRecord?.({ - variables: { - where: { id: recordId }, - updateOneRecordInput: { - [fieldName]: valueToPersist, - }, - }, - }); - } else { - throw new Error( - `Invalid value to toggle for type : ${fieldDefinition}, type may not be implemented in useToggleEditOnlyInput.`, - ); - } - }, - [recordId, fieldDefinition, updateRecord], - ); + updateRecord?.({ + variables: { + where: { id: recordId }, + updateOneRecordInput: { + [fieldName]: valueToPersist, + }, + }, + }); + } else { + throw new Error( + `Invalid value to toggle for type : ${fieldDefinition}, type may not be implemented in useToggleEditOnlyInput.`, + ); + } + }, [recordId, fieldDefinition, store, updateRecord]); return toggleField; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useUpdateJunctionRelationFromCell.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useUpdateJunctionRelationFromCell.ts index f858ea67b1..50792f88eb 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useUpdateJunctionRelationFromCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useUpdateJunctionRelationFromCell.ts @@ -1,4 +1,5 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; @@ -20,7 +21,8 @@ import { getSourceJoinColumnName } from '@/object-record/record-field/ui/utils/j import { searchRecordStoreFamilyState } from '@/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { type SearchRecord } from '~/generated/graphql'; type UseUpdateJunctionRelationFromCellArgs = { fieldMetadataItem: FieldMetadataItem; @@ -66,129 +68,136 @@ export const useUpdateJunctionRelationFromCell = ({ objectNameSingular: junctionObjectNameSingular, }); - const updateJunctionRelationFromCell = useRecoilCallback( - ({ snapshot, set }) => - async ({ morphItem }: { morphItem: RecordPickerPickableMorphItem }) => { - const targetFields = junctionConfig?.targetFields; + const store = useStore(); + const updateJunctionRelationFromCell = useCallback( + async ({ morphItem }: { morphItem: RecordPickerPickableMorphItem }) => { + const targetFields = junctionConfig?.targetFields; - if ( - !isDefined(junctionObjectMetadata) || - !isDefined(sourceFieldOnJunction) || - !isDefined(targetFields) || - targetFields.length === 0 - ) { - return; - } + if ( + !isDefined(junctionObjectMetadata) || + !isDefined(sourceFieldOnJunction) || + !isDefined(targetFields) || + targetFields.length === 0 + ) { + return; + } - if (!isDefined(sourceObjectMetadata)) { - return; - } + if (!isDefined(sourceObjectMetadata)) { + return; + } - const sourceJoinColumnName = getSourceJoinColumnName({ - sourceField: sourceFieldOnJunction, - sourceObjectMetadata, + const sourceJoinColumnName = getSourceJoinColumnName({ + sourceField: sourceFieldOnJunction, + sourceObjectMetadata, + }); + + const fieldName = fieldDefinition.metadata.fieldName; + const junctionObjectName = junctionObjectMetadata.nameSingular; + + const targetFieldInfo = findTargetFieldInfo( + targetFields, + morphItem.objectMetadataId, + objectMetadataItems, + ); + + if (!isDefined(targetFieldInfo)) { + return; + } + + const targetFieldName = targetFieldInfo.fieldName; + const targetJoinColumnName = targetFieldInfo.joinColumnName; + + if ( + !isDefined(sourceJoinColumnName) || + !isDefined(targetJoinColumnName) + ) { + return; + } + + const recordFromStore = store.get( + recordStoreFamilyState.atomFamily(recordId), + ) as Record | null | undefined; + const currentJunctionRecords = + (recordFromStore?.[fieldName] as + | FieldRelationValue + | undefined) ?? []; + + // morphItem.isSelected represents the NEW state (what the user wants) + if (!morphItem.isSelected) { + const junctionRecordToDelete = findJunctionRecordByTargetId({ + junctionRecords: currentJunctionRecords, + targetRecordId: morphItem.recordId, + targetFieldName, }); - const fieldName = fieldDefinition.metadata.fieldName; - const junctionObjectName = junctionObjectMetadata.nameSingular; - - const targetFieldInfo = findTargetFieldInfo( - targetFields, - morphItem.objectMetadataId, - objectMetadataItems, - ); - - if (!isDefined(targetFieldInfo)) { + if (!isDefined(junctionRecordToDelete)) { return; } - const targetFieldName = targetFieldInfo.fieldName; - const targetJoinColumnName = targetFieldInfo.joinColumnName; + await deleteJunctionRecord(junctionRecordToDelete.id); + + const recordFromStoreForDelete = store.get( + recordStoreFamilyState.atomFamily(recordId), + ) as Record | null | undefined; + const currentFieldValue = recordFromStoreForDelete?.[fieldName] as + | FieldRelationValue + | undefined; if ( - !isDefined(sourceJoinColumnName) || - !isDefined(targetJoinColumnName) + !isDefined(currentFieldValue) || + !Array.isArray(currentFieldValue) ) { return; } - const currentJunctionRecords = - snapshot - .getLoadable< - FieldRelationValue - >(recordStoreFamilySelector({ recordId, fieldName })) - .getValue() ?? []; + const updatedJunctionRecords = currentFieldValue.filter( + (record) => record.id !== junctionRecordToDelete.id, + ); - // morphItem.isSelected represents the NEW state (what the user wants) - if (!morphItem.isSelected) { - const junctionRecordToDelete = findJunctionRecordByTargetId({ - junctionRecords: currentJunctionRecords, - targetRecordId: morphItem.recordId, - targetFieldName, - }); - - if (!isDefined(junctionRecordToDelete)) { - return; - } - - await deleteJunctionRecord(junctionRecordToDelete.id); - - const currentFieldValue = snapshot - .getLoadable< - FieldRelationValue - >(recordStoreFamilySelector({ recordId, fieldName })) - .getValue(); - - if ( - !isDefined(currentFieldValue) || - !Array.isArray(currentFieldValue) - ) { - return; - } - - const updatedJunctionRecords = currentFieldValue.filter( - (record) => record.id !== junctionRecordToDelete.id, - ); - - set(recordStoreFamilyState(recordId), (currentRecord) => { + store.set( + recordStoreFamilyState.atomFamily(recordId), + (currentRecord: Record | null | undefined) => { if (!isDefined(currentRecord)) { return currentRecord; } return { ...currentRecord, [fieldName]: updatedJunctionRecords, - }; - }); - } else { - const searchRecord = snapshot - .getLoadable(searchRecordStoreFamilyState(morphItem.recordId)) - .getValue(); + } as ObjectRecord; + }, + ); + } else { + const searchRecord = store.get( + searchRecordStoreFamilyState.atomFamily(morphItem.recordId), + ) as (SearchRecord & { record?: ObjectRecord }) | undefined; - if (!isDefined(searchRecord?.record)) { - return; - } + if (!isDefined(searchRecord?.record)) { + return; + } - const targetRecord = searchRecord.record; - const newJunctionId = v4(); - const now = new Date().toISOString(); + const targetRecord = searchRecord.record; + const newJunctionId = v4(); + const now = new Date().toISOString(); - const junctionRecordForStore = { - id: newJunctionId, - createdAt: now, - updatedAt: now, - __typename: getObjectTypename(junctionObjectName), - [sourceJoinColumnName]: recordId, - [targetJoinColumnName]: morphItem.recordId, - [targetFieldName]: targetRecord, - }; + const junctionRecordForStore = { + id: newJunctionId, + createdAt: now, + updatedAt: now, + __typename: getObjectTypename(junctionObjectName), + [sourceJoinColumnName]: recordId, + [targetJoinColumnName]: morphItem.recordId, + [targetFieldName]: targetRecord, + }; - const newJunctionRecordForApi = { - id: newJunctionId, - [sourceJoinColumnName]: recordId, - [targetJoinColumnName]: morphItem.recordId, - }; + const newJunctionRecordForApi = { + id: newJunctionId, + [sourceJoinColumnName]: recordId, + [targetJoinColumnName]: morphItem.recordId, + }; - set(recordStoreFamilyState(recordId), (currentRecord) => { + store.set( + recordStoreFamilyState.atomFamily(recordId), + (currentRecord: Record | null | undefined) => { if (!isDefined(currentRecord)) { return currentRecord; } @@ -201,13 +210,15 @@ export const useUpdateJunctionRelationFromCell = ({ return { ...currentRecord, [fieldName]: updatedJunctionRecords, - }; - }); + } as ObjectRecord; + }, + ); - await createJunctionRecord(newJunctionRecordForApi); - } - }, + await createJunctionRecord(newJunctionRecordForApi); + } + }, [ + store, createJunctionRecord, deleteJunctionRecord, fieldDefinition.metadata.fieldName, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx index f23862b79e..0319342845 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx @@ -1,12 +1,12 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { RelationFromManyFieldDisplay } from '@/object-record/record-field/ui/meta-types/display/components/RelationFromManyFieldDisplay'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; @@ -19,8 +19,9 @@ import { } from './relationFromManyFieldDisplayMock'; const RelationFieldValueSetterEffect = () => { - const setEntity = useSetRecoilState( - recordStoreFamilyState(relationFromManyFieldDisplayMock.entityValue.id), + const setEntity = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + relationFromManyFieldDisplayMock.entityValue.id, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddressField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddressField.ts index 1c7b14ee23..7b814f6451 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddressField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useAddressField.ts @@ -1,12 +1,12 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { type FieldAddressValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; @@ -23,16 +23,14 @@ export const useAddressField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useArrayField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useArrayField.ts index 45df25cc05..aed8a78d50 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useArrayField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useArrayField.ts @@ -4,10 +4,10 @@ import { recordFieldInputDraftValueComponentState } from '@/object-record/record import { type FieldArrayValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldArray } from '@/object-record/record-field/ui/types/guards/isFieldArray'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const useArrayField = () => { @@ -17,16 +17,14 @@ export const useArrayField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useBooleanField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useBooleanField.ts index a65a3de5ad..4179c7f7b4 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useBooleanField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useBooleanField.ts @@ -1,12 +1,12 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldBoolean } from '@/object-record/record-field/ui/types/guards/isFieldBoolean'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; export const useBooleanField = () => { const { recordId, fieldDefinition } = useContext(FieldContext); @@ -19,16 +19,16 @@ export const useBooleanField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); + const typedFieldValue = fieldValue as boolean; + return { fieldDefinition, - fieldValue, + fieldValue: typedFieldValue, setFieldValue, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useChipField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useChipField.ts index 1d8512b4af..60617e0496 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useChipField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useChipField.ts @@ -1,10 +1,9 @@ import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; - import { isFieldFullName } from '@/object-record/record-field/ui/types/guards/isFieldFullName'; import { isFieldNumber } from '@/object-record/record-field/ui/types/guards/isFieldNumber'; import { isFieldText } from '@/object-record/record-field/ui/types/guards/isFieldText'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; @@ -18,7 +17,7 @@ export const useChipField = () => { ? fieldDefinition.metadata.objectMetadataNameSingular : undefined; - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); return { objectNameSingular, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useCurrencyField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useCurrencyField.ts index 771b7ead68..6bf306afad 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useCurrencyField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useCurrencyField.ts @@ -1,5 +1,4 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; @@ -7,8 +6,9 @@ import { recordFieldInputDraftValueComponentState } from '@/object-record/record import { type FieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldCurrency } from '@/object-record/record-field/ui/types/guards/isFieldCurrency'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { DEFAULT_DECIMAL_VALUE } from '~/utils/format/formatNumber'; @@ -23,16 +23,14 @@ export const useCurrencyField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateField.ts index 029e11ce65..b76c39ffc1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateField.ts @@ -1,14 +1,14 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldDateValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldDate } from '@/object-record/record-field/ui/types/guards/isFieldDate'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; export const useDateField = () => { const { recordId, fieldDefinition, clearable } = useContext(FieldContext); @@ -17,18 +17,18 @@ export const useDateField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); + const typedFieldValue = fieldValue as string | null | undefined; + const { setDraftValue } = useRecordFieldInput(); return { fieldDefinition, - fieldValue, + fieldValue: typedFieldValue, setDraftValue, setFieldValue, clearable, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateTimeField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateTimeField.ts index cbda5c11d6..aa5e4d1e9f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateTimeField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useDateTimeField.ts @@ -1,14 +1,14 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldDateTimeValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldDateTime } from '@/object-record/record-field/ui/types/guards/isFieldDateTime'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; export const useDateTimeField = () => { const { recordId, fieldDefinition, clearable } = useContext(FieldContext); @@ -21,11 +21,9 @@ export const useDateTimeField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useEmailsField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useEmailsField.ts index 8c728ecb52..9f16d0011a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useEmailsField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useEmailsField.ts @@ -1,14 +1,14 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldEmailsValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldEmails } from '@/object-record/record-field/ui/types/guards/isFieldEmails'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; @@ -19,16 +19,14 @@ export const useEmailsField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFilesField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFilesField.ts index eb4bea3664..2b6e60674a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFilesField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFilesField.ts @@ -1,16 +1,16 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldFiles } from '@/object-record/record-field/ui/types/guards/isFieldFiles'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useFilesField = () => { const { recordId, fieldDefinition } = useContext(FieldContext); @@ -19,16 +19,14 @@ export const useFilesField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFullNameField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFullNameField.ts index 3243798815..26bf6f2482 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFullNameField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useFullNameField.ts @@ -1,5 +1,4 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; @@ -7,8 +6,9 @@ import { recordFieldInputDraftValueComponentState } from '@/object-record/record import { type FieldFullNameValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldFullName } from '@/object-record/record-field/ui/types/guards/isFieldFullName'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const useFullNameField = () => { @@ -22,16 +22,14 @@ export const useFullNameField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useJsonField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useJsonField.ts index 166eb6beff..d82b111de5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useJsonField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useJsonField.ts @@ -1,14 +1,14 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldJsonValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { usePrecomputedJsonDraftValue } from '@/object-record/record-field/ui/meta-types/hooks/usePrecomputedJsonDraftValue'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldRawJson } from '@/object-record/record-field/ui/types/guards/isFieldRawJson'; @@ -24,16 +24,14 @@ export const useJsonField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useLinksField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useLinksField.ts index 5cf9f29b8e..23a85a4eaa 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useLinksField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useLinksField.ts @@ -1,14 +1,14 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldLinksValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldLinks } from '@/object-record/record-field/ui/types/guards/isFieldLinks'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; @@ -19,16 +19,14 @@ export const useLinksField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationField.ts index 0d156daaf9..a9e597ca1e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationField.ts @@ -1,9 +1,8 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useGetButtonIcon } from '@/object-record/record-field/ui/hooks/useGetButtonIcon'; import { type FieldRelationValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; @@ -11,7 +10,8 @@ import { recordFieldInputDraftValueComponentState } from '@/object-record/record import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guards/isFieldMorphRelation'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useMorphRelationField = < T extends ObjectRecord | ObjectRecord[], @@ -27,11 +27,12 @@ export const useMorphRelationField = < const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState>( - recordStoreFamilySelector({ recordId, fieldName }), - ); + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, + ) as [FieldRelationValue, (value: FieldRelationValue) => void]; - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMultiSelectField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMultiSelectField.ts index 5d2d1c7526..9eb85d47f8 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMultiSelectField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMultiSelectField.ts @@ -1,5 +1,4 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; @@ -8,8 +7,9 @@ import { type FieldMultiSelectValue } from '@/object-record/record-field/ui/type import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldMultiSelect } from '@/object-record/record-field/ui/types/guards/isFieldMultiSelect'; import { isFieldMultiSelectValue } from '@/object-record/record-field/ui/types/guards/isFieldMultiSelectValue'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const useMultiSelectField = () => { @@ -23,11 +23,9 @@ export const useMultiSelectField = () => { const { fieldName } = fieldDefinition.metadata; - const [fieldValues, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValues, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const fieldMultiSelectValues = isFieldMultiSelectValue(fieldValues) @@ -36,7 +34,7 @@ export const useMultiSelectField = () => { const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useNumberField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useNumberField.ts index 56658eee3a..da6c0a13fd 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useNumberField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useNumberField.ts @@ -1,13 +1,13 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldNumberValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldNumber } from '@/object-record/record-field/ui/types/guards/isFieldNumber'; @@ -19,16 +19,14 @@ export const useNumberField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/usePhonesField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/usePhonesField.ts index f311a504d2..829bdf42cb 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/usePhonesField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/usePhonesField.ts @@ -1,14 +1,14 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; import { type FieldPhonesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldPhones } from '@/object-record/record-field/ui/types/guards/isFieldPhones'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; @@ -19,16 +19,14 @@ export const usePhonesField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts index 00b0d04d89..a4dbc506dc 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts @@ -1,13 +1,13 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { type FieldRatingValue } from 'twenty-shared/types'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldRating } from '@/object-record/record-field/ui/types/guards/isFieldRating'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; export const useRatingField = () => { const { recordId, fieldDefinition } = useContext(FieldContext); @@ -16,14 +16,12 @@ export const useRatingField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); - const rating = fieldValue ?? null; + const rating = (fieldValue ?? null) as FieldRatingValue | null; return { fieldDefinition, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRelationField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRelationField.ts index 3dc36ae7c4..c396bce26d 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRelationField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRelationField.ts @@ -1,9 +1,8 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useGetButtonIcon } from '@/object-record/record-field/ui/hooks/useGetButtonIcon'; import { type FieldRelationValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; @@ -11,7 +10,8 @@ import { recordFieldInputDraftValueComponentState } from '@/object-record/record import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useRelationField = () => { const { recordId, fieldDefinition, maxWidth } = useContext(FieldContext); @@ -25,11 +25,12 @@ export const useRelationField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState>( - recordStoreFamilySelector({ recordId, fieldName }), - ); + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, + ) as [FieldRelationValue, (value: FieldRelationValue) => void]; - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useSelectField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useSelectField.ts index 8ac8566975..de185646e3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useSelectField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useSelectField.ts @@ -1,12 +1,12 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { recordFieldInputDraftValueComponentState } from '@/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { type FieldSelectValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; @@ -20,18 +20,16 @@ export const useSelectField = () => { const { fieldName } = fieldDefinition.metadata; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const fieldSelectValue = isFieldSelectValue(fieldValue) ? fieldValue : null; const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useTextField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useTextField.ts index 84b23f80fd..6cac270173 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useTextField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useTextField.ts @@ -1,5 +1,4 @@ import { useContext } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useRecordFieldInput } from '@/object-record/record-field/ui/hooks/useRecordFieldInput'; @@ -8,8 +7,9 @@ import { type FieldTextValue } from '@/object-record/record-field/ui/types/Field import { assertFieldMetadata } from '@/object-record/record-field/ui/types/guards/assertFieldMetadata'; import { isFieldText } from '@/object-record/record-field/ui/types/guards/isFieldText'; import { isFieldTextValue } from '@/object-record/record-field/ui/types/guards/isFieldTextValue'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; export const useTextField = () => { @@ -19,17 +19,15 @@ export const useTextField = () => { const fieldName = fieldDefinition.metadata.fieldName; - const [fieldValue, setFieldValue] = useRecoilState( - recordStoreFamilySelector({ - recordId, - fieldName: fieldName, - }), + const [fieldValue, setFieldValue] = useFamilySelectorStateV2( + recordStoreFamilySelectorV2, + { recordId, fieldName }, ); const fieldTextValue = isFieldTextValue(fieldValue) ? fieldValue : ''; const { setDraftValue } = useRecordFieldInput(); - const draftValue = useRecoilComponentValue( + const draftValue = useRecoilComponentValueV2( recordFieldInputDraftValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/BooleanFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/BooleanFieldInput.tsx index 334026971d..d163e5a494 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/BooleanFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/BooleanFieldInput.tsx @@ -22,7 +22,7 @@ export const BooleanFieldInput = ({ testId }: BooleanFieldInputProps) => { return ( { index === 0 && emails.length > 1; const getShowSetAsPrimaryButton = (index: number) => index > 0; - const setIsFieldInError = useSetRecoilComponentState( + const setIsFieldInError = useSetRecoilComponentStateV2( recordFieldInputIsFieldInErrorComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx index 1e5c5dfe06..fff34a70d0 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx @@ -14,7 +14,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { filePreviewStateV2 } from '@/ui/field/display/states/filePreviewStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useLingui } from '@lingui/react/macro'; import { useCallback, useContext, useMemo, useState } from 'react'; import { MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES } from 'twenty-shared/constants'; @@ -122,7 +122,7 @@ export const FilesFieldInput = () => { fieldDefinition, ]); - const setIsFieldInError = useSetRecoilComponentState( + const setIsFieldInError = useSetRecoilComponentStateV2( recordFieldInputIsFieldInErrorComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/LinksFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/LinksFieldInput.tsx index b2b830bc6d..e568aff5a7 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/LinksFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/LinksFieldInput.tsx @@ -6,7 +6,7 @@ import { getFieldLinkDefinedLinks } from '@/object-record/record-field/ui/meta-t import { recordFieldInputIsFieldInErrorComponentState } from '@/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState'; import { type FieldLinksValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { linksSchema } from '@/object-record/record-field/ui/types/guards/isFieldLinksValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext, useMemo } from 'react'; import { MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES } from 'twenty-shared/constants'; import { absoluteUrlSchema, isDefined } from 'twenty-shared/utils'; @@ -57,7 +57,7 @@ export const LinksFieldInput = () => { const getShowPrimaryIcon = (index: number) => index === 0 && links.length > 1; const getShowSetAsPrimaryButton = (index: number) => index > 0; - const setIsFieldInError = useSetRecoilComponentState( + const setIsFieldInError = useSetRecoilComponentStateV2( recordFieldInputIsFieldInErrorComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationManyToOneFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationManyToOneFieldInput.tsx index f3184da7b2..cb9ffbe17f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationManyToOneFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationManyToOneFieldInput.tsx @@ -12,7 +12,7 @@ import { SingleRecordPicker } from '@/object-record/record-picker/single-record- import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconForbid } from 'twenty-ui/display'; @@ -63,11 +63,11 @@ export const MorphRelationManyToOneFieldInput = () => { onCancel?.(); }; - const layoutDirection = useRecoilComponentValue( + const layoutDirection = useRecoilComponentValueV2( recordFieldInputLayoutDirectionComponentState, ); - const isLoading = useRecoilComponentValue( + const isLoading = useRecoilComponentValueV2( recordFieldInputLayoutDirectionLoadingComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationOneToManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationOneToManyFieldInput.tsx index be242e7c1f..0c5537ac6e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationOneToManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MorphRelationOneToManyFieldInput.tsx @@ -7,7 +7,7 @@ import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/r import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const MorphRelationOneToManyFieldInput = () => { const instanceId = useAvailableComponentInstanceIdOrThrow( @@ -23,7 +23,7 @@ export const MorphRelationOneToManyFieldInput = () => { onSubmit?.({ skipPersist: true }); }; - const layoutDirection = useRecoilComponentValue( + const layoutDirection = useRecoilComponentValueV2( recordFieldInputLayoutDirectionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/PhonesFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/PhonesFieldInput.tsx index a95cbfa126..a648d24733 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/PhonesFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/PhonesFieldInput.tsx @@ -3,7 +3,7 @@ import { usePhonesField } from '@/object-record/record-field/ui/meta-types/hooks import { PhonesFieldMenuItem } from '@/object-record/record-field/ui/meta-types/input/components/PhonesFieldMenuItem'; import { recordFieldInputIsFieldInErrorComponentState } from '@/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState'; import { phoneSchema } from '@/object-record/record-field/ui/validation-schemas/phoneSchema'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { parsePhoneNumber, type E164Number } from 'libphonenumber-js'; import ReactPhoneNumberInput from 'react-phone-number-input'; @@ -128,7 +128,7 @@ export const PhonesFieldInput = () => { index === 0 && phones.length > 1; const getShowSetAsPrimaryButton = (index: number) => index > 0; - const setIsFieldInError = useSetRecoilComponentState( + const setIsFieldInError = useSetRecoilComponentStateV2( recordFieldInputIsFieldInErrorComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationManyToOneFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationManyToOneFieldInput.tsx index 768bbf9656..06c4758477 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationManyToOneFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationManyToOneFieldInput.tsx @@ -13,8 +13,8 @@ import { singleRecordPickerSelectedIdComponentState } from '@/object-record/reco import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useLingui } from '@lingui/react/macro'; import { useContext } from 'react'; import { CustomError, isDefined } from 'twenty-shared/utils'; @@ -77,15 +77,16 @@ export const RelationManyToOneFieldInput = () => { recordId, }); - const layoutDirection = useRecoilComponentValue( + const layoutDirection = useRecoilComponentValueV2( recordFieldInputLayoutDirectionComponentState, ); - const isLoading = useRecoilComponentValue( + const isLoading = useRecoilComponentValueV2( recordFieldInputLayoutDirectionLoadingComponentState, + instanceId, ); - const setSingleRecordPickerSelectedId = useSetRecoilComponentState( + const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, instanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationOneToManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationOneToManyFieldInput.tsx index 2573fff996..d268915ad2 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationOneToManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RelationOneToManyFieldInput.tsx @@ -1,5 +1,5 @@ -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useContext } from 'react'; +import { useStore } from 'jotai'; import { v4 } from 'uuid'; import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords'; @@ -30,13 +30,15 @@ import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-rec import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch'; import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { buildRecordLabelPayload } from '@/object-record/utils/buildRecordLabelPayload'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { CustomError, isDefined } from 'twenty-shared/utils'; export const RelationOneToManyFieldInput = () => { + const store = useStore(); const { fieldDefinition, recordId } = useContext(FieldContext); const instanceId = useAvailableComponentInstanceIdOrThrow( RecordFieldComponentInstanceContext, @@ -156,92 +158,93 @@ export const RelationOneToManyFieldInput = () => { relationFieldDefinition.metadata.relationObjectMetadataNameSingular, }); - const layoutDirection = useRecoilComponentValue( + const layoutDirection = useRecoilComponentValueV2( recordFieldInputLayoutDirectionComponentState, ); const multipleRecordPickerPickableMorphItemsCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( multipleRecordPickerPickableMorphItemsComponentState, instanceId, ); const { performSearch: multipleRecordPickerPerformSearch } = useMultipleRecordPickerPerformSearch(); - const handleCreateNew = useRecoilCallback( - ({ snapshot, set }) => - async (searchInput?: string) => { - const updatePickerState = ( - newRecordId: string, - targetObjectMetadataId: string, - searchableObjectMetadataItems: (typeof relationObjectMetadataItem)[], - ) => { - const currentMorphItems = snapshot - .getLoadable(multipleRecordPickerPickableMorphItemsCallbackState) - .getValue(); + const handleCreateNew = useCallback( + async (searchInput?: string) => { + const updatePickerState = ( + newRecordId: string, + targetObjectMetadataId: string, + searchableObjectMetadataItems: (typeof relationObjectMetadataItem)[], + ) => { + const currentMorphItems = store.get( + multipleRecordPickerPickableMorphItemsCallbackState, + ); - const newMorphItems = currentMorphItems.concat({ - recordId: newRecordId, - objectMetadataId: targetObjectMetadataId, - isSelected: true, - isMatchingSearchFilter: true, - }); + const newMorphItems = currentMorphItems.concat({ + recordId: newRecordId, + objectMetadataId: targetObjectMetadataId, + isSelected: true, + isMatchingSearchFilter: true, + }); - set( - multipleRecordPickerPickableMorphItemsCallbackState, - newMorphItems, - ); + store.set( + multipleRecordPickerPickableMorphItemsCallbackState, + newMorphItems, + ); - multipleRecordPickerPerformSearch({ - multipleRecordPickerInstanceId: instanceId, - forceSearchFilter: searchInput, - forceSearchableObjectMetadataItems: searchableObjectMetadataItems, - forcePickableMorphItems: newMorphItems, - }); - }; + multipleRecordPickerPerformSearch({ + multipleRecordPickerInstanceId: instanceId, + forceSearchFilter: searchInput, + forceSearchableObjectMetadataItems: searchableObjectMetadataItems, + forcePickableMorphItems: newMorphItems, + }); + }; - if ( - isJunctionRelation && - isDefined(junctionConfig) && - !isMorphJunction && - isDefined(junctionTargetObjectMetadata) - ) { - const { targetFields, sourceField } = junctionConfig; - const targetField = targetFields[0]; + if ( + isJunctionRelation && + isDefined(junctionConfig) && + !isMorphJunction && + isDefined(junctionTargetObjectMetadata) + ) { + const { targetFields, sourceField } = junctionConfig; + const targetField = targetFields[0]; - if (!targetField || !sourceField) { - return; - } + if (!targetField || !sourceField) { + return; + } - const sourceJoinColumnName = getSourceJoinColumnName({ - sourceField, - sourceObjectMetadata: objectMetadataItem, - }); + const sourceJoinColumnName = getSourceJoinColumnName({ + sourceField, + sourceObjectMetadata: objectMetadataItem, + }); - const targetJoinColumnName = getJoinColumnName(targetField.settings); + const targetJoinColumnName = getJoinColumnName(targetField.settings); - if (!sourceJoinColumnName || !targetJoinColumnName) { - return; - } + if (!sourceJoinColumnName || !targetJoinColumnName) { + return; + } - const newTargetId = v4(); - const targetPayload = buildRecordLabelPayload({ - id: newTargetId, - searchInput, - objectMetadataItem: junctionTargetObjectMetadata, - }); + const newTargetId = v4(); + const targetPayload = buildRecordLabelPayload({ + id: newTargetId, + searchInput, + objectMetadataItem: junctionTargetObjectMetadata, + }); - await createTargetRecord(targetPayload); + await createTargetRecord(targetPayload); - const newJunctionId = v4(); - const createdJunction = await createJunctionRecord({ - id: newJunctionId, - [sourceJoinColumnName]: recordId, - [targetJoinColumnName]: newTargetId, - }); + const newJunctionId = v4(); + const createdJunction = await createJunctionRecord({ + id: newJunctionId, + [sourceJoinColumnName]: recordId, + [targetJoinColumnName]: newTargetId, + }); - if (isDefined(createdJunction)) { - set(recordStoreFamilyState(recordId), (currentRecord) => { + if (isDefined(createdJunction)) { + store.set( + recordStoreFamilyState.atomFamily(recordId), + (currentRecord: ObjectRecord | null | undefined) => { if (!isDefined(currentRecord)) { return currentRecord; } @@ -250,25 +253,29 @@ export const RelationOneToManyFieldInput = () => { ? [...currentFieldValue, createdJunction] : [createdJunction]; - return { ...currentRecord, [fieldName]: updatedJunctionRecords }; - }); - } - - updatePickerState(newTargetId, junctionTargetObjectMetadata.id, [ - junctionTargetObjectMetadata, - ]); - return; + return { + ...currentRecord, + [fieldName]: updatedJunctionRecords, + } as ObjectRecord; + }, + ); } - const newRecordId = - await createNewRecordAndOpenRightDrawer?.(searchInput); + updatePickerState(newTargetId, junctionTargetObjectMetadata.id, [ + junctionTargetObjectMetadata, + ]); + return; + } - if (isDefined(newRecordId)) { - updatePickerState(newRecordId, relationObjectMetadataItem.id, [ - relationObjectMetadataItem, - ]); - } - }, + const newRecordId = + await createNewRecordAndOpenRightDrawer?.(searchInput); + + if (isDefined(newRecordId)) { + updatePickerState(newRecordId, relationObjectMetadataItem.id, [ + relationObjectMetadataItem, + ]); + } + }, [ createNewRecordAndOpenRightDrawer, createTargetRecord, @@ -284,6 +291,7 @@ export const RelationOneToManyFieldInput = () => { objectMetadataItem, recordId, relationObjectMetadataItem, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/ArrayFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/ArrayFieldInput.stories.tsx index f4d6d6acb6..3541bbea23 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/ArrayFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/ArrayFieldInput.stories.tsx @@ -31,7 +31,7 @@ const ArrayValueSetterEffect = ({ value }: { value: string[] }) => { const ArrayFieldValueGater = () => { const { fieldValue } = useArrayField(); - return fieldValue && ; + return fieldValue ? : null; }; type ArrayInputWithContextProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx index c64960e54e..cb403a0d7e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx @@ -1,9 +1,9 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { expect, userEvent, within } from 'storybook/test'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; @@ -23,7 +23,7 @@ const BooleanFieldValueSetterEffect = ({ value: boolean; recordId: string; }) => { - const setField = useSetRecoilState(recordStoreFamilyState(recordId)); + const setField = useSetFamilyRecoilStateV2(recordStoreFamilyState, recordId); useEffect(() => { setField({ id: recordId, Boolean: value, __typename: 'Person' }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx index 9bb129eba6..86be3cf205 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/DateTimeFieldInput.stories.tsx @@ -38,7 +38,7 @@ const DateFieldValueSetterEffect = ({ value }: { value: Date }) => { const DateFieldValueGater = () => { const { fieldValue } = useDateTimeField(); - return fieldValue && ; + return fieldValue ? : null; }; type DateFieldInputWithContextProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/EmailsFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/EmailsFieldInput.stories.tsx index 249b93cb13..da70fdb859 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/EmailsFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/EmailsFieldInput.stories.tsx @@ -34,7 +34,7 @@ const EmailValueSetterEffect = ({ value }: { value: FieldEmailsValue }) => { const EmailFieldValueGater = () => { const { fieldValue } = useEmailsField(); - return fieldValue && ; + return fieldValue ? : null; }; type EmailInputWithContextProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/LinksFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/LinksFieldInput.stories.tsx index 34317efe53..a6ac5c5f1d 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/LinksFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/LinksFieldInput.stories.tsx @@ -52,7 +52,7 @@ type LinksInputWithContextProps = { const LinksFieldValueGater = () => { const { fieldValue } = useLinksField(); - return fieldValue && ; + return fieldValue ? : null; }; const LinksInputWithContext = ({ diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/PhonesFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/PhonesFieldInput.stories.tsx index 3a6ca02a97..4cea464589 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/PhonesFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/PhonesFieldInput.stories.tsx @@ -31,7 +31,7 @@ const PhoneValueSetterEffect = ({ value }: { value: FieldPhonesValue }) => { const PhoneFieldValueGater = () => { const { fieldValue } = usePhonesField(); - return fieldValue && ; + return fieldValue ? : null; }; type PhoneInputWithContextProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationManyToOneFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationManyToOneFieldInput.stories.tsx index 9d36383a82..c1dc7ad851 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationManyToOneFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationManyToOneFieldInput.stories.tsx @@ -23,17 +23,18 @@ import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-r import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { RelationManyToOneFieldInput } from '@/object-record/record-field/ui/meta-types/input/components/RelationManyToOneFieldInput'; import { getFieldInputEventContextProviderWithJestMocks } from './utils/getFieldInputEventContextProviderWithJestMocks'; const RelationWorkspaceSetterEffect = () => { - const setRecordFieldInputLayoutDirectionLoading = useSetRecoilComponentState( - recordFieldInputLayoutDirectionLoadingComponentState, - 'relation-to-one-field-input-123-Relation', - ); + const setRecordFieldInputLayoutDirectionLoading = + useSetRecoilComponentStateV2( + recordFieldInputLayoutDirectionLoadingComponentState, + 'relation-to-one-field-input-123-Relation', + ); useEffect(() => { jotaiStore.set(currentWorkspaceState.atom, mockCurrentWorkspace); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationOneToManyFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationOneToManyFieldInput.stories.tsx index f0a56ade69..a893085e81 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationOneToManyFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RelationOneToManyFieldInput.stories.tsx @@ -1,6 +1,6 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { useEffect, useMemo } from 'react'; -import { useSetRecoilState } from 'recoil'; +import { useSetAtom } from 'jotai'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; @@ -20,7 +20,7 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldCont import { useOpenFieldInputEditMode } from '@/object-record/record-field/ui/hooks/useOpenFieldInputEditMode'; import { RelationOneToManyFieldInput } from '@/object-record/record-field/ui/meta-types/input/components/RelationOneToManyFieldInput'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { FieldMetadataType } from 'twenty-shared/types'; import { RelationType } from '~/generated-metadata/graphql'; @@ -55,8 +55,8 @@ const RelationOneToManyFieldInputWithContext = () => { [], ); - const setRecordStoreFieldValue = useSetRecoilState( - recordStoreFamilySelector({ + const setRecordStoreFieldValue = useSetAtom( + recordStoreFamilySelectorV2.selectorFamily({ fieldName: 'people', recordId: 'recordId', }), diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer.ts index bafe9b0366..1d237fcdd2 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer.ts @@ -1,4 +1,3 @@ -import { useSetRecoilState } from 'recoil'; import { v4 } from 'uuid'; import { SEARCH_QUERY } from '@/command-menu/graphql/queries/search'; @@ -11,6 +10,7 @@ import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState'; import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { buildRecordLabelPayload } from '@/object-record/utils/buildRecordLabelPayload'; import { getOperationName } from '@apollo/client/utilities'; import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils'; @@ -33,8 +33,8 @@ export const useAddNewRecordAndOpenRightDrawer = ({ relationFieldMetadataItem, recordId, }: useAddNewRecordAndOpenRightDrawerProps) => { - const setViewableRecordId = useSetRecoilState(viewableRecordIdState); - const setViewableRecordNameSingular = useSetRecoilState( + const setViewableRecordId = useSetRecoilStateV2(viewableRecordIdState); + const setViewableRecordNameSingular = useSetRecoilStateV2( viewableRecordNameSingularState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useMorphPersistManyToOne.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useMorphPersistManyToOne.ts index 1d57e9a59f..c744c4450a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useMorphPersistManyToOne.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useMorphPersistManyToOne.ts @@ -1,8 +1,9 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; @@ -21,82 +22,32 @@ export type MorphPersistManyToOneProps = { export const useMorphPersistManyToOne = ({ objectMetadataNameSingular, }: MorphPersistManyToOneProps) => { + const store = useStore(); const { objectMetadataItems } = useObjectMetadataItems(); const { updateOneRecord } = useUpdateOneRecord(); - const persistMorphManyToOne = useRecoilCallback( - ({ snapshot }) => - async ({ - recordId, + const persistMorphManyToOne = useCallback( + async ({ + recordId, + fieldDefinition, + valueToPersist, + targetObjectMetadataNameSingular, + }: { + recordId: string; + fieldDefinition: FieldDefinition; + valueToPersist: string | null | undefined; + targetObjectMetadataNameSingular?: string; + }) => { + assertFieldMetadata( + FieldMetadataType.MORPH_RELATION, + isFieldMorphRelation, fieldDefinition, - valueToPersist, - targetObjectMetadataNameSingular, - }: { - recordId: string; - fieldDefinition: FieldDefinition; - valueToPersist: string | null | undefined; - targetObjectMetadataNameSingular?: string; - }) => { - assertFieldMetadata( - FieldMetadataType.MORPH_RELATION, - isFieldMorphRelation, - fieldDefinition, - ); + ); - const fieldName = fieldDefinition.metadata.fieldName; - - if (!isDefined(valueToPersist)) { - const recordWithAllMorphObjectIdsToNull = - buildRecordWithAllMorphObjectIdsToNull({ - morphRelations: fieldDefinition.metadata.morphRelations, - fieldName, - relationType: fieldDefinition.metadata.relationType, - }); - - updateOneRecord?.({ - objectNameSingular: objectMetadataNameSingular, - idToUpdate: recordId, - updateOneRecordInput: recordWithAllMorphObjectIdsToNull, - }); - - return; - } - - const targetObjectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.nameSingular === - targetObjectMetadataNameSingular, - ); - - if (!isDefined(targetObjectMetadataItem)) { - throw new Error('Object metadata item not found'); - } - - const computedFieldName = computeMorphRelationFieldName({ - fieldName, - relationType: fieldDefinition.metadata.relationType, - targetObjectMetadataNameSingular: - targetObjectMetadataItem.nameSingular, - targetObjectMetadataNamePlural: targetObjectMetadataItem.namePlural, - }); - - const currentValue: unknown = snapshot - .getLoadable( - recordStoreFamilySelector({ - recordId, - fieldName: computedFieldName, - }), - ) - .getValue(); - - if ( - isDefined(currentValue) && - (currentValue as ObjectRecord).id === valueToPersist - ) { - return; - } + const fieldName = fieldDefinition.metadata.fieldName; + if (!isDefined(valueToPersist)) { const recordWithAllMorphObjectIdsToNull = buildRecordWithAllMorphObjectIdsToNull({ morphRelations: fieldDefinition.metadata.morphRelations, @@ -104,18 +55,64 @@ export const useMorphPersistManyToOne = ({ relationType: fieldDefinition.metadata.relationType, }); - updateOneRecord({ + updateOneRecord?.({ objectNameSingular: objectMetadataNameSingular, idToUpdate: recordId, - updateOneRecordInput: { - ...recordWithAllMorphObjectIdsToNull, - [`${computedFieldName}Id`]: valueToPersist, - }, + updateOneRecordInput: recordWithAllMorphObjectIdsToNull, }); return; - }, - [objectMetadataItems, updateOneRecord, objectMetadataNameSingular], + } + + const targetObjectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === targetObjectMetadataNameSingular, + ); + + if (!isDefined(targetObjectMetadataItem)) { + throw new Error('Object metadata item not found'); + } + + const computedFieldName = computeMorphRelationFieldName({ + fieldName, + relationType: fieldDefinition.metadata.relationType, + targetObjectMetadataNameSingular: targetObjectMetadataItem.nameSingular, + targetObjectMetadataNamePlural: targetObjectMetadataItem.namePlural, + }); + + const currentValue: unknown = store.get( + recordStoreFamilySelectorV2.selectorFamily({ + recordId, + fieldName: computedFieldName, + }), + ); + + if ( + isDefined(currentValue) && + (currentValue as ObjectRecord).id === valueToPersist + ) { + return; + } + + const recordWithAllMorphObjectIdsToNull = + buildRecordWithAllMorphObjectIdsToNull({ + morphRelations: fieldDefinition.metadata.morphRelations, + fieldName, + relationType: fieldDefinition.metadata.relationType, + }); + + updateOneRecord({ + objectNameSingular: objectMetadataNameSingular, + idToUpdate: recordId, + updateOneRecordInput: { + ...recordWithAllMorphObjectIdsToNull, + [`${computedFieldName}Id`]: valueToPersist, + }, + }); + + return; + }, + [objectMetadataItems, objectMetadataNameSingular, store, updateOneRecord], ); return { persistMorphManyToOne }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx index 187e2eef43..ceac0ab343 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx @@ -1,10 +1,9 @@ import { useFileUpload } from '@/file-upload/hooks/useFileUpload'; import { useUploadFilesFieldFile } from '@/object-record/record-field/ui/meta-types/hooks/useUploadFilesFieldFile'; import { uploadMultipleFiles } from '@/object-record/record-field/ui/meta-types/utils/uploadMultipleFiles'; -import { filesFieldUploadState } from '@/object-record/record-field/ui/states/filesFieldUploadState'; import { filesFieldUploadStateV2 } from '@/object-record/record-field/ui/states/filesFieldUploadStateV2'; import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState'; @@ -17,7 +16,7 @@ import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentTyp import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; import { useStore } from 'jotai'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; @@ -36,161 +35,85 @@ export const useOpenFilesFieldInput = () => { const { t } = useLingui(); const store = useStore(); - const openFilesFieldInput = useRecoilCallback( - ({ snapshot, set }) => - async ({ - fieldName, - fieldMetadataId, - recordId, - prefix, - updateRecord, - onClose, - fieldDefinition, - }: { - fieldName: string; - fieldMetadataId: string; - recordId: string; - prefix?: string; - updateRecord: (updateInput: Record) => void; - onClose?: () => void; - fieldDefinition?: { - metadata: { - settings?: { - maxNumberOfValues?: number; - }; + const openFilesFieldInput = useCallback( + async ({ + fieldName, + fieldMetadataId, + recordId, + prefix, + updateRecord, + onClose, + fieldDefinition, + }: { + fieldName: string; + fieldMetadataId: string; + recordId: string; + prefix?: string; + updateRecord: (updateInput: Record) => void; + onClose?: () => void; + fieldDefinition?: { + metadata: { + settings?: { + maxNumberOfValues?: number; }; }; - }) => { - const fieldValue = snapshot - .getLoadable( - recordStoreFamilySelector({ - recordId, - fieldName, - }), - ) - .getValue(); - - const instanceId = getRecordFieldInputInstanceId({ + }; + }) => { + const fieldValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName, - prefix, - }); + }), + ) as FieldFilesValue[]; - if (isDefined(fieldValue) && fieldValue.length > 0) { - pushFocusItemToFocusStack({ - focusId: instanceId, - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, - instanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - return; - } + const instanceId = getRecordFieldInputInstanceId({ + recordId, + fieldName, + prefix, + }); - const isTableContext = prefix === RECORD_TABLE_CELL_INPUT_ID_PREFIX; - - const maxNumberOfValues = - fieldDefinition?.metadata?.settings?.maxNumberOfValues ?? - MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES; - - const currentFileCount = isDefined(fieldValue) ? fieldValue.length : 0; - - set( - filesFieldUploadState({ recordId, fieldName }), - 'UPLOAD_WINDOW_OPEN', - ); - store.set( - filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), - 'UPLOAD_WINDOW_OPEN', - ); - - openFileUpload({ - multiple: true, - onUpload: async (selectedFiles: File[]) => { - if (selectedFiles.length + currentFileCount > maxNumberOfValues) { - enqueueErrorSnackBar({ - message: t`Cannot upload more than ${maxNumberOfValues} files`, - }); - - set(filesFieldUploadState({ recordId, fieldName }), null); - store.set( - filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), - null, - ); - - if (isTableContext && isDefined(recordTableId)) { - set( - recordTableCellEditModePositionComponentState.atomFamily({ - instanceId: recordTableId, - }), - null, - ); - goBackToPreviousDropdownFocusId(); - removeLastFocusItemFromFocusStackByComponentType({ - componentType: FocusComponentType.OPENED_FIELD_INPUT, - }); - } else { - onClose?.(); - } - return; - } - - set( - filesFieldUploadState({ recordId, fieldName }), - 'UPLOADING_FILE', - ); - store.set( - filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), - 'UPLOADING_FILE', - ); - - try { - const uploadedFiles = await uploadMultipleFiles( - selectedFiles, - fieldMetadataId, - uploadFile, - ); - - if (uploadedFiles.length > 0) { - updateRecord({ - [fieldName]: uploadedFiles, - }); - } - } finally { - set(filesFieldUploadState({ recordId, fieldName }), null); - store.set( - filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), - null, - ); - - if (isTableContext && isDefined(recordTableId)) { - set( - recordTableCellEditModePositionComponentState.atomFamily({ - instanceId: recordTableId, - }), - null, - ); - goBackToPreviousDropdownFocusId(); - removeLastFocusItemFromFocusStackByComponentType({ - componentType: FocusComponentType.OPENED_FIELD_INPUT, - }); - } else { - onClose?.(); - } - } + if (isDefined(fieldValue) && fieldValue.length > 0) { + pushFocusItemToFocusStack({ + focusId: instanceId, + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId, }, - onCancel: () => { - set(filesFieldUploadState({ recordId, fieldName }), null); + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + return; + } + + const isTableContext = prefix === RECORD_TABLE_CELL_INPUT_ID_PREFIX; + + const maxNumberOfValues = + fieldDefinition?.metadata?.settings?.maxNumberOfValues ?? + MULTI_ITEM_FIELD_DEFAULT_MAX_VALUES; + + const currentFileCount = isDefined(fieldValue) ? fieldValue.length : 0; + + store.set( + filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), + 'UPLOAD_WINDOW_OPEN', + ); + + openFileUpload({ + multiple: true, + onUpload: async (selectedFiles: File[]) => { + if (selectedFiles.length + currentFileCount > maxNumberOfValues) { + enqueueErrorSnackBar({ + message: t`Cannot upload more than ${maxNumberOfValues} files`, + }); + store.set( filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), null, ); if (isTableContext && isDefined(recordTableId)) { - set( + store.set( recordTableCellEditModePositionComponentState.atomFamily({ instanceId: recordTableId, }), @@ -203,9 +126,71 @@ export const useOpenFilesFieldInput = () => { } else { onClose?.(); } - }, - }); - }, + return; + } + + store.set( + filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), + 'UPLOADING_FILE', + ); + + try { + const uploadedFiles = await uploadMultipleFiles( + selectedFiles, + fieldMetadataId, + uploadFile, + ); + + if (uploadedFiles.length > 0) { + updateRecord({ + [fieldName]: uploadedFiles, + }); + } + } finally { + store.set( + filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), + null, + ); + + if (isTableContext && isDefined(recordTableId)) { + store.set( + recordTableCellEditModePositionComponentState.atomFamily({ + instanceId: recordTableId, + }), + null, + ); + goBackToPreviousDropdownFocusId(); + removeLastFocusItemFromFocusStackByComponentType({ + componentType: FocusComponentType.OPENED_FIELD_INPUT, + }); + } else { + onClose?.(); + } + } + }, + onCancel: () => { + store.set( + filesFieldUploadStateV2.atomFamily({ recordId, fieldName }), + null, + ); + + if (isTableContext && isDefined(recordTableId)) { + store.set( + recordTableCellEditModePositionComponentState.atomFamily({ + instanceId: recordTableId, + }), + null, + ); + goBackToPreviousDropdownFocusId(); + removeLastFocusItemFromFocusStackByComponentType({ + componentType: FocusComponentType.OPENED_FIELD_INPUT, + }); + } else { + onClose?.(); + } + }, + }); + }, [ openFileUpload, uploadFile, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationManyToOneFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationManyToOneFieldInput.tsx index 4aab804c35..0fe7e69338 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationManyToOneFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationManyToOneFieldInput.tsx @@ -6,85 +6,82 @@ import { } from '@/object-record/record-field/ui/types/FieldMetadata'; import { useSingleRecordPickerOpen } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen'; import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils'; export const useOpenMorphRelationManyToOneFieldInput = () => { + const store = useStore(); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); const { openSingleRecordPicker } = useSingleRecordPickerOpen(); - const openMorphRelationManyToOneFieldInput = useRecoilCallback( - ({ set, snapshot }) => - ({ - fieldDefinition, - recordId, - prefix, - }: { - fieldDefinition: FieldDefinition; - recordId: string; - prefix?: string; - }) => { - const potentielFieldNames = fieldDefinition.metadata.morphRelations.map( - (morphRelation) => { - return computeMorphRelationFieldName({ - fieldName: fieldDefinition.metadata.fieldName, - relationType: fieldDefinition.metadata.relationType, - targetObjectMetadataNameSingular: - morphRelation.targetObjectMetadata.nameSingular, - targetObjectMetadataNamePlural: - morphRelation.targetObjectMetadata.namePlural, - }); - }, - ); + const openMorphRelationManyToOneFieldInput = useCallback( + ({ + fieldDefinition, + recordId, + prefix, + }: { + fieldDefinition: FieldDefinition; + recordId: string; + prefix?: string; + }) => { + const potentielFieldNames = fieldDefinition.metadata.morphRelations.map( + (morphRelation) => { + return computeMorphRelationFieldName({ + fieldName: fieldDefinition.metadata.fieldName, + relationType: fieldDefinition.metadata.relationType, + targetObjectMetadataNameSingular: + morphRelation.targetObjectMetadata.nameSingular, + targetObjectMetadataNamePlural: + morphRelation.targetObjectMetadata.namePlural, + }); + }, + ); - const fieldValue = potentielFieldNames - .map((fieldName) => { - const fieldValue = snapshot - .getLoadable>( - recordStoreFamilySelector({ - recordId, - fieldName, - }), - ) - .getValue(); - - return fieldValue; - }) - .find((fieldValue) => isDefined(fieldValue)); - - const recordPickerInstanceId = getRecordFieldInputInstanceId({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - prefix, - }); - - if (isDefined(fieldValue)) { - set( - singleRecordPickerSelectedIdComponentState.atomFamily({ - instanceId: recordPickerInstanceId, + const fieldValue = potentielFieldNames + .map((fieldName) => { + return store.get( + recordStoreFamilySelectorV2.selectorFamily({ + recordId, + fieldName, }), - fieldValue.id, - ); - } + ) as FieldRelationValue; + }) + .find((fieldValue) => isDefined(fieldValue)); - openSingleRecordPicker(recordPickerInstanceId); + const recordPickerInstanceId = getRecordFieldInputInstanceId({ + recordId, + fieldName: fieldDefinition.metadata.fieldName, + prefix, + }); - pushFocusItemToFocusStack({ - focusId: recordPickerInstanceId, - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, + if (isDefined(fieldValue)) { + store.set( + singleRecordPickerSelectedIdComponentState.atomFamily({ instanceId: recordPickerInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - }, - [openSingleRecordPicker, pushFocusItemToFocusStack], + }), + fieldValue.id, + ); + } + + openSingleRecordPicker(recordPickerInstanceId); + + pushFocusItemToFocusStack({ + focusId: recordPickerInstanceId, + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId: recordPickerInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, + [openSingleRecordPicker, pushFocusItemToFocusStack, store], ); return { openMorphRelationManyToOneFieldInput }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationOneToManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationOneToManyFieldInput.tsx index bff9d7e275..b53ddfda99 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationOneToManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationOneToManyFieldInput.tsx @@ -1,5 +1,6 @@ +import { useStore } from 'jotai'; + import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldMorphRelationMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; @@ -10,133 +11,131 @@ import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-r import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { recordStoreMorphOneToManyValueWithObjectNameFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector'; +import { recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { type ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const useOpenMorphRelationOneToManyFieldInput = () => { + const store = useStore(); const { performSearch } = useMultipleRecordPickerPerformSearch(); const { openMultipleRecordPicker } = useMultipleRecordPickerOpen(); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); - const openMorphRelationOneToManyFieldInput = useRecoilCallback( - ({ set, snapshot }) => - ({ + const openMorphRelationOneToManyFieldInput = useCallback( + ({ + recordId, + prefix, + fieldDefinition, + }: { + recordId: string; + prefix?: string; + fieldDefinition: FieldDefinition; + }) => { + const recordPickerInstanceId = getRecordFieldInputInstanceId({ recordId, + fieldName: fieldDefinition.metadata.fieldName, prefix, - fieldDefinition, - }: { - recordId: string; - prefix?: string; - fieldDefinition: FieldDefinition; - }) => { - const recordPickerInstanceId = getRecordFieldInputInstanceId({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - prefix, - }); + }); - const objectNameSingulars = fieldDefinition.metadata.morphRelations.map( - ({ targetObjectMetadata }) => targetObjectMetadata.nameSingular, - ); + const objectNameSingulars = fieldDefinition.metadata.morphRelations.map( + ({ targetObjectMetadata }) => targetObjectMetadata.nameSingular, + ); - const morphValuesWithObjectNameSingularFieldValue = snapshot - .getLoadable( - recordStoreMorphOneToManyValueWithObjectNameFamilySelector({ - recordId, - morphRelations: fieldDefinition.metadata.morphRelations, - }), - ) - .getValue(); - - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); - - const objectMetadataItemArray = objectMetadataItems.filter( - (objectMetadataItem) => - objectNameSingulars.includes(objectMetadataItem.nameSingular), - ); - - if ( - !isDefined(objectMetadataItemArray) || - objectMetadataItemArray.length === 0 - ) { - return; - } - - openMultipleRecordPicker(recordPickerInstanceId); - - const pickableMorphItems: RecordPickerPickableMorphItem[] = - morphValuesWithObjectNameSingularFieldValue.flatMap( - (recordWithObjectNameSingular) => { - const objectMetadataItem = objectMetadataItemArray.find( - (objectMetadataItem) => - objectMetadataItem.nameSingular === - recordWithObjectNameSingular.objectNameSingular, - ); - - if (!objectMetadataItem) { - return []; - } - - return recordWithObjectNameSingular.value.map( - (recordValue: ObjectRecord) => ({ - objectMetadataId: objectMetadataItem.id, - recordId: recordValue.id, - isSelected: true, - isMatchingSearchFilter: true, - }), - ); - }, - ); - - const records = morphValuesWithObjectNameSingularFieldValue.flatMap( - (recordWithObjectNameSingular) => recordWithObjectNameSingular.value, - ); - - for (const record of records) { - set(recordStoreFamilyState(record.id), record); - } - - set( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId: recordPickerInstanceId, - }), - pickableMorphItems, - ); - - set( - multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( - { instanceId: recordPickerInstanceId }, - ), - objectMetadataItemArray, - ); - - performSearch({ - multipleRecordPickerInstanceId: recordPickerInstanceId, - forceSearchFilter: '', - forceSearchableObjectMetadataItems: objectMetadataItemArray, - forcePickableMorphItems: pickableMorphItems, - }); - - pushFocusItemToFocusStack({ - focusId: recordPickerInstanceId, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: recordPickerInstanceId, + const morphValuesWithObjectNameSingularFieldValue = store.get( + recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2.selectorFamily( + { + recordId, + morphRelations: fieldDefinition.metadata.morphRelations, }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, + ), + ); + + const objectMetadataItems = store.get(objectMetadataItemsState.atom); + + const objectMetadataItemArray = objectMetadataItems.filter( + (objectMetadataItem) => + objectNameSingulars.includes(objectMetadataItem.nameSingular), + ); + + if ( + !isDefined(objectMetadataItemArray) || + objectMetadataItemArray.length === 0 + ) { + return; + } + + openMultipleRecordPicker(recordPickerInstanceId); + + const pickableMorphItems: RecordPickerPickableMorphItem[] = + morphValuesWithObjectNameSingularFieldValue.flatMap( + (recordWithObjectNameSingular) => { + const objectMetadataItem = objectMetadataItemArray.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === + recordWithObjectNameSingular.objectNameSingular, + ); + + if (!objectMetadataItem) { + return []; + } + + return recordWithObjectNameSingular.value.map( + (recordValue: ObjectRecord) => ({ + objectMetadataId: objectMetadataItem.id, + recordId: recordValue.id, + isSelected: true, + isMatchingSearchFilter: true, + }), + ); }, - }); - }, - [openMultipleRecordPicker, performSearch, pushFocusItemToFocusStack], + ); + + const records = morphValuesWithObjectNameSingularFieldValue.flatMap( + (recordWithObjectNameSingular) => recordWithObjectNameSingular.value, + ); + + for (const record of records) { + store.set(recordStoreFamilyState.atomFamily(record.id), record); + } + + store.set( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ + instanceId: recordPickerInstanceId, + }), + pickableMorphItems, + ); + + store.set( + multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( + { instanceId: recordPickerInstanceId }, + ), + objectMetadataItemArray, + ); + + performSearch({ + multipleRecordPickerInstanceId: recordPickerInstanceId, + forceSearchFilter: '', + forceSearchableObjectMetadataItems: objectMetadataItemArray, + forcePickableMorphItems: pickableMorphItems, + }); + + pushFocusItemToFocusStack({ + focusId: recordPickerInstanceId, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: recordPickerInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, + [store, openMultipleRecordPicker, performSearch, pushFocusItemToFocusStack], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationFromManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationFromManyFieldInput.tsx index ab3f6d2078..1861b95d1a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationFromManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationFromManyFieldInput.tsx @@ -8,111 +8,105 @@ import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-pic import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; +import { useStore } from 'jotai'; + import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; export const useOpenRelationFromManyFieldInput = () => { + const store = useStore(); const { performSearch } = useMultipleRecordPickerPerformSearch(); const { openMultipleRecordPicker } = useMultipleRecordPickerOpen(); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); - const openRelationFromManyFieldInput = useRecoilCallback( - ({ set, snapshot }) => - ({ - fieldName, - objectNameSingular, + const openRelationFromManyFieldInput = useCallback( + ({ + fieldName, + objectNameSingular, + recordId, + prefix, + }: { + fieldName: string; + objectNameSingular: string; + recordId: string; + prefix?: string; + }) => { + const recordPickerInstanceId = getRecordFieldInputInstanceId({ recordId, + fieldName, prefix, - }: { - fieldName: string; - objectNameSingular: string; - recordId: string; - prefix?: string; - }) => { - const recordPickerInstanceId = getRecordFieldInputInstanceId({ - recordId, - fieldName, - prefix, + }); + + const fieldValue = + (store.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + ) as FieldRelationValue) ?? []; + + const objectMetadataItems = store.get(objectMetadataItemsState.atom); + + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ); + + if (!objectMetadataItem) { + return; + } + + openMultipleRecordPicker(recordPickerInstanceId); + + const pickableMorphItems: RecordPickerPickableMorphItem[] = + fieldValue.map((record) => { + return { + objectMetadataId: objectMetadataItem.id, + recordId: record.id, + isSelected: true, + isMatchingSearchFilter: true, + }; }); - const fieldValue = - snapshot - .getLoadable>( - recordStoreFamilySelector({ - recordId, - fieldName, - }), - ) - .getValue() ?? []; + for (const record of fieldValue) { + store.set(recordStoreFamilyState.atomFamily(record.id), record); + } - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + store.set( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ + instanceId: recordPickerInstanceId, + }), + pickableMorphItems, + ); - const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.nameSingular === objectNameSingular, - ); + store.set( + multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( + { instanceId: recordPickerInstanceId }, + ), + [objectMetadataItem], + ); - if (!objectMetadataItem) { - return; - } + performSearch({ + multipleRecordPickerInstanceId: recordPickerInstanceId, + forceSearchFilter: '', + forceSearchableObjectMetadataItems: [objectMetadataItem], + forcePickableMorphItems: pickableMorphItems, + }); - openMultipleRecordPicker(recordPickerInstanceId); - - const pickableMorphItems: RecordPickerPickableMorphItem[] = - fieldValue.map((record) => { - return { - objectMetadataId: objectMetadataItem.id, - recordId: record.id, - isSelected: true, - isMatchingSearchFilter: true, - }; - }); - - for (const record of fieldValue) { - set(recordStoreFamilyState(record.id), record); - } - - set( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId: recordPickerInstanceId, - }), - pickableMorphItems, - ); - - set( - multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( - { instanceId: recordPickerInstanceId }, - ), - [objectMetadataItem], - ); - - performSearch({ - multipleRecordPickerInstanceId: recordPickerInstanceId, - forceSearchFilter: '', - forceSearchableObjectMetadataItems: [objectMetadataItem], - forcePickableMorphItems: pickableMorphItems, - }); - - pushFocusItemToFocusStack({ - focusId: recordPickerInstanceId, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: recordPickerInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - }, - [openMultipleRecordPicker, performSearch, pushFocusItemToFocusStack], + pushFocusItemToFocusStack({ + focusId: recordPickerInstanceId, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: recordPickerInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, + [store, openMultipleRecordPicker, performSearch, pushFocusItemToFocusStack], ); return { openRelationFromManyFieldInput }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationToOneFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationToOneFieldInput.tsx index da60667b18..0cea6165aa 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationToOneFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenRelationToOneFieldInput.tsx @@ -4,65 +4,61 @@ import { } from '@/object-record/record-field/ui/types/FieldMetadata'; import { useSingleRecordPickerOpen } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen'; import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useOpenRelationToOneFieldInput = () => { + const store = useStore(); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); const { openSingleRecordPicker } = useSingleRecordPickerOpen(); - const openRelationToOneFieldInput = useRecoilCallback( - ({ set, snapshot }) => - ({ - fieldName, + const openRelationToOneFieldInput = useCallback( + ({ + fieldName, + recordId, + prefix, + }: { + fieldName: string; + recordId: string; + prefix?: string; + }) => { + const recordPickerInstanceId = getRecordFieldInputInstanceId({ recordId, + fieldName, prefix, - }: { - fieldName: string; - recordId: string; - prefix?: string; - }) => { - const recordPickerInstanceId = getRecordFieldInputInstanceId({ - recordId, - fieldName, - prefix, - }); - const fieldValue = snapshot - .getLoadable>( - recordStoreFamilySelector({ - recordId, - fieldName, - }), - ) - .getValue(); + }); + const fieldValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName }), + ) as FieldRelationValue; - if (isDefined(fieldValue)) { - set( - singleRecordPickerSelectedIdComponentState.atomFamily({ - instanceId: recordPickerInstanceId, - }), - fieldValue.id, - ); - } - - openSingleRecordPicker(recordPickerInstanceId); - - pushFocusItemToFocusStack({ - focusId: recordPickerInstanceId, - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, + if (isDefined(fieldValue)) { + store.set( + singleRecordPickerSelectedIdComponentState.atomFamily({ instanceId: recordPickerInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - }, - [openSingleRecordPicker, pushFocusItemToFocusStack], + }), + fieldValue.id, + ); + } + + openSingleRecordPicker(recordPickerInstanceId); + + pushFocusItemToFocusStack({ + focusId: recordPickerInstanceId, + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId: recordPickerInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, + [openSingleRecordPicker, pushFocusItemToFocusStack, store], ); return { openRelationToOneFieldInput }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateMorphRelationOneToManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateMorphRelationOneToManyFieldInput.tsx index 3b87315f3e..ffa5104ced 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateMorphRelationOneToManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateMorphRelationOneToManyFieldInput.tsx @@ -1,5 +1,4 @@ -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useContext } from 'react'; import { useRecordOneToManyFieldAttachTargetRecord } from '@/object-record/hooks/useRecordOneToManyFieldAttachTargetRecord'; import { useRecordOneToManyFieldDetachTargetRecord } from '@/object-record/hooks/useRecordOneToManyFieldDetachTargetRecord'; @@ -29,51 +28,48 @@ export const useUpdateMorphRelationOneToManyFieldInput = () => { const { recordOneToManyFieldAttachTargetRecord } = useRecordOneToManyFieldAttachTargetRecord(); - const updateMorphRelationOneToMany = useRecoilCallback( - () => - async ( - morphItem: Pick< - RecordPickerPickableMorphItem, - 'recordId' | 'isSelected' | 'objectMetadataId' - >, - ) => { - if (!fieldDefinition.metadata.objectMetadataNameSingular) { - throw new Error('ObjectMetadataNameSingular is required'); - } + const updateMorphRelationOneToMany = useCallback( + async ( + morphItem: Pick< + RecordPickerPickableMorphItem, + 'recordId' | 'isSelected' | 'objectMetadataId' + >, + ) => { + if (!fieldDefinition.metadata.objectMetadataNameSingular) { + throw new Error('ObjectMetadataNameSingular is required'); + } - const targetMorphRelation = - fieldDefinition.metadata.morphRelations.find( - (morphRelation) => - morphRelation.targetObjectMetadata.id === - morphItem.objectMetadataId, - ); + const targetMorphRelation = fieldDefinition.metadata.morphRelations.find( + (morphRelation) => + morphRelation.targetObjectMetadata.id === morphItem.objectMetadataId, + ); - if (!isDefined(targetMorphRelation)) { - throw new Error('TargetMorphRelation is required'); - } + if (!isDefined(targetMorphRelation)) { + throw new Error('TargetMorphRelation is required'); + } - if (morphItem.isSelected) { - await recordOneToManyFieldAttachTargetRecord({ - sourceObjectNameSingular: - fieldDefinition.metadata.objectMetadataNameSingular, - targetObjectNameSingular: - targetMorphRelation.targetObjectMetadata.nameSingular, - targetGQLFieldName: targetMorphRelation.targetFieldMetadata.name, - sourceRecordId: recordId, - targetRecordId: morphItem.recordId, - }); - } else { - await recordOneToManyFieldDetachTargetRecord({ - sourceObjectNameSingular: - fieldDefinition.metadata.objectMetadataNameSingular, - targetObjectNameSingular: - targetMorphRelation.targetObjectMetadata.nameSingular, - targetGQLFieldName: targetMorphRelation.targetFieldMetadata.name, - sourceRecordId: recordId, - targetRecordId: morphItem.recordId, - }); - } - }, + if (morphItem.isSelected) { + await recordOneToManyFieldAttachTargetRecord({ + sourceObjectNameSingular: + fieldDefinition.metadata.objectMetadataNameSingular, + targetObjectNameSingular: + targetMorphRelation.targetObjectMetadata.nameSingular, + targetGQLFieldName: targetMorphRelation.targetFieldMetadata.name, + sourceRecordId: recordId, + targetRecordId: morphItem.recordId, + }); + } else { + await recordOneToManyFieldDetachTargetRecord({ + sourceObjectNameSingular: + fieldDefinition.metadata.objectMetadataNameSingular, + targetObjectNameSingular: + targetMorphRelation.targetObjectMetadata.nameSingular, + targetGQLFieldName: targetMorphRelation.targetFieldMetadata.name, + sourceRecordId: recordId, + targetRecordId: morphItem.recordId, + }); + } + }, [ fieldDefinition.metadata.morphRelations, fieldDefinition.metadata.objectMetadataNameSingular, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateRelationOneToManyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateRelationOneToManyFieldInput.tsx index 1c1256ea3d..fe60fd9ea0 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateRelationOneToManyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useUpdateRelationOneToManyFieldInput.tsx @@ -1,5 +1,4 @@ -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useContext } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useRecordOneToManyFieldAttachTargetRecord } from '@/object-record/hooks/useRecordOneToManyFieldAttachTargetRecord'; @@ -49,8 +48,8 @@ export const useUpdateRelationOneToManyFieldInput = () => { const { recordOneToManyFieldAttachTargetRecord } = useRecordOneToManyFieldAttachTargetRecord(); - const updateRelation = useRecoilCallback( - () => async (morphItem: RecordPickerPickableMorphItem) => { + const updateRelation = useCallback( + async (morphItem: RecordPickerPickableMorphItem) => { if ( !fieldDefinition.metadata?.relationObjectMetadataNameSingular || !fieldDefinition.metadata?.targetFieldMetadataName diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts deleted file mode 100644 index 05fa715e28..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { atomFamily } from 'recoil'; - -type FilesFieldUploadStateKey = { - recordId: string; - fieldName: string; -}; - -type FilesFieldUploadState = 'UPLOAD_WINDOW_OPEN' | 'UPLOADING_FILE' | null; - -export const filesFieldUploadState = atomFamily< - FilesFieldUploadState, - FilesFieldUploadStateKey ->({ - key: 'filesFieldUploadState', - default: null, -}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/lastShowPageRecordId.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/lastShowPageRecordId.ts index c6732a56a5..0615d32dd9 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/states/lastShowPageRecordId.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/states/lastShowPageRecordId.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const lastShowPageRecordIdState = createState({ +export const lastShowPageRecordIdState = createStateV2({ key: 'lastShowPageRecordIdState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState.ts index 93f12a35a5..ff5419a1e1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputDraftValueComponentState.ts @@ -1,8 +1,8 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordFieldInputDraftValueComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordFieldInputDraftValueComponentState', defaultValue: undefined, componentInstanceContext: RecordFieldComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState.ts index bd53f9b3cb..86ee932b85 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputIsFieldInErrorComponentState.ts @@ -1,8 +1,8 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordFieldInputIsFieldInErrorComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordFieldInputIsFieldInErrorComponentState', defaultValue: false, componentInstanceContext: RecordFieldComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionComponentState.ts index 6a81beca02..6b5fb7aa13 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionComponentState.ts @@ -1,9 +1,9 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; import { type FieldInputLayoutDirection } from '@/object-record/record-field/ui/types/FieldInputLayoutDirection'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordFieldInputLayoutDirectionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordFieldInputLayoutDirectionComponentState', defaultValue: 'upward', componentInstanceContext: RecordFieldComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionLoadingComponentState.ts index 04037ced44..f321e8b8c1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/states/recordFieldInputLayoutDirectionLoadingComponentState.ts @@ -1,8 +1,8 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordFieldInputLayoutDirectionLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordFieldInputLayoutDirectionLoadingComponentState', defaultValue: true, componentInstanceContext: RecordFieldComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx index 6ac1b321a7..5d2b9f57c6 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx @@ -1,24 +1,36 @@ import { renderHook } from '@testing-library/react'; - -import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; -import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { act } from 'react'; -import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; + import { useRemoveRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup'; import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup'; +import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; +import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; +import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; +import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -const Wrapper = getJestMetadataAndApolloMocksWrapper({ +const BaseWrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks: [], }); +const Wrapper = ({ children }: { children: React.ReactNode }) => ( + + + {children} + + +); + describe('useRemoveRecordFilterGroup', () => { it('should remove an existing record filter group', () => { const { result } = renderHook( () => { - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'test', ); const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup(); @@ -60,8 +72,9 @@ describe('useRemoveRecordFilterGroup', () => { it('should not modify record filter groups when trying to remove a non-existent record filter group', () => { const { result } = renderHook( () => { - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'test', ); const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup(); diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx index 5758fe0a37..5daf309b38 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx @@ -2,22 +2,34 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup'; +import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -const Wrapper = getJestMetadataAndApolloMocksWrapper({ +const BaseWrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks: [], }); +const Wrapper = ({ children }: { children: React.ReactNode }) => ( + + + {children} + + +); + describe('useUpsertRecordFilterGroup', () => { it('should add a new record filter group', () => { const { result } = renderHook( () => { - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'test', ); const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup(); @@ -48,8 +60,9 @@ describe('useUpsertRecordFilterGroup', () => { it('should update an existing record filter group', () => { const { result } = renderHook( () => { - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'test', ); const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup(); diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup.ts b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup.ts index 4376c0a403..615741ec55 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup.ts @@ -1,61 +1,51 @@ import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; export const useRemoveRecordFilterGroup = () => { - const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState(currentRecordFilterGroupsComponentState); + const currentRecordFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + ); + const store = useStore(); const { onUpdate } = useContext(AdvancedFilterContext); - const removeRecordFilterGroupCallback = useRecoilCallback( - ({ set, snapshot }) => - (recordFilterGroupIdToRemove: string) => { - const currentRecordFilterGroups = getSnapshotValue( - snapshot, - currentRecordFilterGroupsCallbackState, - ); + const removeRecordFilterGroupCallback = ( + recordFilterGroupIdToRemove: string, + ) => { + const currentRecordFilterGroups = store.get(currentRecordFilterGroupsAtom); - const hasFoundRecordFilterGroupInCurrentRecordFilterGroups = - currentRecordFilterGroups.some( + const hasFoundRecordFilterGroupInCurrentRecordFilterGroups = + currentRecordFilterGroups.some( + (existingRecordFilterGroup) => + existingRecordFilterGroup.id === recordFilterGroupIdToRemove, + ); + + if (hasFoundRecordFilterGroupInCurrentRecordFilterGroups) { + store.set(currentRecordFilterGroupsAtom, (currentRecordFilterGroups) => { + const newCurrentRecordFilterGroups = [...currentRecordFilterGroups]; + + const indexOfRecordFilterGroupToRemove = + newCurrentRecordFilterGroups.findIndex( (existingRecordFilterGroup) => existingRecordFilterGroup.id === recordFilterGroupIdToRemove, ); - if (hasFoundRecordFilterGroupInCurrentRecordFilterGroups) { - set( - currentRecordFilterGroupsCallbackState, - (currentRecordFilterGroups) => { - const newCurrentRecordFilterGroups = [ - ...currentRecordFilterGroups, - ]; - - const indexOfRecordFilterGroupToRemove = - newCurrentRecordFilterGroups.findIndex( - (existingRecordFilterGroup) => - existingRecordFilterGroup.id === - recordFilterGroupIdToRemove, - ); - - if (indexOfRecordFilterGroupToRemove === -1) { - return newCurrentRecordFilterGroups; - } - - newCurrentRecordFilterGroups.splice( - indexOfRecordFilterGroupToRemove, - 1, - ); - - return newCurrentRecordFilterGroups; - }, - ); + if (indexOfRecordFilterGroupToRemove === -1) { + return newCurrentRecordFilterGroups; } - }, - [currentRecordFilterGroupsCallbackState], - ); + + newCurrentRecordFilterGroups.splice( + indexOfRecordFilterGroupToRemove, + 1, + ); + + return newCurrentRecordFilterGroups; + }); + } + }; const removeRecordFilterGroup = (recordFilterGroupIdToRemove: string) => { removeRecordFilterGroupCallback(recordFilterGroupIdToRemove); diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRootRecordFilterGroupIfEmpty.ts b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRootRecordFilterGroupIfEmpty.ts index b39970208d..0d1cb96e01 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRootRecordFilterGroupIfEmpty.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useRemoveRootRecordFilterGroupIfEmpty.ts @@ -1,69 +1,54 @@ import { useRemoveRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useRemoveRecordFilterGroup'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; export const useRemoveRootRecordFilterGroupIfEmpty = () => { - const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState(currentRecordFilterGroupsComponentState); + const currentRecordFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + ); - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( + const currentRecordFiltersAtom = useRecoilComponentStateCallbackStateV2( currentRecordFiltersComponentState, ); + const store = useStore(); const { removeRecordFilterGroup } = useRemoveRecordFilterGroup(); - const removeRootRecordFilterGroupIfEmpty = useRecoilCallback( - ({ snapshot }) => - () => { - const currentRecordFilterGroups = getSnapshotValue( - snapshot, - currentRecordFilterGroupsCallbackState, + const removeRootRecordFilterGroupIfEmpty = () => { + const currentRecordFilterGroups = store.get(currentRecordFilterGroupsAtom); + + const currentRecordFilters = store.get(currentRecordFiltersAtom); + + const rootRecordFilterGroup = currentRecordFilterGroups.find( + (existingRecordFilterGroup) => + !isDefined(existingRecordFilterGroup.parentRecordFilterGroupId), + ); + + if (isDefined(rootRecordFilterGroup)) { + const recordFilterGroupsInRootRecordFilterGroup = + currentRecordFilterGroups.filter( + (recordFilterGroupToFilter) => + recordFilterGroupToFilter.parentRecordFilterGroupId === + rootRecordFilterGroup.id, ); - const currentRecordFilters = getSnapshotValue( - snapshot, - currentRecordFiltersCallbackState, - ); + const recordFiltersInRootRecordFilterGroup = currentRecordFilters.filter( + (recordFilterToFilter) => + recordFilterToFilter.recordFilterGroupId === rootRecordFilterGroup.id, + ); - const rootRecordFilterGroup = currentRecordFilterGroups.find( - (existingRecordFilterGroup) => - !isDefined(existingRecordFilterGroup.parentRecordFilterGroupId), - ); + const rootRecordFilterGroupIsEmpty = + recordFilterGroupsInRootRecordFilterGroup.length === 0 && + recordFiltersInRootRecordFilterGroup.length === 0; - if (isDefined(rootRecordFilterGroup)) { - const recordFilterGroupsInRootRecordFilterGroup = - currentRecordFilterGroups.filter( - (recordFilterGroupToFilter) => - recordFilterGroupToFilter.parentRecordFilterGroupId === - rootRecordFilterGroup.id, - ); - - const recordFiltersInRootRecordFilterGroup = - currentRecordFilters.filter( - (recordFilterToFilter) => - recordFilterToFilter.recordFilterGroupId === - rootRecordFilterGroup.id, - ); - - const rootRecordFilterGroupIsEmpty = - recordFilterGroupsInRootRecordFilterGroup.length === 0 && - recordFiltersInRootRecordFilterGroup.length === 0; - - if (rootRecordFilterGroupIsEmpty) { - removeRecordFilterGroup(rootRecordFilterGroup.id); - } - } - }, - [ - removeRecordFilterGroup, - currentRecordFilterGroupsCallbackState, - currentRecordFiltersCallbackState, - ], - ); + if (rootRecordFilterGroupIsEmpty) { + removeRecordFilterGroup(rootRecordFilterGroup.id); + } + } + }; return { removeRootRecordFilterGroupIfEmpty, diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup.ts b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup.ts index 9944648f1e..86b7846972 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup.ts @@ -1,64 +1,55 @@ import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; export const useUpsertRecordFilterGroup = () => { - const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState(currentRecordFilterGroupsComponentState); + const currentRecordFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + ); + const store = useStore(); const { onUpdate } = useContext(AdvancedFilterContext); - const upsertRecordFilterGroupCallback = useRecoilCallback( - ({ set, snapshot }) => - (recordFilterGroupToSet: RecordFilterGroup) => { - const currentRecordFilterGroups = getSnapshotValue( - snapshot, - currentRecordFilterGroupsCallbackState, - ); + const upsertRecordFilterGroupCallback = ( + recordFilterGroupToSet: RecordFilterGroup, + ) => { + const currentRecordFilterGroups = store.get(currentRecordFilterGroupsAtom); - const hasFoundRecordFilterGroupInCurrentRecordFilterGroups = - currentRecordFilterGroups.some( + const hasFoundRecordFilterGroupInCurrentRecordFilterGroups = + currentRecordFilterGroups.some( + (existingRecordFilterGroup) => + existingRecordFilterGroup.id === recordFilterGroupToSet.id, + ); + + if (!hasFoundRecordFilterGroupInCurrentRecordFilterGroups) { + store.set(currentRecordFilterGroupsAtom, [ + ...currentRecordFilterGroups, + recordFilterGroupToSet, + ]); + } else { + store.set(currentRecordFilterGroupsAtom, (currentRecordFilterGroups) => { + const newCurrentRecordFilterGroups = [...currentRecordFilterGroups]; + + const indexOfRecordFilterGroupToUpdate = + newCurrentRecordFilterGroups.findIndex( (existingRecordFilterGroup) => existingRecordFilterGroup.id === recordFilterGroupToSet.id, ); - if (!hasFoundRecordFilterGroupInCurrentRecordFilterGroups) { - set(currentRecordFilterGroupsCallbackState, [ - ...currentRecordFilterGroups, - recordFilterGroupToSet, - ]); - } else { - set( - currentRecordFilterGroupsCallbackState, - (currentRecordFilterGroups) => { - const newCurrentRecordFilterGroups = [ - ...currentRecordFilterGroups, - ]; - - const indexOfRecordFilterGroupToUpdate = - newCurrentRecordFilterGroups.findIndex( - (existingRecordFilterGroup) => - existingRecordFilterGroup.id === recordFilterGroupToSet.id, - ); - - if (indexOfRecordFilterGroupToUpdate === -1) { - return newCurrentRecordFilterGroups; - } - - newCurrentRecordFilterGroups[indexOfRecordFilterGroupToUpdate] = { - ...recordFilterGroupToSet, - }; - - return newCurrentRecordFilterGroups; - }, - ); + if (indexOfRecordFilterGroupToUpdate === -1) { + return newCurrentRecordFilterGroups; } - }, - [currentRecordFilterGroupsCallbackState], - ); + + newCurrentRecordFilterGroups[indexOfRecordFilterGroupToUpdate] = { + ...recordFilterGroupToSet, + }; + + return newCurrentRecordFilterGroups; + }); + } + }; const upsertRecordFilterGroup = ( recordFilterGroupToSet: RecordFilterGroup, diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState.ts index 7c3fa20bf6..3732ebcdaa 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState.ts @@ -1,8 +1,8 @@ import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const currentRecordFilterGroupsComponentState = createComponentState< +export const currentRecordFilterGroupsComponentState = createComponentStateV2< RecordFilterGroup[] >({ key: 'currentRecordFilterGroupsComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useRemoveRecordFilter.test.tsx b/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useRemoveRecordFilter.test.tsx index 07cf8340b1..041d560104 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useRemoveRecordFilter.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useRemoveRecordFilter.test.tsx @@ -1,25 +1,37 @@ import { renderHook } from '@testing-library/react'; +import { act } from 'react'; +import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; +import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; +import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { act } from 'react'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewFilterOperand } from 'twenty-shared/types'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; -import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; -const Wrapper = getJestMetadataAndApolloMocksWrapper({ +const BaseWrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks: [], }); +const Wrapper = ({ children }: { children: React.ReactNode }) => ( + + + {children} + + +); + describe('useRemoveRecordFilter', () => { it('should remove an existing record filter', () => { const { result } = renderHook( () => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'test', ); const { upsertRecordFilter } = useUpsertRecordFilter(); @@ -65,8 +77,9 @@ describe('useRemoveRecordFilter', () => { it('should not modify filters when trying to remove a non-existent filter', () => { const { result } = renderHook( () => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'test', ); const { upsertRecordFilter } = useUpsertRecordFilter(); const { removeRecordFilter } = useRemoveRecordFilter(); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useUpsertRecordFilter.test.tsx b/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useUpsertRecordFilter.test.tsx index 0532ea05f5..46e427a457 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useUpsertRecordFilter.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/__tests__/useUpsertRecordFilter.test.tsx @@ -1,24 +1,36 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; +import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; +import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewFilterOperand } from 'twenty-shared/types'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; -const Wrapper = getJestMetadataAndApolloMocksWrapper({ +const BaseWrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks: [], }); +const Wrapper = ({ children }: { children: React.ReactNode }) => ( + + + {children} + + +); + describe('useUpsertRecordFilter', () => { it('should add a new filter when record filter id does not exist', () => { const { result } = renderHook( () => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'test', ); const { upsertRecordFilter } = useUpsertRecordFilter(); @@ -51,8 +63,9 @@ describe('useUpsertRecordFilter', () => { it('should update an existing filter when record filter id exists', () => { const { result } = renderHook( () => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'test', ); const { upsertRecordFilter } = useUpsertRecordFilter(); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts index a7fb151a73..e717751155 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts @@ -2,76 +2,80 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; export const useCreateRecordFilterFromObjectFilterDropdownCurrentStates = () => { const fieldMetadataItemUsedInDropdownCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentSelectorCallbackStateV2( fieldMetadataItemUsedInDropdownComponentSelector, ); const selectedOperandInDropdownCallbackState = - useRecoilComponentCallbackState(selectedOperandInDropdownComponentState); + useRecoilComponentStateCallbackStateV2( + selectedOperandInDropdownComponentState, + ); const subFieldNameUsedInDropdownCallbackState = - useRecoilComponentCallbackState(subFieldNameUsedInDropdownComponentState); + useRecoilComponentStateCallbackStateV2( + subFieldNameUsedInDropdownComponentState, + ); + + const store = useStore(); const createRecordFilterFromObjectFilterDropdownCurrentStates = - useRecoilCallback( - ({ snapshot }) => - () => { - const fieldMetadataItemUsedInDropdown = snapshot - .getLoadable(fieldMetadataItemUsedInDropdownCallbackState) - .getValue(); - - const selectedOperandInDropdown = snapshot - .getLoadable(selectedOperandInDropdownCallbackState) - .getValue(); - - const subFieldNameUsedInDropdown = snapshot - .getLoadable(subFieldNameUsedInDropdownCallbackState) - .getValue(); - - if (!isDefined(fieldMetadataItemUsedInDropdown)) { - throw new Error( - `Field metadata item used in dropdown is not defined when creating a record filter from object filter dropdown current states, this should not happen.`, - ); - } - - const filterType = getFilterTypeFromFieldType( - fieldMetadataItemUsedInDropdown.type, - ); - - if (!isDefined(selectedOperandInDropdown)) { - throw new Error( - `Selected operand in dropdown is not defined when creating a record filter from object filter dropdown current states, this should not happen.`, - ); - } - - const newRecordFilterFromObjectFilterDropdownStates: RecordFilter = - { - id: v4(), - fieldMetadataId: fieldMetadataItemUsedInDropdown.id, - operand: selectedOperandInDropdown, - displayValue: '', - label: fieldMetadataItemUsedInDropdown.label, - type: filterType, - value: '', - subFieldName: subFieldNameUsedInDropdown, - }; - - return { newRecordFilterFromObjectFilterDropdownStates }; - }, - [ + useCallback(() => { + const fieldMetadataItemUsedInDropdown = store.get( fieldMetadataItemUsedInDropdownCallbackState, + ); + + const selectedOperandInDropdown = store.get( selectedOperandInDropdownCallbackState, + ); + + const subFieldNameUsedInDropdown = store.get( subFieldNameUsedInDropdownCallbackState, - ], - ); + ); + + if (!isDefined(fieldMetadataItemUsedInDropdown)) { + throw new Error( + `Field metadata item used in dropdown is not defined when creating a record filter from object filter dropdown current states, this should not happen.`, + ); + } + + const filterType = getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ); + + if (!isDefined(selectedOperandInDropdown)) { + throw new Error( + `Selected operand in dropdown is not defined when creating a record filter from object filter dropdown current states, this should not happen.`, + ); + } + + const newRecordFilterFromObjectFilterDropdownStates: RecordFilter = { + id: v4(), + fieldMetadataId: fieldMetadataItemUsedInDropdown.id, + operand: selectedOperandInDropdown, + displayValue: '', + label: fieldMetadataItemUsedInDropdown.label, + type: filterType, + value: '', + subFieldName: subFieldNameUsedInDropdown, + }; + + return { newRecordFilterFromObjectFilterDropdownStates }; + }, [ + fieldMetadataItemUsedInDropdownCallbackState, + selectedOperandInDropdownCallbackState, + store, + subFieldNameUsedInDropdownCallbackState, + ]); return { createRecordFilterFromObjectFilterDropdownCurrentStates, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useRemoveRecordFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useRemoveRecordFilter.ts index 9c9e006554..b999d1e947 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useRemoveRecordFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useRemoveRecordFilter.ts @@ -1,35 +1,36 @@ import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRemoveRecordFilter = () => { - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( + const currentRecordFiltersAtom = useRecoilComponentStateCallbackStateV2( currentRecordFiltersComponentState, ); + const store = useStore(); const { onUpdate } = useContext(AdvancedFilterContext); - const removeRecordFilterCallback = useRecoilCallback( - ({ set, snapshot }) => - ({ recordFilterId }: { recordFilterId: string }) => { - const currentRecordFilters = getSnapshotValue( - snapshot, - currentRecordFiltersCallbackState, - ); + const removeRecordFilterCallback = useCallback( + ({ recordFilterId }: { recordFilterId: string }) => { + const currentRecordFilters = store.get( + currentRecordFiltersAtom, + ) as RecordFilter[]; - const filterToRemove = currentRecordFilters.find( - (existingFilter) => existingFilter.id === recordFilterId, - ); + const filterToRemove = currentRecordFilters.find( + (existingFilter) => existingFilter.id === recordFilterId, + ); - if (!isDefined(filterToRemove)) { - return; - } + if (!isDefined(filterToRemove)) { + return; + } - set(currentRecordFiltersCallbackState, (currentRecordFilters) => { + store.set( + currentRecordFiltersAtom, + (currentRecordFilters: RecordFilter[]) => { const newCurrentRecordFilters = [...currentRecordFilters]; const indexOfFilterToRemove = newCurrentRecordFilters.findIndex( @@ -39,9 +40,10 @@ export const useRemoveRecordFilter = () => { newCurrentRecordFilters.splice(indexOfFilterToRemove, 1); return newCurrentRecordFilters; - }); - }, - [currentRecordFiltersCallbackState], + }, + ); + }, + [currentRecordFiltersAtom, store], ); const removeRecordFilter = ({ diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useUpsertRecordFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useUpsertRecordFilter.ts index 30c90249b8..c23dd8a5e3 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useUpsertRecordFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useUpsertRecordFilter.ts @@ -1,38 +1,37 @@ import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; export const useUpsertRecordFilter = () => { - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( + const currentRecordFiltersAtom = useRecoilComponentStateCallbackStateV2( currentRecordFiltersComponentState, ); + const store = useStore(); const { onUpdate } = useContext(AdvancedFilterContext); - const upsertRecordFilterCallback = useRecoilCallback( - ({ set, snapshot }) => - (recordFilterToSet: RecordFilter) => { - const currentRecordFilters = getSnapshotValue( - snapshot, - currentRecordFiltersCallbackState, - ); + const upsertRecordFilterCallback = useCallback( + (recordFilterToSet: RecordFilter) => { + const currentRecordFilters = store.get( + currentRecordFiltersAtom, + ) as RecordFilter[]; - const foundRecordFilterInCurrentRecordFilters = - currentRecordFilters.some( - (existingFilter) => existingFilter.id === recordFilterToSet.id, - ); + const foundRecordFilterInCurrentRecordFilters = currentRecordFilters.some( + (existingFilter) => existingFilter.id === recordFilterToSet.id, + ); - if (!foundRecordFilterInCurrentRecordFilters) { - set(currentRecordFiltersCallbackState, [ - ...currentRecordFilters, - recordFilterToSet, - ]); - } else { - set(currentRecordFiltersCallbackState, (currentRecordFilters) => { + if (!foundRecordFilterInCurrentRecordFilters) { + store.set(currentRecordFiltersAtom, [ + ...currentRecordFilters, + recordFilterToSet, + ]); + } else { + store.set( + currentRecordFiltersAtom, + (currentRecordFilters: RecordFilter[]) => { const newCurrentRecordFilters = [...currentRecordFilters]; const indexOfFilterToUpdate = newCurrentRecordFilters.findIndex( @@ -44,10 +43,11 @@ export const useUpsertRecordFilter = () => { }; return newCurrentRecordFilters; - }); - } - }, - [currentRecordFiltersCallbackState], + }, + ); + } + }, + [currentRecordFiltersAtom, store], ); const upsertRecordFilter = (recordFilterToSet: RecordFilter) => { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/states/anyFieldFilterValueComponentState.ts b/packages/twenty-front/src/modules/object-record/record-filter/states/anyFieldFilterValueComponentState.ts index 8cce95e819..799e277fd3 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/states/anyFieldFilterValueComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/states/anyFieldFilterValueComponentState.ts @@ -1,8 +1,10 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const anyFieldFilterValueComponentState = createComponentState({ - key: 'anyFieldFilterValueComponentState', - defaultValue: '', - componentInstanceContext: RecordFiltersComponentInstanceContext, -}); +export const anyFieldFilterValueComponentState = createComponentStateV2( + { + key: 'anyFieldFilterValueComponentState', + defaultValue: '', + componentInstanceContext: RecordFiltersComponentInstanceContext, + }, +); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/states/currentRecordFiltersComponentState.ts b/packages/twenty-front/src/modules/object-record/record-filter/states/currentRecordFiltersComponentState.ts index bd7ab8564c..247d164ba7 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/states/currentRecordFiltersComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/states/currentRecordFiltersComponentState.ts @@ -1,8 +1,8 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const currentRecordFiltersComponentState = createComponentState< +export const currentRecordFiltersComponentState = createComponentStateV2< RecordFilter[] >({ key: 'currentRecordFiltersComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts b/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts index e1fcd0f0e7..fe0dec6aca 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts @@ -1,23 +1,22 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { isRecordFilterAboutSoftDelete } from '@/object-record/record-filter/utils/isRecordFilterAboutSoftDelete'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const hasAnySoftDeleteFilterOnViewComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'hasAnySoftDeleteFilterOnViewComponentSelector', componentInstanceContext: RecordFiltersComponentInstanceContext, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + const objectMetadataItems = get(objectMetadataItemsState); const currentRecordFilters = get( - currentRecordFiltersComponentState.atomFamily({ instanceId }), - ); + currentRecordFiltersComponentState, + componentStateKey, + ) as RecordFilter[]; const hasAnySoftDeleteFilterOnView = currentRecordFilters.some( (recordFilter) => { diff --git a/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupMenuItemDraggable.tsx b/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupMenuItemDraggable.tsx index 1653839d28..0cc186f180 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupMenuItemDraggable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupMenuItemDraggable.tsx @@ -3,8 +3,8 @@ import { type RecordGroupDefinition, RecordGroupDefinitionType, } from '@/object-record/record-group/types/RecordGroupDefinition'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { Tag } from 'twenty-ui/components'; import { IconEye, IconEyeOff } from 'twenty-ui/display'; @@ -25,8 +25,9 @@ export const RecordGroupMenuItemDraggable = ({ onVisibilityChange, isVisibleLimitReached = false, }: RecordGroupMenuItemDraggableProps) => { - const recordGroup = useRecoilValue( - recordGroupDefinitionFamilyState(recordGroupId), + const recordGroup = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + recordGroupId, ); if (!isDefined(recordGroup)) { diff --git a/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx b/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx index 7489349a7e..4df4068ea4 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx @@ -1,7 +1,7 @@ import { RECORD_GROUP_REORDER_CONFIRMATION_MODAL_ID } from '@/object-record/record-group/constants/RecordGroupReorderConfirmationModalId'; import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { type ReactNode } from 'react'; import { createPortal } from 'react-dom'; @@ -13,7 +13,7 @@ type RecordGroupReorderConfirmationModalProps = { export const RecordGroupReorderConfirmationModal = ({ onConfirmClick, }: RecordGroupReorderConfirmationModalProps): ReactNode => { - const recordGroupSort = useRecoilComponentValue( + const recordGroupSort = useRecoilComponentValueV2( recordIndexRecordGroupSortComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useCurrentRecordGroupDefinition.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useCurrentRecordGroupDefinition.ts index e47657fa96..52bc72c21d 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useCurrentRecordGroupDefinition.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useCurrentRecordGroupDefinition.ts @@ -1,13 +1,14 @@ import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; export const useCurrentRecordGroupDefinition = () => { const context = useContext(RecordGroupContext); - const recordGroupDefinition = useRecoilValue( - recordGroupDefinitionFamilyState(context?.recordGroupId), + const recordGroupDefinition = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + context?.recordGroupId ?? '', ); return recordGroupDefinition; 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 c6b764ac4c..1d76f9dd3e 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 @@ -9,8 +9,8 @@ import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record- import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag'; 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 { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type ViewType } from '@/views/types/ViewType'; import { t } from '@lingui/core/macro'; @@ -49,7 +49,7 @@ export const useRecordGroupActions = ({ objectNameSingular, }); - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); @@ -60,7 +60,7 @@ export const useRecordGroupActions = ({ navigationMemorizedUrlState, ); - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, viewType, ); diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts index 1ffb053158..02cbeb3fab 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts @@ -1,13 +1,13 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRecordGroupFilter = (fields: FieldMetadataItem[]) => { const currentRecordGroupDefinition = useCurrentRecordGroupDefinition(); - const groupFieldMetadata = useRecoilComponentValue( + const groupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal.ts index 91b885960c..77819d1cf8 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal.ts @@ -7,8 +7,8 @@ import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyO import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { type ViewType } from '@/views/types/ViewType'; import { type OnDragEndResponder } from '@hello-pangea/dnd'; import { useState } from 'react'; @@ -47,11 +47,12 @@ export const useRecordGroupReorderConfirmationModal = ({ toIndex: result.destination.index - 1, }); }; - const isDragableSortRecordGroup = useRecoilComponentValue( + const isDragableSortRecordGroup = useRecoilComponentSelectorValueV2( recordIndexRecordGroupIsDraggableSortComponentSelector, + recordIndexId, ); - const setRecordGroupSort = useSetRecoilComponentState( + const [, setRecordGroupSort] = useRecoilComponentStateV2( recordIndexRecordGroupSortComponentState, ); const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown(); diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupVisibility.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupVisibility.ts index 0875224316..4de015e99c 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupVisibility.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupVisibility.ts @@ -1,51 +1,50 @@ +import { useStore } from 'jotai'; + import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; import { recordIndexShouldHideEmptyRecordGroupsComponentState } from '@/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { recordGroupDefinitionToViewGroup } from '@/views/utils/recordGroupDefinitionToViewGroup'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; export const useRecordGroupVisibility = () => { - const recordIndexShouldHideEmptyRecordGroupsCallbackState = - useRecoilComponentCallbackState( + const store = useStore(); + + const recordIndexShouldHideEmptyRecordGroupsAtom = + useRecoilComponentStateCallbackStateV2( recordIndexShouldHideEmptyRecordGroupsComponentState, ); const { saveViewGroup } = useSaveCurrentViewGroups(); const { updateCurrentView } = useUpdateCurrentView(); - const handleVisibilityChange = useRecoilCallback( - ({ set }) => - async (updatedRecordGroup: RecordGroupDefinition) => { - set( - recordGroupDefinitionFamilyState(updatedRecordGroup.id), - updatedRecordGroup, - ); + const handleVisibilityChange = useCallback( + async (updatedRecordGroup: RecordGroupDefinition) => { + store.set( + recordGroupDefinitionFamilyState.atomFamily(updatedRecordGroup.id), + updatedRecordGroup, + ); - saveViewGroup(recordGroupDefinitionToViewGroup(updatedRecordGroup)); - }, - [saveViewGroup], + saveViewGroup(recordGroupDefinitionToViewGroup(updatedRecordGroup)); + }, + [saveViewGroup, store], ); - const handleHideEmptyRecordGroupChange = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const currentHideState = snapshot - .getLoadable(recordIndexShouldHideEmptyRecordGroupsCallbackState) - .getValue(); + const handleHideEmptyRecordGroupChange = useCallback(async () => { + const currentHideState = store.get( + recordIndexShouldHideEmptyRecordGroupsAtom, + ); - const newHideState = !currentHideState; + const newHideState = !currentHideState; - set(recordIndexShouldHideEmptyRecordGroupsCallbackState, newHideState); + store.set(recordIndexShouldHideEmptyRecordGroupsAtom, newHideState); - await updateCurrentView({ - shouldHideEmptyGroups: newHideState, - }); - }, - [recordIndexShouldHideEmptyRecordGroupsCallbackState, updateCurrentView], - ); + await updateCurrentView({ + shouldHideEmptyGroups: newHideState, + }); + }, [store, recordIndexShouldHideEmptyRecordGroupsAtom, updateCurrentView]); return { handleVisibilityChange, diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useReorderRecordGroups.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useReorderRecordGroups.ts index 2e5e86e0db..1d08be2533 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useReorderRecordGroups.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useReorderRecordGroups.ts @@ -1,16 +1,17 @@ +import { useStore } from 'jotai'; + import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { useSetRecordGroups } from '@/object-record/record-group/hooks/useSetRecordGroups'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentFamilySelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2'; import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups'; import { type ViewType } from '@/views/types/ViewType'; import { mapRecordGroupDefinitionsToViewGroups } from '@/views/utils/mapRecordGroupDefinitionsToViewGroups'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { moveArrayItem } from '~/utils/array/moveArrayItem'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -29,83 +30,83 @@ export const useReorderRecordGroups = ({ recordIndexId, viewType, }: UseReorderRecordGroupsParams) => { + const store = useStore(); const { setRecordGroups } = useSetRecordGroups(); const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const visibleRecordGroupIdsFamilySelector = useRecoilComponentCallbackState( - visibleRecordGroupIdsComponentFamilySelector, - recordIndexId, - ); + const visibleRecordGroupIdsFamilySelector = + useRecoilComponentFamilySelectorCallbackStateV2( + visibleRecordGroupIdsComponentFamilySelector, + recordIndexId, + ); const { saveViewGroups } = useSaveCurrentViewGroups(); - const groupFieldMetadata = useRecoilComponentValue( + const groupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); - const reorderRecordGroups = useRecoilCallback( - ({ snapshot }) => - ({ fromIndex, toIndex }: ReorderRecordGroupsParams) => { - const visibleRecordGroupIds = getSnapshotValue( - snapshot, - visibleRecordGroupIdsFamilySelector(viewType), + const reorderRecordGroups = useCallback( + ({ fromIndex, toIndex }: ReorderRecordGroupsParams) => { + const visibleRecordGroupIds = store.get( + visibleRecordGroupIdsFamilySelector(viewType), + ); + + const reorderedVisibleRecordGroupIds = moveArrayItem( + visibleRecordGroupIds, + { + fromIndex, + toIndex, + }, + ); + + if ( + isDeeplyEqual(visibleRecordGroupIds, reorderedVisibleRecordGroupIds) + ) { + return; + } + + const updatedRecordGroups = reorderedVisibleRecordGroupIds.reduce< + RecordGroupDefinition[] + >((acc, recordGroupId, reorderIndex) => { + const recordGroupDefinition = store.get( + recordGroupDefinitionFamilyState.atomFamily(recordGroupId), ); - const reorderedVisibleRecordGroupIds = moveArrayItem( - visibleRecordGroupIds, + if (!isDefined(recordGroupDefinition)) { + return acc; + } + + return [ + ...acc, { - fromIndex, - toIndex, + ...recordGroupDefinition, + position: reorderIndex, }, - ); + ]; + }, []); - if ( - isDeeplyEqual(visibleRecordGroupIds, reorderedVisibleRecordGroupIds) - ) { - return; - } + if (!isDefined(groupFieldMetadata?.id)) { + throw new Error('mainGroupByFieldMetadataId is required'); + } - const updatedRecordGroups = reorderedVisibleRecordGroupIds.reduce< - RecordGroupDefinition[] - >((acc, recordGroupId, index) => { - const recordGroupDefinition = getSnapshotValue( - snapshot, - recordGroupDefinitionFamilyState(recordGroupId), - ); - - if (!isDefined(recordGroupDefinition)) { - return acc; - } - - return [ - ...acc, - { - ...recordGroupDefinition, - position: index, - }, - ]; - }, []); - - if (!isDefined(groupFieldMetadata?.id)) { - throw new Error('mainGroupByFieldMetadataId is required'); - } - - setRecordGroups({ - mainGroupByFieldMetadataId: groupFieldMetadata?.id, - recordGroups: updatedRecordGroups, - recordIndexId, - objectMetadataItemId: objectMetadataItem.id, - }); - saveViewGroups( - mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups), - ); - }, + setRecordGroups({ + mainGroupByFieldMetadataId: groupFieldMetadata?.id, + recordGroups: updatedRecordGroups, + recordIndexId, + objectMetadataItemId: objectMetadataItem.id, + }); + saveViewGroups( + mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups), + ); + }, [ objectMetadataItem.id, groupFieldMetadata?.id, recordIndexId, saveViewGroups, setRecordGroups, + store, viewType, visibleRecordGroupIdsFamilySelector, ], diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useSetRecordGroups.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useSetRecordGroups.ts index da64e03e72..674b8205f5 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useSetRecordGroups.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useSetRecordGroups.ts @@ -1,3 +1,5 @@ +import { useStore } from 'jotai'; + import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; @@ -5,111 +7,101 @@ import { recordGroupIdsComponentState } from '@/object-record/record-group/state import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { type ViewGroup } from '@/views/types/ViewGroup'; import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useSetRecordGroups = () => { - const setRecordGroups = useRecoilCallback( - ({ snapshot, set }) => - ({ - mainGroupByFieldMetadataId, - recordGroups, - recordIndexId, - objectMetadataItemId, - }: { - mainGroupByFieldMetadataId: string; - recordGroups: RecordGroupDefinition[]; - recordIndexId: string; - objectMetadataItemId: string; - }) => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, + const store = useStore(); + + const setRecordGroups = useCallback( + ({ + mainGroupByFieldMetadataId, + recordGroups, + recordIndexId, + objectMetadataItemId, + }: { + mainGroupByFieldMetadataId: string; + recordGroups: RecordGroupDefinition[]; + recordIndexId: string; + objectMetadataItemId: string; + }) => { + const objectMetadataItems = store.get(objectMetadataItemsState.atom); + + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => objectMetadataItem.id === objectMetadataItemId, + ); + + if (!isDefined(objectMetadataItem)) { + return; + } + + const currentRecordGroupIds = store.get( + recordGroupIdsComponentState.atomFamily({ + instanceId: recordIndexId, + }), + ); + + const fieldMetadataId = mainGroupByFieldMetadataId; + const fieldMetadata = fieldMetadataId + ? objectMetadataItem.fields.find( + (field) => field.id === fieldMetadataId, + ) + : undefined; + const recordIndexGroupFieldMetadataAtom = + recordIndexGroupFieldMetadataItemComponentState.atomFamily({ + instanceId: recordIndexId, + }); + const currentFieldMetadata = store.get(recordIndexGroupFieldMetadataAtom); + + // Set the field metadata linked to the record groups + if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) { + store.set(recordIndexGroupFieldMetadataAtom, fieldMetadata); + } + + // Set the record groups by id + recordGroups.forEach((recordGroup) => { + const existingRecordGroup = store.get( + recordGroupDefinitionFamilyState.atomFamily(recordGroup.id), ); - const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.id === objectMetadataItemId, - ); - - if (!isDefined(objectMetadataItem)) { + if (isDeeplyEqual(existingRecordGroup, recordGroup)) { return; } - const currentRecordGroupIds = getSnapshotValue( - snapshot, - recordGroupIdsComponentState.atomFamily({ - instanceId: recordIndexId, - }), + store.set( + recordGroupDefinitionFamilyState.atomFamily(recordGroup.id), + recordGroup, ); + }); - const fieldMetadataId = mainGroupByFieldMetadataId; - const fieldMetadata = fieldMetadataId - ? objectMetadataItem.fields.find( - (field) => field.id === fieldMetadataId, - ) - : undefined; - const currentFieldMetadata = getSnapshotValue( - snapshot, - recordIndexGroupFieldMetadataItemComponentState.atomFamily({ - instanceId: recordIndexId, - }), - ); + const recordGroupIds = recordGroups.map(({ id }) => id); - // Set the field metadata linked to the record groups - if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) { - set( - recordIndexGroupFieldMetadataItemComponentState.atomFamily({ - instanceId: recordIndexId, - }), - fieldMetadata, - ); - } + // Get ids that has been removed between the current and new record groups + const removedRecordGroupIds = currentRecordGroupIds.filter( + (id) => !recordGroupIds.includes(id), + ); - // Set the record groups by id - recordGroups.forEach((recordGroup) => { - const existingRecordGroup = getSnapshotValue( - snapshot, - recordGroupDefinitionFamilyState(recordGroup.id), - ); + // Remove the record groups that has been removed + removedRecordGroupIds.forEach((id) => { + store.set(recordGroupDefinitionFamilyState.atomFamily(id), undefined); + }); - if (isDeeplyEqual(existingRecordGroup, recordGroup)) { - return; - } + if (isDeeplyEqual(currentRecordGroupIds, recordGroupIds)) { + return; + } - set(recordGroupDefinitionFamilyState(recordGroup.id), recordGroup); - }); - - const recordGroupIds = recordGroups.map(({ id }) => id); - - // Get ids that has been removed between the current and new record groups - const removedRecordGroupIds = currentRecordGroupIds.filter( - (id) => !recordGroupIds.includes(id), - ); - - // Remove the record groups that has been removed - removedRecordGroupIds.forEach((id) => { - set(recordGroupDefinitionFamilyState(id), undefined); - }); - - if (isDeeplyEqual(currentRecordGroupIds, recordGroupIds)) { - return; - } - - // Set the record group ids - set( - recordGroupIdsComponentState.atomFamily({ - instanceId: recordIndexId, - }), - recordGroupIds, - ); - }, - [], + // Set the record group ids + store.set( + recordGroupIdsComponentState.atomFamily({ + instanceId: recordIndexId, + }), + recordGroupIds, + ); + }, + [store], ); const setRecordGroupsFromViewGroups = useCallback( diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useShouldHideRecordGroup.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useShouldHideRecordGroup.ts index 65114c5a97..b19ea1f86b 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/hooks/useShouldHideRecordGroup.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useShouldHideRecordGroup.ts @@ -1,14 +1,14 @@ import { emptyRecordGroupByIdComponentFamilyState } from '@/object-record/record-group/states/emptyRecordGroupByIdComponentFamilyState'; import { recordIndexShouldHideEmptyRecordGroupsComponentState } from '@/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useShouldHideRecordGroup = (recordGroupId: string): boolean => { - const shouldHideEmptyRecordGroups = useRecoilComponentValue( + const shouldHideEmptyRecordGroups = useRecoilComponentValueV2( recordIndexShouldHideEmptyRecordGroupsComponentState, ); - const isRecordGroupEmpty = useRecoilComponentFamilyValue( + const isRecordGroupEmpty = useRecoilComponentFamilyValueV2( emptyRecordGroupByIdComponentFamilyState, recordGroupId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/emptyRecordGroupByIdComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-group/states/emptyRecordGroupByIdComponentFamilyState.ts index d7a1c9906e..d064e42233 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/emptyRecordGroupByIdComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/emptyRecordGroupByIdComponentFamilyState.ts @@ -1,8 +1,8 @@ -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const emptyRecordGroupByIdComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'emptyRecordGroupByIdComponentFamilyState', defaultValue: false, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupDefinitionFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupDefinitionFamilyState.ts index 0cfc5d8e19..a0548046a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupDefinitionFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupDefinitionFamilyState.ts @@ -1,10 +1,10 @@ +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { atomFamily } from 'recoil'; -export const recordGroupDefinitionFamilyState = atomFamily< +export const recordGroupDefinitionFamilyState = createFamilyStateV2< RecordGroupDefinition | undefined, RecordGroupDefinition['id'] >({ key: 'recordGroupDefinitionFamilyState', - default: undefined, + defaultValue: undefined, }); diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupIdsComponentState.ts index 371f86ffa8..8eee5054a3 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupIdsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/recordGroupIdsComponentState.ts @@ -1,8 +1,8 @@ +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -export const recordGroupIdsComponentState = createComponentState< +export const recordGroupIdsComponentState = createComponentStateV2< RecordGroupDefinition['id'][] >({ key: 'recordGroupIdsComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/availableRecordGroupIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/availableRecordGroupIdsComponentSelector.ts index 5319e2bd5a..ac2fc27188 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/availableRecordGroupIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/availableRecordGroupIdsComponentSelector.ts @@ -5,45 +5,44 @@ import { RecordGroupDefinitionType, } from '@/object-record/record-group/types/RecordGroupDefinition'; import { recordGroupSortedInsert } from '@/object-record/record-group/utils/recordGroupSortedInsert'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; - +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { isDefined } from 'twenty-shared/utils'; -export const availableRecordGroupIdsComponentSelector = createComponentSelector< - RecordGroupDefinition['id'][] ->({ - key: 'availableRecordGroupIdsComponentSelector', - componentInstanceContext: ViewComponentInstanceContext, - get: - ({ instanceId }) => - ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ +export const availableRecordGroupIdsComponentSelector = + createComponentSelectorV2({ + key: 'availableRecordGroupIdsComponentSelector', + componentInstanceContext: ViewComponentInstanceContext, + get: + ({ instanceId }) => + ({ get }) => { + const recordGroupIds = get(recordGroupIdsComponentState, { instanceId, - }), - ); + }); - const result: RecordGroupDefinition[] = []; + const result: RecordGroupDefinition[] = []; - for (const recordGroupId of recordGroupIds) { - const recordGroupDefinition = get( - recordGroupDefinitionFamilyState(recordGroupId), - ); + for (const recordGroupId of recordGroupIds) { + const recordGroupDefinition = get( + recordGroupDefinitionFamilyState, + recordGroupId, + ); - if (!isDefined(recordGroupDefinition)) { - continue; + if (!isDefined(recordGroupDefinition)) { + continue; + } + + if ( + recordGroupDefinition.type === RecordGroupDefinitionType.NoValue + ) { + continue; + } + + recordGroupSortedInsert(result, recordGroupDefinition, (a, b) => + a.title.localeCompare(b.title), + ); } - if (recordGroupDefinition.type === RecordGroupDefinitionType.NoValue) { - continue; - } - - recordGroupSortedInsert(result, recordGroupDefinition, (a, b) => - a.title.localeCompare(b.title), - ); - } - - return result.map(({ id }) => id); - }, -}); + return result.map(({ id }) => id); + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector.ts index f9497e37b1..158c17dc1e 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector.ts @@ -1,20 +1,18 @@ import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const hasRecordGroupsComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'hasRecordGroupsComponentSelector', componentInstanceContext: ViewComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupIds = get(recordGroupIdsComponentState, { + instanceId, + }); return recordGroupIds.length > 0; }, diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector.ts index 771f985904..a0e6d8ecff 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector.ts @@ -1,12 +1,11 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; - -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { isDefined } from 'twenty-shared/utils'; -export const hiddenRecordGroupIdsComponentSelector = createComponentSelector< +export const hiddenRecordGroupIdsComponentSelector = createComponentSelectorV2< RecordGroupDefinition['id'][] >({ key: 'hiddenRecordGroupIdsComponentSelector', @@ -14,15 +13,14 @@ export const hiddenRecordGroupIdsComponentSelector = createComponentSelector< get: ({ instanceId }) => ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupIds = get(recordGroupIdsComponentState, { + instanceId, + }); return recordGroupIds.filter((recordGroupId) => { const recordGroupDefinition = get( - recordGroupDefinitionFamilyState(recordGroupId), + recordGroupDefinitionFamilyState, + recordGroupId, ); if (!isDefined(recordGroupDefinition)) { diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector.ts index 993b222df3..cffffdd045 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector.ts @@ -1,38 +1,35 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; - -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { isDefined } from 'twenty-shared/utils'; -export const recordGroupDefinitionsComponentSelector = createComponentSelector< - RecordGroupDefinition[] ->({ - key: 'recordGroupDefinitionsComponentSelector', - componentInstanceContext: ViewComponentInstanceContext, - get: - ({ instanceId }) => - ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ +export const recordGroupDefinitionsComponentSelector = + createComponentSelectorV2({ + key: 'recordGroupDefinitionsComponentSelector', + componentInstanceContext: ViewComponentInstanceContext, + get: + ({ instanceId }) => + ({ get }) => { + const recordGroupIds = get(recordGroupIdsComponentState, { instanceId, - }), - ); + }); - return recordGroupIds.reduce( - (acc, recordGroupId) => { - const recordGroupDefinition = get( - recordGroupDefinitionFamilyState(recordGroupId), - ); + return recordGroupIds.reduce( + (acc, recordGroupId) => { + const recordGroupDefinition = get( + recordGroupDefinitionFamilyState, + recordGroupId, + ); - if (!isDefined(recordGroupDefinition)) { - return acc; - } + if (!isDefined(recordGroupDefinition)) { + return acc; + } - return [...acc, recordGroupDefinition]; - }, - [], - ); - }, -}); + return [...acc, recordGroupDefinition]; + }, + [], + ); + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts index f2c75e65e1..9caaa683b2 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts @@ -1,14 +1,13 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; - +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { type Nullable } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const recordGroupFromGroupValueComponentFamilySelector = - createComponentFamilySelector< + createComponentFamilySelectorV2< RecordGroupDefinition | undefined, { recordGroupValue: Nullable } >({ @@ -17,15 +16,14 @@ export const recordGroupFromGroupValueComponentFamilySelector = get: ({ instanceId, familyKey }) => ({ get }): RecordGroupDefinition | undefined => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupIds = get(recordGroupIdsComponentState, { + instanceId, + }); - const recordGroupId = recordGroupIds.find((recordGroupId) => { + const recordGroupId = recordGroupIds.find((id) => { const recordGroupDefinition = get( - recordGroupDefinitionFamilyState(recordGroupId), + recordGroupDefinitionFamilyState, + id, ); return recordGroupDefinition?.value === familyKey.recordGroupValue; @@ -36,7 +34,8 @@ export const recordGroupFromGroupValueComponentFamilySelector = } const recordGroupDefinition = get( - recordGroupDefinitionFamilyState(recordGroupId), + recordGroupDefinitionFamilyState, + recordGroupId, ); return recordGroupDefinition; diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector.ts index 12eccb6f1f..0513446b51 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector.ts @@ -6,36 +6,29 @@ import { recordGroupSortedInsert } from '@/object-record/record-group/utils/reco import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { recordIndexShouldHideEmptyRecordGroupsComponentState } from '@/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; - +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { type ViewType } from '@/views/types/ViewType'; - import { isDefined } from 'twenty-shared/utils'; export const visibleRecordGroupIdsComponentFamilySelector = - createComponentFamilySelector({ + createComponentFamilySelectorV2({ key: 'visibleRecordGroupIdsComponentFamilySelector', componentInstanceContext: ViewComponentInstanceContext, get: - ({ instanceId }) => + ({ instanceId, familyKey: _viewType }) => ({ get }) => { - const recordGroupSort = get( - recordIndexRecordGroupSortComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupSort = get(recordIndexRecordGroupSortComponentState, { + instanceId, + }); - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupIds = get(recordGroupIdsComponentState, { + instanceId, + }); const shouldHideEmptyRecordGroups = get( - recordIndexShouldHideEmptyRecordGroupsComponentState.atomFamily({ - instanceId, - }), + recordIndexShouldHideEmptyRecordGroupsComponentState, + { instanceId }, ); const result: RecordGroupDefinition[] = []; @@ -57,7 +50,8 @@ export const visibleRecordGroupIdsComponentFamilySelector = for (const recordGroupId of recordGroupIds) { const recordGroupDefinition = get( - recordGroupDefinitionFamilyState(recordGroupId), + recordGroupDefinitionFamilyState, + recordGroupId, ); if (!isDefined(recordGroupDefinition)) { @@ -70,10 +64,8 @@ export const visibleRecordGroupIdsComponentFamilySelector = if (shouldHideEmptyRecordGroups) { const rowIds = get( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordGroupId, - }), + recordIndexRecordIdsByGroupComponentFamilyState, + { instanceId, familyKey: recordGroupId }, ); if (rowIds.length === 0) { continue; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index ecebfa9421..62f9754a45 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -1,11 +1,11 @@ import styled from '@emotion/styled'; -import { useRecoilState } from 'recoil'; import { ObjectOptionsDropdown } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdown'; import { RecordBoardContainer } from '@/object-record/record-board/components/RecordBoardContainer'; import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer'; import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect'; import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; @@ -32,7 +32,7 @@ const StyledContainerWithPadding = styled.div` `; export const RecordIndexContainer = () => { - const [recordIndexViewType] = useRecoilState(recordIndexViewTypeState); + const recordIndexViewType = useRecoilValueV2(recordIndexViewTypeState); const { objectNamePlural, diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx index b0871c2f8b..7f176307be 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx @@ -10,17 +10,17 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect = () => { - const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentState( + const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentStateV2( contextStoreNumberOfSelectedRecordsComponentState, ); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, ); @@ -38,15 +38,15 @@ export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect = objectMetadataItem?.nameSingular ?? '', ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx index 0cd969aac4..fb9a6b2581 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx @@ -8,6 +8,7 @@ import { RecordComponentInstanceContextsWrapper } from '@/object-record/componen import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { lastShowPageRecordIdState } from '@/object-record/record-field/ui/states/lastShowPageRecordId'; import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect'; import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect'; import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader'; @@ -18,7 +19,7 @@ import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-sel import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import styled from '@emotion/styled'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { NotFound } from '~/pages/not-found/NotFound'; const StyledIndexContainer = styled.div` @@ -31,14 +32,10 @@ export const RecordIndexContainerGater = () => { const { recordIndexId, objectMetadataItem } = useRecordIndexIdFromCurrentContextStore(); - const handleIndexRecordsLoaded = useRecoilCallback( - ({ set }) => - () => { - // TODO: find a better way to reset this state ? - set(lastShowPageRecordIdState, null); - }, - [], - ); + const handleIndexRecordsLoaded = useCallback(() => { + // TODO: find a better way to reset this state ? + jotaiStore.set(lastShowPageRecordIdState.atom, null); + }, []); const { indexIdentifierUrl } = useHandleIndexIdentifierClick({ objectMetadataItem, diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx index 22b8ff1f7e..247998d7e5 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx @@ -11,36 +11,38 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/conte import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; import { unselectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const RecordIndexFiltersToContextStoreEffect = () => { const { recordIndexId } = useRecordIndexContextOrThrow(); - const recordIndexFilters = useRecoilComponentValue( + const recordIndexFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, recordIndexId, ); - const recordIndexFilterGroups = useRecoilComponentValue( + const recordIndexFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, recordIndexId, ); - const setContextStoreTargetedRecords = useSetRecoilComponentState( + const setContextStoreTargetedRecords = useSetRecoilComponentStateV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const hasUserSelectedAllRows = useRecoilComponentValue( + const hasUserSelectedAllRows = useRecoilComponentValueV2( hasUserSelectedAllRowsComponentState, recordIndexId, ); - const selectedRowIds = useRecoilComponentValue( + const selectedRowIds = useRecoilComponentSelectorValueV2( selectedRowIdsComponentSelector, recordIndexId, ); - const unselectedRowIds = useRecoilComponentValue( + const unselectedRowIds = useRecoilComponentSelectorValueV2( unselectedRowIdsComponentSelector, recordIndexId, ); @@ -71,12 +73,14 @@ export const RecordIndexFiltersToContextStoreEffect = () => { unselectedRowIds, ]); - const setContextStoreFilters = useSetRecoilComponentState( + const setContextStoreFilters = useSetRecoilComponentStateV2( contextStoreFiltersComponentState, + recordIndexId, ); - const setContextStoreFilterGroups = useSetRecoilComponentState( + const setContextStoreFilterGroups = useSetRecoilComponentStateV2( contextStoreFilterGroupsComponentState, + recordIndexId, ); useEffect(() => { @@ -93,11 +97,12 @@ export const RecordIndexFiltersToContextStoreEffect = () => { setContextStoreFilters, ]); - const setContextStoreAnyFieldFilterValue = useSetRecoilComponentState( + const setContextStoreAnyFieldFilterValue = useSetRecoilComponentStateV2( contextStoreAnyFieldFilterValueComponentState, + recordIndexId, ); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregateQueryEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregateQueryEffect.tsx index 69b46501a4..6ea675b883 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregateQueryEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregateQueryEffect.tsx @@ -9,8 +9,8 @@ import { useSetRecordIndexAggregateDisplayValueForRecordGroupValue } from '@/obj import { recordIndexAggregateDisplayLabelComponentState } from '@/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState'; import { turnRecordIndexGroupByAggregateQueryResultIntoRecordAggregateValueByGroupValue } from '@/object-record/record-index/utils/turnRecordIndexGroupByAggregateQueryResultIntoRecordAggregateValueByGroupValue'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useEffect } from 'react'; import { type Nullable } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -40,8 +40,8 @@ export const RecordIndexGroupAggregateQueryEffect = ({ recordIndexGroupAggregateOperation, }); - const recordIndexAggregateDisplayLabelCallbackState = - useRecoilComponentCallbackState( + const recordIndexAggregateDisplayLabelAtom = + useRecoilComponentStateCallbackStateV2( recordIndexAggregateDisplayLabelComponentState, ); @@ -51,7 +51,7 @@ export const RecordIndexGroupAggregateQueryEffect = ({ const { setRecordIndexAggregateDisplayValueForRecordGroupValue } = useSetRecordIndexAggregateDisplayValueForRecordGroupValue(); - const recordGroupDefinitions = useRecoilComponentValue( + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, ); @@ -112,7 +112,7 @@ export const RecordIndexGroupAggregateQueryEffect = ({ recordIndexGroupAggregateFieldMetadataItem, recordIndexGroupAggregateOperation, recordAggregateGqlField, - recordIndexAggregateDisplayLabelCallbackState, + recordIndexAggregateDisplayLabelAtom, objectMetadataItem, recordGroupDefinitions, ]); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregatesDataLoader.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregatesDataLoader.tsx index b1e70e83f8..65733f3902 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregatesDataLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexGroupAggregatesDataLoader.tsx @@ -3,19 +3,19 @@ import { recordIndexGroupAggregateFieldMetadataItemComponentState } from '@/obje import { recordIndexGroupAggregateOperationComponentState } from '@/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const RecordIndexGroupAggregatesDataLoader = () => { - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); - const recordIndexGroupAggregateFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupAggregateFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupAggregateFieldMetadataItemComponentState, ); - const recordIndexGroupAggregateOperation = useRecoilComponentValue( + const recordIndexGroupAggregateOperation = useRecoilComponentValueV2( recordIndexGroupAggregateOperationComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx index 237e560926..e3fc3457a4 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx @@ -1,7 +1,7 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { useEffect, useState } from 'react'; @@ -9,7 +9,7 @@ import { isDefined } from 'twenty-shared/utils'; export const RecordIndexLoadBaseOnContextStoreEffect = () => { const { loadRecordIndexStates } = useLoadRecordIndexStates(); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx index 94d76f3130..8a5f01468f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageHeader.tsx @@ -6,7 +6,7 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton'; import { PageHeader } from '@/ui/layout/page/components/PageHeader'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; @@ -32,7 +32,7 @@ export const RecordIndexPageHeader = () => { const { findObjectMetadataItemByNamePlural } = useFilteredObjectMetadataItems(); - const contextStoreNumberOfSelectedRecords = useRecoilComponentValue( + const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2( contextStoreNumberOfSelectedRecordsComponentState, ); @@ -59,7 +59,7 @@ export const RecordIndexPageHeader = () => { label ); - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem.tsx index 72c027a2e3..facb0587e4 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem.tsx @@ -1,7 +1,7 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { MenuItem } from 'twenty-ui/navigation'; import { Tag } from 'twenty-ui/components'; @@ -19,8 +19,9 @@ export const RecordIndexPageKanbanAddMenuItem = ({ columnId, onItemClick, }: RecordIndexPageKanbanAddMenuItemProps) => { - const recordGroupDefinition = useRecoilValue( - recordGroupDefinitionFamilyState(columnId), + const recordGroupDefinition = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + columnId, ); if (!isDefined(recordGroupDefinition)) { diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx index e16640326a..93ecfa9935 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx @@ -2,13 +2,13 @@ import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-ind import { useRemoveRecordSort } from '@/object-record/record-sort/hooks/useRemoveRecordSort'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useLingui } from '@lingui/react/macro'; export const RecordIndexRemoveSortingModal = () => { const { t } = useLingui(); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx index 407e4bea53..38e06c5706 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx @@ -1,13 +1,13 @@ -import { useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState'; import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { type ViewField } from '@/views/types/ViewField'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const RecordIndexTableContainerEffect = () => { @@ -22,43 +22,39 @@ export const RecordIndexTableContainerEffect = () => { const { currentView } = useGetCurrentViewOnly(); - const setViewFieldAggregateOperation = useRecoilCallback( - ({ set, snapshot }) => - (viewField: ViewField) => { - const aggregateOperationForViewField = snapshot - .getLoadable( - viewFieldAggregateOperationState({ - viewFieldId: viewField.id, - }), + const setViewFieldAggregateOperation = useCallback( + (viewField: ViewField) => { + const aggregateOperationForViewField = jotaiStore.get( + viewFieldAggregateOperationState.atomFamily({ + viewFieldId: viewField.id, + }), + ); + + const viewFieldMetadataType = columnDefinitions.find( + (columnDefinition) => + columnDefinition.fieldMetadataId === viewField.fieldMetadataId, + )?.type; + + const convertedViewFieldAggregateOperation = isDefined( + viewField.aggregateOperation, + ) + ? convertAggregateOperationToExtendedAggregateOperation( + viewField.aggregateOperation, + viewFieldMetadataType, ) - .getValue(); + : viewField.aggregateOperation; - const viewFieldMetadataType = columnDefinitions.find( - (columnDefinition) => - columnDefinition.fieldMetadataId === viewField.fieldMetadataId, - )?.type; - - const convertedViewFieldAggregateOperation = isDefined( - viewField.aggregateOperation, - ) - ? convertAggregateOperationToExtendedAggregateOperation( - viewField.aggregateOperation, - viewFieldMetadataType, - ) - : viewField.aggregateOperation; - - if ( - aggregateOperationForViewField !== - convertedViewFieldAggregateOperation - ) { - set( - viewFieldAggregateOperationState({ - viewFieldId: viewField.id, - }), - convertedViewFieldAggregateOperation, - ); - } - }, + if ( + aggregateOperationForViewField !== convertedViewFieldAggregateOperation + ) { + jotaiStore.set( + viewFieldAggregateOperationState.atomFamily({ + viewFieldId: viewField.id, + }), + convertedViewFieldAggregateOperation, + ); + } + }, [columnDefinitions], ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useRecordIndexLazyFetchRecords.ts b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useRecordIndexLazyFetchRecords.ts index 9282a6cd82..2e626ee37f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useRecordIndexLazyFetchRecords.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useRecordIndexLazyFetchRecords.ts @@ -16,7 +16,8 @@ import { type RecordField } from '@/object-record/record-field/types/RecordField import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; import { isDefined } from 'twenty-shared/utils'; @@ -58,7 +59,7 @@ export const useRecordIndexLazyFetchRecords = ({ viewBarId: recordIndexId, }); - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, recordIndexId, ); @@ -67,20 +68,24 @@ export const useRecordIndexLazyFetchRecords = ({ (column) => column.metadata.fieldName === recordGroupFieldMetadata?.name, ); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, + recordIndexId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, + recordIndexId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, + recordIndexId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, + recordIndexId, ); const { filterValueDependencies } = useFilterValueDependencies(); @@ -98,7 +103,7 @@ export const useRecordIndexLazyFetchRecords = ({ contextStoreAnyFieldFilterValue, }); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts index d27fc2a631..2e457e472f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts @@ -8,7 +8,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition'; import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { combineFilters, computeRecordGqlOperationFilter, @@ -29,15 +29,15 @@ export const useFindManyRecordIndexTableParams = ( const currentRecordGroupDefinition = useCurrentRecordGroupDefinition(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -50,7 +50,7 @@ export const useFindManyRecordIndexTableParams = ( filterValueDependencies, }); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts index e89396200c..ad10635f2e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleIndexIdentifierClick.ts @@ -1,6 +1,6 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { AppPath } from 'twenty-shared/types'; import { getAppPath } from 'twenty-shared/utils'; @@ -11,7 +11,7 @@ export const useHandleIndexIdentifierClick = ({ recordIndexId: string; objectMetadataItem: ObjectMetadataItem; }) => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleRecordGroupField.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleRecordGroupField.ts index 949ce65a18..1040db1153 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleRecordGroupField.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleRecordGroupField.ts @@ -3,20 +3,21 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { useSetRecordGroups } from '@/object-record/record-group/hooks/useSetRecordGroups'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate'; import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState'; import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { type ViewGroup } from '@/views/types/ViewGroup'; import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { type CoreView } from '~/generated-metadata/graphql'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; export const useHandleRecordGroupField = () => { - const currentViewIdCallbackState = useRecoilComponentCallbackState( + const currentViewIdCallbackState = useRecoilComponentStateCallbackStateV2( contextStoreCurrentViewIdComponentState, ); @@ -31,105 +32,98 @@ export const useHandleRecordGroupField = () => { const { refreshCoreViewsByObjectMetadataId } = useRefreshCoreViewsByObjectMetadataId(); - const handleRecordGroupFieldChange = useRecoilCallback( - ({ snapshot }) => - async (fieldMetadataItem: FieldMetadataItem) => { - const currentViewId = snapshot - .getLoadable(currentViewIdCallbackState) - .getValue(); + const store = useStore(); - if (!currentViewId) { - return; + const handleRecordGroupFieldChange = useCallback( + async (fieldMetadataItem: FieldMetadataItem) => { + const currentViewId = store.get(currentViewIdCallbackState); + + if (!currentViewId) { + return; + } + + const view = getViewFromPrefetchState(currentViewId); + + if (isUndefinedOrNull(view)) { + return; + } + + if ( + isUndefinedOrNull(fieldMetadataItem.options) || + fieldMetadataItem.options.length === 0 + ) { + return; + } + + const updatedViewResult = await performViewAPIUpdate({ + id: view.id, + input: { + mainGroupByFieldMetadataId: fieldMetadataItem.id, + }, + }); + + if (updatedViewResult.status === 'successful') { + const updatedCoreView = updatedViewResult.response.data + ?.updateCoreView as CoreView; + + if (isDefined(updatedCoreView)) { + const updatedViewConverted = convertCoreViewToView(updatedCoreView); + await loadRecordIndexStates(updatedViewConverted, objectMetadataItem); } + } - const view = getViewFromPrefetchState(currentViewId); + const existingGroupKeys = new Set( + view.viewGroups.map( + (group) => `${view.mainGroupByFieldMetadataId}:${group.fieldValue}`, + ), + ); - if (isUndefinedOrNull(view)) { - return; - } - - if ( - isUndefinedOrNull(fieldMetadataItem.options) || - fieldMetadataItem.options.length === 0 - ) { - return; - } - - const updatedViewResult = await performViewAPIUpdate({ - id: view.id, - input: { - mainGroupByFieldMetadataId: fieldMetadataItem.id, - }, - }); - - if (updatedViewResult.status === 'successful') { - const updatedCoreView = updatedViewResult.response.data - ?.updateCoreView as CoreView; - - if (isDefined(updatedCoreView)) { - const updatedViewConverted = convertCoreViewToView(updatedCoreView); - await loadRecordIndexStates( - updatedViewConverted, - objectMetadataItem, - ); - } - } - - const existingGroupKeys = new Set( - view.viewGroups.map( - (group) => `${view.mainGroupByFieldMetadataId}:${group.fieldValue}`, - ), + const viewGroupsToCreate = fieldMetadataItem.options + .filter( + (option) => + !existingGroupKeys.has(`${fieldMetadataItem.id}:${option.value}`), + ) + .sort((a, b) => a.value.localeCompare(b.value)) + .map( + (option, index) => + ({ + __typename: 'ViewGroup', + id: v4(), + fieldValue: option.value, + isVisible: true, + position: index, + }) satisfies ViewGroup, ); - const viewGroupsToCreate = fieldMetadataItem.options - // Avoid creation of already existing view groups - .filter( - (option) => - !existingGroupKeys.has(`${fieldMetadataItem.id}:${option.value}`), - ) - // Alphabetically sort the options by default - .sort((a, b) => a.value.localeCompare(b.value)) - .map( - (option, index) => - ({ - __typename: 'ViewGroup', - id: v4(), - fieldValue: option.value, - isVisible: true, - position: index, - }) satisfies ViewGroup, - ); + if ( + !existingGroupKeys.has(`${fieldMetadataItem.id}:`) && + fieldMetadataItem.isNullable === true + ) { + viewGroupsToCreate.push({ + __typename: 'ViewGroup', + id: v4(), + fieldValue: '', + isVisible: true, + position: fieldMetadataItem.options.length, + } satisfies ViewGroup); + } - if ( - !existingGroupKeys.has(`${fieldMetadataItem.id}:`) && - fieldMetadataItem.isNullable === true - ) { - viewGroupsToCreate.push({ - __typename: 'ViewGroup', - id: v4(), - fieldValue: '', - isVisible: true, - position: fieldMetadataItem.options.length, - } satisfies ViewGroup); - } + const newViewGroupsList = [ + ...view.viewGroups.filter( + (_group) => view.mainGroupByFieldMetadataId === fieldMetadataItem.id, + ), + ...viewGroupsToCreate, + ]; - const newViewGroupsList = [ - ...view.viewGroups.filter( - (_group) => - view.mainGroupByFieldMetadataId === fieldMetadataItem.id, - ), - ...viewGroupsToCreate, - ]; + setRecordGroupsFromViewGroups({ + viewId: view.id, + mainGroupByFieldMetadataId: fieldMetadataItem.id, + viewGroups: newViewGroupsList, + objectMetadataItem, + }); - setRecordGroupsFromViewGroups({ - viewId: view.id, - mainGroupByFieldMetadataId: fieldMetadataItem.id, - viewGroups: newViewGroupsList, - objectMetadataItem, - }); - - await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); - }, + await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); + }, [ currentViewIdCallbackState, getViewFromPrefetchState, @@ -138,43 +132,39 @@ export const useHandleRecordGroupField = () => { objectMetadataItem, refreshCoreViewsByObjectMetadataId, loadRecordIndexStates, + store, ], ); - const resetRecordGroupField = useRecoilCallback( - ({ snapshot }) => - async () => { - const currentViewId = snapshot - .getLoadable(currentViewIdCallbackState) - .getValue(); + const resetRecordGroupField = useCallback(async () => { + const currentViewId = store.get(currentViewIdCallbackState); - if (!currentViewId) { - return; - } + if (!currentViewId) { + return; + } - const view = getViewFromPrefetchState(currentViewId); + const view = getViewFromPrefetchState(currentViewId); - if (isUndefinedOrNull(view)) { - return; - } + if (isUndefinedOrNull(view)) { + return; + } - if (view.viewGroups.length === 0) { - return; - } + if (view.viewGroups.length === 0) { + return; + } - await performViewAPIUpdate({ - id: view.id, - input: { - mainGroupByFieldMetadataId: null, - }, - }); + await performViewAPIUpdate({ + id: view.id, + input: { + mainGroupByFieldMetadataId: null, }, - [ - currentViewIdCallbackState, - getViewFromPrefetchState, - performViewAPIUpdate, - ], - ); + }); + }, [ + currentViewIdCallbackState, + getViewFromPrefetchState, + performViewAPIUpdate, + store, + ]); return { handleRecordGroupFieldChange, resetRecordGroupField }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts index 21d0c09814..e9456f33ec 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnSort.ts @@ -3,9 +3,9 @@ import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMeta import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsertRecordSort'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { ViewSortDirection } from '~/generated-metadata/graphql'; @@ -26,42 +26,44 @@ export const useHandleToggleColumnSort = ({ const { upsertRecordSort } = useUpsertRecordSort(); - const currentRecordSortsCallbackState = useRecoilComponentCallbackState( - currentRecordSortsComponentState, - ); + const currentRecordSortsCallbackState = + useRecoilComponentStateCallbackStateV2(currentRecordSortsComponentState); - const handleToggleColumnSort = useRecoilCallback( - ({ snapshot }) => - (fieldMetadataId: string) => { - const correspondingColumnDefinition = columnDefinitions.find( - (columnDefinition) => - columnDefinition.fieldMetadataId === fieldMetadataId, - ); + const store = useStore(); - if (!isDefined(correspondingColumnDefinition)) return; + const handleToggleColumnSort = useCallback( + (fieldMetadataId: string) => { + const correspondingColumnDefinition = columnDefinitions.find( + (columnDefinition) => + columnDefinition.fieldMetadataId === fieldMetadataId, + ); - const currentRecordSorts = getSnapshotValue( - snapshot, - currentRecordSortsCallbackState, - ); + if (!isDefined(correspondingColumnDefinition)) return; - const existingSort = currentRecordSorts.find( - (sort) => sort.fieldMetadataId === fieldMetadataId, - ); + const currentRecordSorts = store.get(currentRecordSortsCallbackState); - const newSort: RecordSort = { - id: existingSort?.id ?? v4(), - fieldMetadataId, - direction: existingSort - ? existingSort.direction === ViewSortDirection.ASC - ? ViewSortDirection.DESC - : ViewSortDirection.ASC - : ViewSortDirection.ASC, - }; + const existingSort = currentRecordSorts.find( + (sort) => sort.fieldMetadataId === fieldMetadataId, + ); - upsertRecordSort(newSort); - }, - [columnDefinitions, currentRecordSortsCallbackState, upsertRecordSort], + const newSort: RecordSort = { + id: existingSort?.id ?? v4(), + fieldMetadataId, + direction: existingSort + ? existingSort.direction === ViewSortDirection.ASC + ? ViewSortDirection.DESC + : ViewSortDirection.ASC + : ViewSortDirection.ASC, + }; + + upsertRecordSort(newSort); + }, + [ + columnDefinitions, + currentRecordSortsCallbackState, + store, + upsertRecordSort, + ], ); return handleToggleColumnSort; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts index ec365030c4..e800e1c907 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts @@ -6,11 +6,11 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { t } from '@lingui/core/macro'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; import { ViewFilterOperand } from 'twenty-shared/types'; type UseHandleToggleTrashColumnFilterProps = { @@ -30,7 +30,7 @@ export const useHandleToggleTrashColumnFilter = ({ useColumnDefinitionsFromObjectMetadata(objectMetadataItem); const isSoftDeleteFilterActiveComponentRecoilState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( isSoftDeleteFilterActiveComponentState, viewBarId, ); @@ -68,12 +68,13 @@ export const useHandleToggleTrashColumnFilter = ({ upsertRecordFilter(newFilter); }, [columnDefinitions, objectMetadataItem, upsertRecordFilter]); - const toggleSoftDeleteFilterState = useRecoilCallback( - ({ set }) => - (currentState: boolean) => { - set(isSoftDeleteFilterActiveComponentRecoilState, currentState); - }, - [isSoftDeleteFilterActiveComponentRecoilState], + const store = useStore(); + + const toggleSoftDeleteFilterState = useCallback( + (currentState: boolean) => { + store.set(isSoftDeleteFilterActiveComponentRecoilState, currentState); + }, + [isSoftDeleteFilterActiveComponentRecoilState, store], ); return { handleToggleTrashColumnFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts index 98d0a55b55..e7a91418bd 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts @@ -22,45 +22,47 @@ import { type ColumnDefinition } from '@/object-record/record-table/types/Column import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation'; import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { type View } from '@/views/types/View'; import { type ViewField } from '@/views/types/ViewField'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; import { useStore } from 'jotai'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useLoadRecordIndexStates = () => { const store = useStore(); const setContextStoreTargetedRecordsRuleComponentState = - useSetRecoilComponentState(contextStoreTargetedRecordsRuleComponentState); + useSetRecoilComponentStateV2(contextStoreTargetedRecordsRuleComponentState); - const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState); - const setRecordIndexOpenRecordIn = useSetRecoilState( + const setRecordIndexViewType = useSetRecoilStateV2(recordIndexViewTypeState); + const setRecordIndexOpenRecordIn = useSetRecoilStateV2( recordIndexOpenRecordInState, ); - const setRecordIndexGroupFieldMetadataItem = useSetRecoilComponentState( + const setRecordIndexGroupFieldMetadataItem = useSetRecoilComponentStateV2( recordIndexGroupFieldMetadataItemComponentState, ); - const setRecordIndexGroupAggregateOperation = useSetRecoilComponentState( + const setRecordIndexGroupAggregateOperation = useSetRecoilComponentStateV2( recordIndexGroupAggregateOperationComponentState, ); const setRecordIndexGroupAggregateFieldMetadataItem = - useSetRecoilComponentState( + useSetRecoilComponentStateV2( recordIndexGroupAggregateFieldMetadataItemComponentState, ); - const setRecordIndexShouldHideEmptyRecordGroups = useSetRecoilComponentState( - recordIndexShouldHideEmptyRecordGroupsComponentState, - ); + const setRecordIndexShouldHideEmptyRecordGroups = + useSetRecoilComponentStateV2( + recordIndexShouldHideEmptyRecordGroupsComponentState, + ); - const setRecordIndexCalendarFieldMetadataIdState = useSetRecoilState( + const setRecordIndexCalendarFieldMetadataIdState = useSetRecoilStateV2( recordIndexCalendarFieldMetadataIdState, ); @@ -69,111 +71,107 @@ export const useLoadRecordIndexStates = () => { const { setRecordGroupsFromViewGroups } = useSetRecordGroups(); - const onViewFieldsChange = useRecoilCallback( - ({ set, snapshot }) => - (viewFields: ViewField[], objectMetadataItem: ObjectMetadataItem) => { - const activeFieldMetadataItems = objectMetadataItem.fields.filter( - (field) => field.isActive && !isHiddenSystemField(field), - ); + const onViewFieldsChange = useCallback( + (viewFields: ViewField[], objectMetadataItem: ObjectMetadataItem) => { + const activeFieldMetadataItems = objectMetadataItem.fields.filter( + (field) => field.isActive && !isHiddenSystemField(field), + ); - const filterableFieldMetadataItems = jotaiStore.get( - availableFieldMetadataItemsForFilterFamilySelector.selectorFamily({ - objectMetadataItemId: objectMetadataItem.id, + const filterableFieldMetadataItems = jotaiStore.get( + availableFieldMetadataItemsForFilterFamilySelector.selectorFamily({ + objectMetadataItemId: objectMetadataItem.id, + }), + ); + + const sortableFieldMetadataItems = jotaiStore.get( + availableFieldMetadataItemsForSortFamilySelector.selectorFamily({ + objectMetadataItemId: objectMetadataItem.id, + }), + ); + + const columnDefinitions: ColumnDefinition[] = + activeFieldMetadataItems + .map((field, index) => + formatFieldMetadataItemAsColumnDefinition({ + position: index, + field, + objectMetadataItem, + }), + ) + .filter(filterAvailableTableColumns) + .map((column) => { + const existsInFilterDefinitions = filterableFieldMetadataItems.some( + (fieldMetadataItem) => + fieldMetadataItem.id === column.fieldMetadataId, + ); + + const existsInSortDefinitions = sortableFieldMetadataItems.some( + (fieldMetadataItem) => + fieldMetadataItem.id === column.fieldMetadataId, + ); + + return { + ...column, + isFilterable: existsInFilterDefinitions, + isSortable: existsInSortDefinitions, + }; + }); + + const newFieldDefinitions = mapViewFieldsToColumnDefinitions({ + viewFields, + columnDefinitions, + }); + + const existingRecordIndexFieldDefinitions = jotaiStore.get( + recordIndexFieldDefinitionsState.atom, + ); + + if ( + !isDeeplyEqual(existingRecordIndexFieldDefinitions, newFieldDefinitions) + ) { + jotaiStore.set( + recordIndexFieldDefinitionsState.atom, + newFieldDefinitions, + ); + } + + for (const viewField of viewFields) { + const viewFieldMetadataType = objectMetadataItem.fields?.find( + (field) => field.id === viewField.fieldMetadataId, + )?.type; + + const aggregateOperationForViewField = jotaiStore.get( + viewFieldAggregateOperationState.atomFamily({ + viewFieldId: viewField.id, }), ); - - const sortableFieldMetadataItems = jotaiStore.get( - availableFieldMetadataItemsForSortFamilySelector.selectorFamily({ - objectMetadataItemId: objectMetadataItem.id, - }), - ); - - const columnDefinitions: ColumnDefinition[] = - activeFieldMetadataItems - .map((field, index) => - formatFieldMetadataItemAsColumnDefinition({ - position: index, - field, - objectMetadataItem, - }), + const convertedViewFieldAggregateOperation = isDefined( + viewField.aggregateOperation, + ) + ? convertAggregateOperationToExtendedAggregateOperation( + viewField.aggregateOperation, + viewFieldMetadataType, ) - .filter(filterAvailableTableColumns) - .map((column) => { - const existsInFilterDefinitions = - filterableFieldMetadataItems.some( - (fieldMetadataItem) => - fieldMetadataItem.id === column.fieldMetadataId, - ); - - const existsInSortDefinitions = sortableFieldMetadataItems.some( - (fieldMetadataItem) => - fieldMetadataItem.id === column.fieldMetadataId, - ); - - return { - ...column, - isFilterable: existsInFilterDefinitions, - isSortable: existsInSortDefinitions, - }; - }); - - const newFieldDefinitions = mapViewFieldsToColumnDefinitions({ - viewFields, - columnDefinitions, - }); - - const existingRecordIndexFieldDefinitions = snapshot - .getLoadable(recordIndexFieldDefinitionsState) - .getValue(); + : viewField.aggregateOperation; if ( - !isDeeplyEqual( - existingRecordIndexFieldDefinitions, - newFieldDefinitions, - ) + aggregateOperationForViewField !== + convertedViewFieldAggregateOperation ) { - set(recordIndexFieldDefinitionsState, newFieldDefinitions); + jotaiStore.set( + viewFieldAggregateOperationState.atomFamily({ + viewFieldId: viewField.id, + }), + convertedViewFieldAggregateOperation, + ); } - - for (const viewField of viewFields) { - const viewFieldMetadataType = objectMetadataItem.fields?.find( - (field) => field.id === viewField.fieldMetadataId, - )?.type; - - const aggregateOperationForViewField = snapshot - .getLoadable( - viewFieldAggregateOperationState({ - viewFieldId: viewField.id, - }), - ) - .getValue(); - const convertedViewFieldAggregateOperation = isDefined( - viewField.aggregateOperation, - ) - ? convertAggregateOperationToExtendedAggregateOperation( - viewField.aggregateOperation, - viewFieldMetadataType, - ) - : viewField.aggregateOperation; - - if ( - aggregateOperationForViewField !== - convertedViewFieldAggregateOperation - ) { - set( - viewFieldAggregateOperationState({ - viewFieldId: viewField.id, - }), - convertedViewFieldAggregateOperation, - ); - } - } - }, + } + }, [], ); - const loadRecordIndexStates = useRecoilCallback( - () => async (view: View, objectMetadataItem: ObjectMetadataItem) => { + const loadRecordIndexStates = useCallback( + async (view: View, objectMetadataItem: ObjectMetadataItem) => { const filterableFieldMetadataItems = jotaiStore.get( availableFieldMetadataItemsForFilterFamilySelector.selectorFamily({ objectMetadataItemId: objectMetadataItem.id, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts index cef86555d1..25161a9060 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts @@ -8,9 +8,11 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/conte import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { canOpenObjectInSidePanel } from '@/object-record/utils/canOpenObjectInSidePanel'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { AppPath } from 'twenty-shared/types'; import { useIsMobile } from 'twenty-ui/utilities'; import { useNavigateApp } from '~/hooks/useNavigateApp'; @@ -25,73 +27,68 @@ export const useOpenRecordFromIndexView = () => { const isMobile = useIsMobile(); - const currentRecordFilters = useRecoilComponentCallbackState( + const currentRecordFilters = useRecoilComponentStateCallbackStateV2( currentRecordFiltersComponentState, recordIndexId, ); - const currentRecordSorts = useRecoilComponentCallbackState( + const currentRecordSorts = useRecoilComponentStateCallbackStateV2( currentRecordSortsComponentState, recordIndexId, ); - const currentRecordFilterGroups = useRecoilComponentCallbackState( + const currentRecordFilterGroups = useRecoilComponentStateCallbackStateV2( currentRecordFilterGroupsComponentState, recordIndexId, ); const { closeCommandMenu } = useCommandMenu(); - const openRecordFromIndexView = useRecoilCallback( - ({ snapshot, set }) => - ({ recordId }: { recordId: string }) => { - const recordIndexOpenRecordIn = snapshot - .getLoadable(recordIndexOpenRecordInState) - .getValue(); + const store = useStore(); - const parentViewFilters = snapshot - .getLoadable(currentRecordFilters) - .getValue(); + const openRecordFromIndexView = useCallback( + ({ recordId }: { recordId: string }) => { + const recordIndexOpenRecordIn = jotaiStore.get( + recordIndexOpenRecordInState.atom, + ); - const parentViewSorts = snapshot - .getLoadable(currentRecordSorts) - .getValue(); + const parentViewFilters = store.get(currentRecordFilters); - const parentViewFilterGroups = snapshot - .getLoadable(currentRecordFilterGroups) - .getValue(); + const parentViewSorts = store.get(currentRecordSorts); - set( - contextStoreRecordShowParentViewComponentState.atomFamily({ - instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, - }), - { - parentViewComponentId: recordIndexId, - parentViewObjectNameSingular: objectNameSingular, - parentViewFilterGroups, - parentViewFilters, - parentViewSorts, - }, - ); + const parentViewFilterGroups = store.get(currentRecordFilterGroups); - if ( - !isMobile && - recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL && - canOpenObjectInSidePanel(objectNameSingular) - ) { - openRecordInCommandMenu({ - recordId, - objectNameSingular, - resetNavigationStack: true, - }); - } else { - closeCommandMenu(); - navigate(AppPath.RecordShowPage, { - objectNameSingular, - objectRecordId: recordId, - }); - } - }, + store.set( + contextStoreRecordShowParentViewComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + { + parentViewComponentId: recordIndexId, + parentViewObjectNameSingular: objectNameSingular, + parentViewFilterGroups, + parentViewFilters, + parentViewSorts, + }, + ); + + if ( + !isMobile && + recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL && + canOpenObjectInSidePanel(objectNameSingular) + ) { + openRecordInCommandMenu({ + recordId, + objectNameSingular, + resetNavigationStack: true, + }); + } else { + closeCommandMenu(); + navigate(AppPath.RecordShowPage, { + objectNameSingular, + objectRecordId: recordId, + }); + } + }, [ currentRecordFilters, currentRecordSorts, @@ -102,6 +99,7 @@ export const useOpenRecordFromIndexView = () => { openRecordInCommandMenu, isMobile, closeCommandMenu, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts index 17c8579bf2..1be44b27a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts @@ -2,7 +2,7 @@ import { labelIdentifierFieldMetadataItemSelector } from '@/object-metadata/stat import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; @@ -19,7 +19,7 @@ export const useRecordIndexFieldMetadataDerivedStates = ( ]), ); - const currentRecordFields = useRecoilComponentValue( + const currentRecordFields = useRecoilComponentValueV2( currentRecordFieldsComponentState, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupCommonQueryVariables.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupCommonQueryVariables.ts index 7506b449e9..4c01985271 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupCommonQueryVariables.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupCommonQueryVariables.ts @@ -10,7 +10,8 @@ import { computeRecordGroupOptionsFilter } from '@/object-record/record-group/ut import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { combineFilters, computeRecordGqlOperationFilter, @@ -21,15 +22,15 @@ export const useRecordIndexGroupCommonQueryVariables = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); const { objectMetadataItems } = useObjectMetadataItems(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); @@ -42,7 +43,7 @@ export const useRecordIndexGroupCommonQueryVariables = () => { fields: objectMetadataItem.fields, }); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, ); @@ -58,7 +59,7 @@ export const useRecordIndexGroupCommonQueryVariables = () => { objectMetadataItems, ); - const recordGroupFieldMetadata = useRecoilComponentValue( + const recordGroupFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); @@ -67,7 +68,7 @@ export const useRecordIndexGroupCommonQueryVariables = () => { additionalFieldMetadataId: recordGroupFieldMetadata?.id, }); - const recordGroupDefinitions = useRecoilComponentValue( + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupsAggregatesGroupBy.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupsAggregatesGroupBy.ts index ed636f95f5..d19336bbfc 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupsAggregatesGroupBy.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexGroupsAggregatesGroupBy.ts @@ -11,7 +11,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { useAggregateGqlFieldsFromRecordIndexGroupAggregates } from '@/object-record/record-index/hooks/useAggregateGqlFieldsFromRecordIndexGroupAggregates'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; import { buildGroupByFieldObject } from '@/page-layout/widgets/graph/utils/buildGroupByFieldObject'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useQuery } from '@apollo/client'; import { type Nullable } from 'twenty-shared/types'; import { @@ -35,11 +35,11 @@ export const useRecordIndexGroupsAggregatesGroupBy = ({ }) => { const apolloCoreClient = useApolloCoreClient(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -67,7 +67,7 @@ export const useRecordIndexGroupsAggregatesGroupBy = ({ }) : EMPTY_QUERY; - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore.ts index 41c13ef7cd..92775e9186 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore.ts @@ -1,10 +1,10 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useRecordIndexIdFromCurrentContextStore = () => { - const contextStoreCurrentViewId = useRecoilComponentValue( + const contextStoreCurrentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayLabel.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayLabel.ts index c98f560346..b49918d0fb 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayLabel.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayLabel.ts @@ -2,31 +2,28 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte import { recordIndexAggregateDisplayLabelComponentState } from '@/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState'; import { getRecordAggregateDisplayLabel } from '@/object-record/record-index/utils/getRecordndexAggregateDisplayLabel'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; export const useSetRecordIndexAggregateDisplayLabel = () => { - const recordIndexAggregateDisplayLabelCallbackState = - useRecoilComponentCallbackState( + const recordIndexAggregateDisplayLabelAtom = + useRecoilComponentStateCallbackStateV2( recordIndexAggregateDisplayLabelComponentState, ); - const setRecordIndexAggregateDisplayLabel = useRecoilCallback( - ({ set }) => - ( - recordIndexGroupAggregateOperation: ExtendedAggregateOperations, - recordIndexGroupAggregateFieldMetadataItem: FieldMetadataItem, - ) => { - const { aggregateLabel } = getRecordAggregateDisplayLabel({ - aggregateOperation: recordIndexGroupAggregateOperation, - aggregateFieldMetadataItem: - recordIndexGroupAggregateFieldMetadataItem, - }); + const store = useStore(); - set(recordIndexAggregateDisplayLabelCallbackState, aggregateLabel); - }, - [recordIndexAggregateDisplayLabelCallbackState], - ); + const setRecordIndexAggregateDisplayLabel = ( + recordIndexGroupAggregateOperation: ExtendedAggregateOperations, + recordIndexGroupAggregateFieldMetadataItem: FieldMetadataItem, + ) => { + const { aggregateLabel } = getRecordAggregateDisplayLabel({ + aggregateOperation: recordIndexGroupAggregateOperation, + aggregateFieldMetadataItem: recordIndexGroupAggregateFieldMetadataItem, + }); + + store.set(recordIndexAggregateDisplayLabelAtom, aggregateLabel); + }; return { setRecordIndexAggregateDisplayLabel, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayValueForRecordGroupValue.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayValueForRecordGroupValue.ts index 4d72d9a2ea..cc3d2d41f1 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayValueForRecordGroupValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useSetRecordIndexAggregateDisplayValueForRecordGroupValue.ts @@ -2,58 +2,60 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte import { transformAggregateRawValueIntoAggregateDisplayValue } from '@/object-record/record-aggregate/utils/transformAggregateRawValueIntoAggregateDisplayValue'; import { recordIndexAggregateDisplayValueForGroupValueComponentFamilyState } from '@/object-record/record-index/states/recordIndexAggregateDisplayValueForGroupValueComponentFamilyState'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; -import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { UserContext } from '@/users/contexts/UserContext'; -import { useContext } from 'react'; -import { useRecoilCallback, useRecoilValue } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { type Nullable } from 'twenty-shared/types'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; export const useSetRecordIndexAggregateDisplayValueForRecordGroupValue = () => { const { dateFormat, timeFormat, timeZone } = useContext(UserContext); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const recordIndexAggregateValueByGroupValueCallbackState = - useRecoilComponentFamilyCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexAggregateDisplayValueForGroupValueComponentFamilyState, ); - const setRecordIndexAggregateDisplayValueForRecordGroupValue = - useRecoilCallback( - ({ set }) => - ( - recordIndexGroupAggregateOperation: ExtendedAggregateOperations, - recordIndexGroupAggregateFieldMetadataItem: FieldMetadataItem, - recordIndexGroupValue: string, - rawValue: Nullable, - ) => { - const aggregateDisplayValue = - transformAggregateRawValueIntoAggregateDisplayValue({ - aggregateFieldMetadataItem: - recordIndexGroupAggregateFieldMetadataItem, - aggregateOperation: recordIndexGroupAggregateOperation, - aggregateRawValue: rawValue, - dateFormat, - timeFormat, - timeZone, - localeCatalog: dateLocale.localeCatalog, - }); + const store = useStore(); - set( - recordIndexAggregateValueByGroupValueCallbackState({ - groupValue: recordIndexGroupValue, - }), - aggregateDisplayValue, - ); - }, - [ - recordIndexAggregateValueByGroupValueCallbackState, - dateFormat, - dateLocale, - timeFormat, - timeZone, - ], - ); + const setRecordIndexAggregateDisplayValueForRecordGroupValue = useCallback( + ( + recordIndexGroupAggregateOperation: ExtendedAggregateOperations, + recordIndexGroupAggregateFieldMetadataItem: FieldMetadataItem, + recordIndexGroupValue: string, + rawValue: Nullable, + ) => { + const aggregateDisplayValue = + transformAggregateRawValueIntoAggregateDisplayValue({ + aggregateFieldMetadataItem: + recordIndexGroupAggregateFieldMetadataItem, + aggregateOperation: recordIndexGroupAggregateOperation, + aggregateRawValue: rawValue, + dateFormat, + timeFormat, + timeZone, + localeCatalog: dateLocale.localeCatalog, + }); + + store.set( + recordIndexAggregateValueByGroupValueCallbackState({ + groupValue: recordIndexGroupValue, + }), + aggregateDisplayValue, + ); + }, + [ + recordIndexAggregateValueByGroupValueCallbackState, + dateFormat, + dateLocale, + store, + timeFormat, + timeZone, + ], + ); return { setRecordIndexAggregateDisplayValueForRecordGroupValue, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState.ts index abee0d4057..b707a69c09 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordIndexAggregateDisplayLabelComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexAggregateDisplayLabelForGroupValueComponentFamilyState', defaultValue: null, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayValueForGroupValueComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayValueForGroupValueComponentFamilyState.ts index 1af450362b..531d411f7f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayValueForGroupValueComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexAggregateDisplayValueForGroupValueComponentFamilyState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const recordIndexAggregateDisplayValueForGroupValueComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'recordIndexAggregateDisplayValueForGroupValueComponentFamilyState', defaultValue: null, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState.ts index 3f8236ff97..901cf9d3c3 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const recordIndexCalendarFieldMetadataIdState = createState< +export const recordIndexCalendarFieldMetadataIdState = createStateV2< string | null >({ key: 'recordIndexCalendarFieldMetadataIdState', diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarLayoutState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarLayoutState.ts index 7d22095b33..edb42c22e3 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarLayoutState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexCalendarLayoutState.ts @@ -1,7 +1,9 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { ViewCalendarLayout } from '~/generated-metadata/graphql'; -export const recordIndexCalendarLayoutState = createState({ - key: 'recordIndexCalendarLayoutState', - defaultValue: ViewCalendarLayout.MONTH, -}); +export const recordIndexCalendarLayoutState = createStateV2( + { + key: 'recordIndexCalendarLayoutState', + defaultValue: ViewCalendarLayout.MONTH, + }, +); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexEntityCountByGroupComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexEntityCountByGroupComponentFamilyState.ts index 01e79df460..f3ff3e704d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexEntityCountByGroupComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexEntityCountByGroupComponentFamilyState.ts @@ -1,10 +1,12 @@ import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexEntityCountByGroupComponentFamilyState = - createComponentFamilyState({ - key: 'recordIndexEntityCountByGroupComponentFamilyState', - defaultValue: undefined, - componentInstanceContext: ViewComponentInstanceContext, - }); + createComponentFamilyStateV2( + { + key: 'recordIndexEntityCountByGroupComponentFamilyState', + defaultValue: undefined, + componentInstanceContext: ViewComponentInstanceContext, + }, + ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexFieldDefinitionsState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexFieldDefinitionsState.ts index be7b993200..e2c7784f66 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexFieldDefinitionsState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexFieldDefinitionsState.ts @@ -1,8 +1,8 @@ import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const recordIndexFieldDefinitionsState = createState< +export const recordIndexFieldDefinitionsState = createStateV2< ColumnDefinition[] >({ key: 'recordIndexFieldDefinitionsState', diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateFieldMetadataItemComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateFieldMetadataItemComponentState.ts index 47f8c927fc..44a5ab7a11 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateFieldMetadataItemComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateFieldMetadataItemComponentState.ts @@ -1,9 +1,9 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordIndexGroupAggregateFieldMetadataItemComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexGroupAggregateFieldMetadataItemComponentState', defaultValue: null, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState.ts index f2d25fa827..3d13b268d3 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState.ts @@ -1,9 +1,9 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordIndexGroupAggregateOperationComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexGroupAggregateOperationComponentState', defaultValue: null, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState.ts index 96e0b8ec00..e1b584ff7e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState.ts @@ -1,9 +1,9 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexGroupFieldMetadataItemComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexGroupFieldMetadataItemComponentState', defaultValue: undefined, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState.ts index d28017e25c..92833e534d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState.ts @@ -1,9 +1,9 @@ import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexHasFetchedAllRecordsByGroupComponentState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'recordIndexHasFetchedAllRecordsByGroupComponentState', componentInstanceContext: ViewComponentInstanceContext, defaultValue: false, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexOpenRecordInState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexOpenRecordInState.ts index 1b950156a1..054ed22633 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexOpenRecordInState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexOpenRecordInState.ts @@ -1,7 +1,9 @@ import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const recordIndexOpenRecordInState = createState({ - key: 'recordIndexOpenRecordInState', - defaultValue: ViewOpenRecordInType.SIDE_PANEL, -}); +export const recordIndexOpenRecordInState = createStateV2( + { + key: 'recordIndexOpenRecordInState', + defaultValue: ViewOpenRecordInType.SIDE_PANEL, + }, +); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupSortComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupSortComponentState.ts index 8256df8d56..61fb1e4155 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupSortComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupSortComponentState.ts @@ -1,9 +1,9 @@ import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexRecordGroupSortComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexRecordGroupSortComponentState', defaultValue: RecordGroupSort.Manual, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState.ts index 43c73df127..0e465a159f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordIndexRecordGroupsAreInInitialLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexRecordGroupsAreInInitialLoadingComponentState', defaultValue: false, componentInstanceContext: ContextStoreComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState.ts index 7932bab14f..3a826abbd9 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState.ts @@ -1,9 +1,9 @@ import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexRecordIdsByGroupComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'recordIndexRecordIdsByGroupComponentFamilyState', defaultValue: [], componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState.ts index d5ca3c1f62..be0ef93ca3 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexShouldHideEmptyRecordGroupsComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexShouldHideEmptyRecordGroupsComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordIndexShouldHideEmptyRecordGroupsComponentState', defaultValue: false, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexViewTypeState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexViewTypeState.ts index 782b12cc7e..cfb711c0fd 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexViewTypeState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/recordIndexViewTypeState.ts @@ -1,7 +1,7 @@ import { type ViewType } from '@/views/types/ViewType'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const recordIndexViewTypeState = createState({ +export const recordIndexViewTypeState = createStateV2({ key: 'recordIndexViewTypeState', defaultValue: undefined, }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsOfAllRecordGroupsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsOfAllRecordGroupsComponentSelector.ts index feae320b56..3d71c74c0e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsOfAllRecordGroupsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsOfAllRecordGroupsComponentSelector.ts @@ -1,32 +1,28 @@ import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const allRecordIdsOfAllRecordGroupsComponentSelector = - createComponentSelector({ - key: 'recordIndexAllRecordIdsComponentSelector', + createComponentSelectorV2({ + key: 'allRecordIdsOfAllRecordGroupsComponentSelector', componentInstanceContext: ViewComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupIds = get(recordGroupIdsComponentState, { + instanceId, + }); if (recordGroupIds.length === 0) { return []; } return recordGroupIds.reduce((acc, recordGroupId) => { - const rowIds = get( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordGroupId, - }), - ); + const rowIds = get(recordIndexRecordIdsByGroupComponentFamilyState, { + instanceId, + familyKey: recordGroupId, + }); return [...acc, ...rowIds]; }, []); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsWithoutGroupsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsWithoutGroupsComponentSelector.ts index ca6563f0a5..44fd2af08a 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsWithoutGroupsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/allRecordIdsWithoutGroupsComponentSelector.ts @@ -1,21 +1,18 @@ import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { NO_RECORD_GROUP_FAMILY_KEY } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -import { type SparseArray } from '~/types/SparseArray'; export const allRecordIdsWithoutGroupsComponentSelector = - createComponentSelector>({ + createComponentSelectorV2({ key: 'allRecordIdsWithoutGroupsComponentSelector', componentInstanceContext: ViewComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - return get( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ - instanceId, - familyKey: NO_RECORD_GROUP_FAMILY_KEY, - }), - ); + return get(recordIndexRecordIdsByGroupComponentFamilyState, { + instanceId, + familyKey: NO_RECORD_GROUP_FAMILY_KEY, + }); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector.ts index d4b79a34d9..b166d356c1 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector.ts @@ -1,56 +1,39 @@ import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const NO_RECORD_GROUP_FAMILY_KEY = 'record-group-default-id'; -export const recordIndexAllRecordIdsComponentSelector = createComponentSelector< - string[] ->({ - key: 'recordIndexAllRecordIdsComponentSelector', - componentInstanceContext: ViewComponentInstanceContext, - get: - ({ instanceId }) => - ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ +export const recordIndexAllRecordIdsComponentSelector = + createComponentSelectorV2({ + key: 'recordIndexAllRecordIdsComponentSelector', + componentInstanceContext: ViewComponentInstanceContext, + get: + ({ instanceId }) => + ({ get }) => { + const recordGroupIds = get(recordGroupIdsComponentState, { instanceId, - }), - ); + }); - if (recordGroupIds.length === 0) { - return get( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ + if (recordGroupIds.length === 0) { + return get(recordIndexRecordIdsByGroupComponentFamilyState, { instanceId, familyKey: NO_RECORD_GROUP_FAMILY_KEY, - }), + }); + } + + return recordGroupIds.reduce( + (acc, recordGroupId) => { + const rowIds = get( + recordIndexRecordIdsByGroupComponentFamilyState, + { instanceId, familyKey: recordGroupId }, + ); + + return [...acc, ...rowIds]; + }, + [], ); - } - - return recordGroupIds.reduce( - (acc, recordGroupId) => { - const rowIds = get( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordGroupId, - }), - ); - - return [...acc, ...rowIds]; - }, - [], - ); - }, - set: - ({ instanceId }) => - ({ set }, recordIds) => - set( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ - instanceId, - familyKey: NO_RECORD_GROUP_FAMILY_KEY, - }), - recordIds, - ), -}); + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexHasRecordsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexHasRecordsComponentSelector.ts index e43ed84bab..3e1c128939 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexHasRecordsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexHasRecordsComponentSelector.ts @@ -1,19 +1,17 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexHasRecordsComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'recordIndexHasRecordsComponentSelector', componentInstanceContext: ViewComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); return allRecordIds.length > 0; }, diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexRecordGroupIsDraggableSortComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexRecordGroupIsDraggableSortComponentSelector.ts index 90c832839c..2d32060b31 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexRecordGroupIsDraggableSortComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/selectors/recordIndexRecordGroupIsDraggableSortComponentSelector.ts @@ -1,21 +1,18 @@ import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort'; import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const recordIndexRecordGroupIsDraggableSortComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'recordIndexRecordGroupIsDraggableSortComponentSelector', componentInstanceContext: ViewComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { return ( - get( - recordIndexRecordGroupSortComponentState.atomFamily({ - instanceId, - }), - ) === RecordGroupSort.Manual + get(recordIndexRecordGroupSortComponentState, { instanceId }) === + RecordGroupSort.Manual ); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts index 795895336d..10283833a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const shouldCompactRecordIndexLabelIdentifierComponentState = - createComponentState({ + createComponentStateV2({ key: 'shouldCompactRecordIndexLabelIdentifierComponentState', componentInstanceContext: ContextStoreComponentInstanceContext, defaultValue: false, diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditMode.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditMode.tsx index 64d00d4774..ba7650ffac 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCellEditMode.tsx @@ -5,8 +5,8 @@ import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-r import { RecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext'; import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { autoUpdate, @@ -42,12 +42,12 @@ export const RecordInlineCellEditMode = ({ RecordFieldComponentInstanceContext, ); - const setFieldInputLayoutDirection = useSetRecoilComponentState( + const setFieldInputLayoutDirection = useSetRecoilComponentStateV2( recordFieldInputLayoutDirectionComponentState, recordFieldComponentInstanceId, ); - const setFieldInputLayoutDirectionLoading = useSetRecoilComponentState( + const setFieldInputLayoutDirectionLoading = useSetRecoilComponentStateV2( recordFieldInputLayoutDirectionLoadingComponentState, recordFieldComponentInstanceId, ); @@ -63,7 +63,7 @@ export const RecordInlineCellEditMode = ({ }, }; - const isFieldInError = useRecoilComponentValue( + const isFieldInError = useRecoilComponentValueV2( recordFieldInputIsFieldInErrorComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsSelectedRecords.ts b/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsSelectedRecords.ts index fdc7a69afe..ca92f4d350 100644 --- a/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsSelectedRecords.ts +++ b/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsSelectedRecords.ts @@ -1,15 +1,16 @@ import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState'; import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; -import { recordStoreRecordsSelector } from '@/object-record/record-store/states/selectors/recordStoreRecordsSelector'; +import { recordStoreRecordsSelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreRecordsSelectorV2'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; -import { useRecoilValue } from 'recoil'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; export const useMergeRecordsSelectedRecords = () => { const mergeRecordsPageInstanceId = useComponentInstanceStateContext( CommandMenuPageComponentInstanceContext, )?.instanceId; - const commandMenuNavigationMorphItemsByPage = useRecoilValue( + const commandMenuNavigationMorphItemsByPage = useRecoilValueV2( commandMenuNavigationMorphItemsByPageState, ); @@ -18,10 +19,9 @@ export const useMergeRecordsSelectedRecords = () => { .get(mergeRecordsPageInstanceId ?? '') ?.map((morphItem) => morphItem.recordId) ?? []; - const selectedRecords = useRecoilValue( - recordStoreRecordsSelector({ - recordIds: selectedRecordIds, - }), + const selectedRecords = useFamilySelectorValueV2( + recordStoreRecordsSelectorV2, + { recordIds: selectedRecordIds }, ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-picker/hooks/useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId.ts b/packages/twenty-front/src/modules/object-record/record-picker/hooks/useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId.ts index 5f6e1b65f1..df4862c515 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/hooks/useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/hooks/useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId.ts @@ -1,8 +1,8 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { searchRecordStoreFamilyState } from '@/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState'; import { multipleRecordPickerSinglePickableMorphItemComponentFamilySelector } from '@/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerSinglePickableMorphItemComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; type UseRecordPickerGetRecordAndObjectMetadataItemFromRecordIdProps = { @@ -15,12 +15,15 @@ export const useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId = }: UseRecordPickerGetRecordAndObjectMetadataItemFromRecordIdProps) => { const { objectMetadataItems } = useObjectMetadataItems(); - const pickableMorphItem = useRecoilComponentFamilyValue( + const pickableMorphItem = useRecoilComponentFamilySelectorValueV2( multipleRecordPickerSinglePickableMorphItemComponentFamilySelector, recordId, ); - const searchRecord = useRecoilValue(searchRecordStoreFamilyState(recordId)); + const searchRecord = useFamilyRecoilValueV2( + searchRecordStoreFamilyState, + recordId, + ); if (!isDefined(pickableMorphItem) || !isDefined(searchRecord)) { return { searchRecord: null, objectMetadataItem: null }; diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx index e5baf59233..902893034e 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx @@ -1,3 +1,6 @@ +import { useCallback, useRef } from 'react'; +import { useStore } from 'jotai'; + import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { MultipleRecordPickerItemsDisplay } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerItemsDisplay'; import { MultipleRecordPickerOnClickOutsideEffect } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerOnClickOutsideEffect'; @@ -13,9 +16,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRef } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { Key } from 'ts-key-enum'; import { isDefined } from 'twenty-shared/utils'; import { t } from '@lingui/core/macro'; @@ -51,29 +52,28 @@ export const MultipleRecordPicker = ({ selectableListComponentInstanceId, ); - const multipleRecordPickerSearchFilterState = useRecoilComponentCallbackState( - multipleRecordPickerSearchFilterComponentState, - componentInstanceId, - ); + const multipleRecordPickerSearchFilterState = + useRecoilComponentStateCallbackStateV2( + multipleRecordPickerSearchFilterComponentState, + componentInstanceId, + ); const multipleRecordPickerPickableMorphItemsState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( multipleRecordPickerPickableMorphItemsComponentState, componentInstanceId, ); - const resetState = useRecoilCallback( - ({ set }) => { - return () => { - set(multipleRecordPickerPickableMorphItemsState, []); - set(multipleRecordPickerSearchFilterState, ''); - }; - }, - [ - multipleRecordPickerPickableMorphItemsState, - multipleRecordPickerSearchFilterState, - ], - ); + const store = useStore(); + + const resetState = useCallback(() => { + store.set(multipleRecordPickerPickableMorphItemsState, []); + store.set(multipleRecordPickerSearchFilterState, ''); + }, [ + multipleRecordPickerPickableMorphItemsState, + multipleRecordPickerSearchFilterState, + store, + ]); const handleSubmit = () => { onSubmit?.(); @@ -97,17 +97,12 @@ export const MultipleRecordPicker = ({ const containerRef = useRef(null); - const handleCreateNewButtonClick = useRecoilCallback( - ({ snapshot }) => { - return () => { - const recordPickerSearchFilter = snapshot - .getLoadable(multipleRecordPickerSearchFilterState) - .getValue(); - onCreate?.(recordPickerSearchFilter); - }; - }, - [multipleRecordPickerSearchFilterState, onCreate], - ); + const handleCreateNewButtonClick = useCallback(() => { + const recordPickerSearchFilter = store.get( + multipleRecordPickerSearchFilterState, + ); + onCreate?.(recordPickerSearchFilter); + }, [multipleRecordPickerSearchFilterState, onCreate, store]); const hasCreatePermissionOnObjectForCreate = useObjectPermissionsForObject( objectMetadataItemIdForCreate ?? '', diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerFetchMoreLoader.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerFetchMoreLoader.tsx index 37c9ecfa7f..75ccc5d607 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerFetchMoreLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerFetchMoreLoader.tsx @@ -11,12 +11,13 @@ import { multipleRecordPickerShouldShowInitialLoadingComponentState } from '@/ob import { multipleRecordPickerShouldShowSkeletonComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState'; import { multipleRecordPickerPaginationSelector } from '@/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPaginationSelector'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import styled from '@emotion/styled'; import { useCallback } from 'react'; import { useInView } from 'react-intersection-observer'; -import { useRecoilCallback } from 'recoil'; const StyledText = styled.div` align-items: center; @@ -36,60 +37,57 @@ export const MultipleRecordPickerFetchMoreLoader = () => { const [ multipleRecordPickerIsFetchingMore, setMultipleRecordPickerIsFetchingMore, - ] = useRecoilComponentState(multipleRecordPickerIsFetchingMoreComponentState); + ] = useRecoilComponentStateV2( + multipleRecordPickerIsFetchingMoreComponentState, + ); const componentInstanceId = useAvailableComponentInstanceIdOrThrow( MultipleRecordPickerComponentInstanceContext, ); - const paginationState = useRecoilComponentValue( + const paginationState = useRecoilComponentSelectorValueV2( multipleRecordPickerPaginationSelector, componentInstanceId, ); - const isLoading = useRecoilComponentValue( + const isLoading = useRecoilComponentValueV2( multipleRecordPickerIsLoadingComponentState, componentInstanceId, ); - const searchFilter = useRecoilComponentValue( + const searchFilter = useRecoilComponentValueV2( multipleRecordPickerSearchFilterComponentState, componentInstanceId, ); - const multipleRecordPickerShouldShowInitialLoading = useRecoilComponentValue( - multipleRecordPickerShouldShowInitialLoadingComponentState, - ); + const multipleRecordPickerShouldShowInitialLoading = + useRecoilComponentValueV2( + multipleRecordPickerShouldShowInitialLoadingComponentState, + ); - const multipleRecordPickerShouldShowSkeleton = useRecoilComponentValue( + const multipleRecordPickerShouldShowSkeleton = useRecoilComponentValueV2( multipleRecordPickerShouldShowSkeletonComponentState, ); const { performSearch } = useMultipleRecordPickerPerformSearch(); - const fetchMore = useRecoilCallback( - ({ snapshot }) => - async () => { - const paginationState = snapshot - .getLoadable( - multipleRecordPickerPaginationState.atomFamily({ - instanceId: componentInstanceId, - }), - ) - .getValue(); + const fetchMore = useCallback(async () => { + const currentPaginationState = jotaiStore.get( + multipleRecordPickerPaginationState.atomFamily({ + instanceId: componentInstanceId, + }), + ); - if (isLoading || !paginationState.hasNextPage) { - return; - } + if (isLoading || !currentPaginationState.hasNextPage) { + return; + } - await performSearch({ - multipleRecordPickerInstanceId: componentInstanceId, - forceSearchFilter: searchFilter, - loadMore: true, - }); - }, - [componentInstanceId, performSearch, searchFilter, isLoading], - ); + await performSearch({ + multipleRecordPickerInstanceId: componentInstanceId, + forceSearchFilter: searchFilter, + loadMore: true, + }); + }, [componentInstanceId, performSearch, searchFilter, isLoading]); const { ref } = useInView({ onChange: useCallback( diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerLoadingEffect.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerLoadingEffect.tsx index e23be97c33..68d89d37c0 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerLoadingEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerLoadingEffect.tsx @@ -1,24 +1,24 @@ import { multipleRecordPickerIsFetchingMoreComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsFetchingMoreComponentState'; import { multipleRecordPickerIsLoadingComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsLoadingComponentState'; import { multipleRecordPickerShouldShowSkeletonComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect, useState } from 'react'; import { useDebouncedCallback } from 'use-debounce'; export const MultipleRecordPickerLoadingEffect = () => { const [previousLoading, setPreviousLoading] = useState(false); - const loading = useRecoilComponentValue( + const loading = useRecoilComponentValueV2( multipleRecordPickerIsLoadingComponentState, ); - const setMultipleRecordPickerShowSkeleton = useSetRecoilComponentState( + const setMultipleRecordPickerShowSkeleton = useSetRecoilComponentStateV2( multipleRecordPickerShouldShowSkeletonComponentState, ); - const [multipleRecordPickerIsFetchingMore] = useRecoilComponentState( + const [multipleRecordPickerIsFetchingMore] = useRecoilComponentStateV2( multipleRecordPickerIsFetchingMoreComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx index 67cefb5aa0..24a46d3704 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx @@ -10,9 +10,9 @@ import { type RecordPickerPickableMorphItem } from '@/object-record/record-picke import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { capitalize } from 'twenty-shared/utils'; import { Avatar } from 'twenty-ui/display'; import { MenuItemMultiSelectAvatar } from 'twenty-ui/navigation'; @@ -49,11 +49,12 @@ export const MultipleRecordPickerMenuItemContent = ({ selectableListComponentInstanceId, ); - const isRecordSelectedWithObjectItem = useRecoilComponentFamilyValue( - multipleRecordPickerIsSelectedComponentFamilySelector, - searchRecord.recordId, - componentInstanceId, - ); + const isRecordSelectedWithObjectItem = + useRecoilComponentFamilySelectorValueV2( + multipleRecordPickerIsSelectedComponentFamilySelector, + searchRecord.recordId, + componentInstanceId, + ); const handleSelectChange = (isSelected: boolean) => { onChange({ @@ -68,7 +69,7 @@ export const MultipleRecordPickerMenuItemContent = ({ const displayText = searchRecord.label?.trim() || t`Untitled ${labelSingular}`; - const searchableObjectMetadataItems = useRecoilComponentValue( + const searchableObjectMetadataItems = useRecoilComponentValueV2( multipleRecordPickerSearchableObjectMetadataItemsComponentState, componentInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx index 8fc4c5143a..78c3db4ec1 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx @@ -13,9 +13,11 @@ import { type RecordPickerPickableMorphItem } from '@/object-record/record-picke import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; type MultipleRecordPickerMenuItemsProps = { onChange?: (morphItem: RecordPickerPickableMorphItem) => void; @@ -33,47 +35,46 @@ export const MultipleRecordPickerMenuItems = ({ const selectableListComponentInstanceId = getMultipleRecordPickerSelectableListId(componentInstanceId); - const pickableRecordIds = useRecoilComponentValue( + const pickableRecordIds = useRecoilComponentSelectorValueV2( multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector, componentInstanceId, ); - const multipleRecordPickerPickableMorphItemsState = - useRecoilComponentCallbackState( + const multipleRecordPickerPickableMorphItemsAtom = + useRecoilComponentStateCallbackStateV2( multipleRecordPickerPickableMorphItemsComponentState, componentInstanceId, ); - const handleChange = useRecoilCallback( - ({ snapshot, set }) => { - return (morphItem: RecordPickerPickableMorphItem) => { - const previousMorphItems = snapshot - .getLoadable(multipleRecordPickerPickableMorphItemsState) - .getValue(); + const handleChange = useCallback( + (morphItem: RecordPickerPickableMorphItem) => { + const previousMorphItems = jotaiStore.get( + multipleRecordPickerPickableMorphItemsAtom, + ); - const existingMorphItemIndex = previousMorphItems.findIndex( - (item) => item.recordId === morphItem.recordId, - ); + const existingMorphItemIndex = previousMorphItems.findIndex( + (item) => item.recordId === morphItem.recordId, + ); - const newMorphItems = [...previousMorphItems]; + const newMorphItems = [...previousMorphItems]; - if (existingMorphItemIndex === -1) { - newMorphItems.push(morphItem); - } else { - newMorphItems[existingMorphItemIndex] = morphItem; - } + if (existingMorphItemIndex === -1) { + newMorphItems.push(morphItem); + } else { + newMorphItems[existingMorphItemIndex] = morphItem; + } - set(multipleRecordPickerPickableMorphItemsState, newMorphItems); - }; + jotaiStore.set(multipleRecordPickerPickableMorphItemsAtom, newMorphItems); }, - [multipleRecordPickerPickableMorphItemsState], + [multipleRecordPickerPickableMorphItemsAtom], ); - const multipleRecordPickerShouldShowInitialLoading = useRecoilComponentValue( - multipleRecordPickerShouldShowInitialLoadingComponentState, - ); + const multipleRecordPickerShouldShowInitialLoading = + useRecoilComponentValueV2( + multipleRecordPickerShouldShowInitialLoadingComponentState, + ); - const multipleRecordPickerShouldShowSkeleton = useRecoilComponentValue( + const multipleRecordPickerShouldShowSkeleton = useRecoilComponentValueV2( multipleRecordPickerShouldShowSkeletonComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx index e94dfbef4d..bb33ce99f6 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx @@ -1,10 +1,12 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch'; import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useDebouncedCallback } from 'use-debounce'; export const MultipleRecordPickerSearchInput = () => { @@ -13,27 +15,28 @@ export const MultipleRecordPickerSearchInput = () => { ); const [recordPickerSearchFilter, setRecordPickerSearchFilter] = - useRecoilComponentState(multipleRecordPickerSearchFilterComponentState); + useRecoilComponentStateV2(multipleRecordPickerSearchFilterComponentState); const { performSearch } = useMultipleRecordPickerPerformSearch(); - const debouncedSearch = useDebouncedCallback( - useRecoilCallback( - ({ set }) => - (searchFilter: string) => { - set( - multipleRecordPickerSearchFilterComponentState.atomFamily({ - instanceId: componentInstanceId, - }), - searchFilter, - ); + const store = useStore(); - performSearch({ - multipleRecordPickerInstanceId: componentInstanceId, - forceSearchFilter: searchFilter, - }); - }, - [componentInstanceId, performSearch], + const debouncedSearch = useDebouncedCallback( + useCallback( + (searchFilter: string) => { + store.set( + multipleRecordPickerSearchFilterComponentState.atomFamily({ + instanceId: componentInstanceId, + }), + searchFilter, + ); + + performSearch({ + multipleRecordPickerInstanceId: componentInstanceId, + forceSearchFilter: searchFilter, + }); + }, + [componentInstanceId, performSearch, store], ), 500, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen.ts index 6fbe98b000..80640b1a08 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen.ts @@ -1,39 +1,37 @@ import { multipleRecordPickerShouldShowInitialLoadingComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowInitialLoadingComponentState'; import { multipleRecordPickerShouldShowSkeletonComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useMultipleRecordPickerOpen = () => { - const openMultipleRecordPicker = useRecoilCallback( - ({ set }) => - (recordPickerComponentInstanceId: string) => { - set( - multipleRecordPickerShouldShowInitialLoadingComponentState.atomFamily( - { - instanceId: recordPickerComponentInstanceId, - }, - ), - true, - ); - set( - multipleRecordPickerShouldShowSkeletonComponentState.atomFamily({ - instanceId: recordPickerComponentInstanceId, - }), - true, - ); - setTimeout(() => { - set( - multipleRecordPickerShouldShowInitialLoadingComponentState.atomFamily( - { - instanceId: recordPickerComponentInstanceId, - }, - ), - false, - ); - }, 100); - }, + const setInitialLoading = useCallback( + (recordPickerComponentInstanceId: string, value: boolean) => { + jotaiStore.set( + multipleRecordPickerShouldShowInitialLoadingComponentState.atomFamily({ + instanceId: recordPickerComponentInstanceId, + }), + value, + ); + }, [], ); + const openMultipleRecordPicker = useCallback( + (recordPickerComponentInstanceId: string) => { + setInitialLoading(recordPickerComponentInstanceId, true); + jotaiStore.set( + multipleRecordPickerShouldShowSkeletonComponentState.atomFamily({ + instanceId: recordPickerComponentInstanceId, + }), + true, + ); + setTimeout(() => { + setInitialLoading(recordPickerComponentInstanceId, false); + }, 100); + }, + [setInitialLoading], + ); + return { openMultipleRecordPicker, }; diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts index df631c9a11..3fb760f656 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch.ts @@ -14,13 +14,16 @@ import { type RecordPickerPickableMorphItem } from '@/object-record/record-picke import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId'; import { type ApolloClient } from '@apollo/client'; import { isNonEmptyArray } from '@sniptt/guards'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { type SearchRecord, type SearchResultEdge } from '~/generated/graphql'; const MULTIPLE_RECORD_PICKER_PAGE_SIZE = 30; export const useMultipleRecordPickerPerformSearch = () => { + const store = useStore(); const apolloCoreClient = useApolloCoreClient(); const { performCombinedFindManyRecords } = @@ -28,125 +31,142 @@ export const useMultipleRecordPickerPerformSearch = () => { const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); - const performSearch = useRecoilCallback( - ({ snapshot, set }) => - async ({ - multipleRecordPickerInstanceId, - forceSearchFilter = '', - forceSearchableObjectMetadataItems = [], - forcePickableMorphItems = [], - loadMore = false, - }: { - multipleRecordPickerInstanceId: string; - forceSearchFilter?: string; - forceSearchableObjectMetadataItems?: ObjectMetadataItem[]; - forcePickableMorphItems?: RecordPickerPickableMorphItem[]; - loadMore?: boolean; - }) => { - const { getLoadable } = snapshot; + const performSearch = useCallback( + async ({ + multipleRecordPickerInstanceId, + forceSearchFilter = '', + forceSearchableObjectMetadataItems = [], + forcePickableMorphItems = [], + loadMore = false, + }: { + multipleRecordPickerInstanceId: string; + forceSearchFilter?: string; + forceSearchableObjectMetadataItems?: ObjectMetadataItem[]; + forcePickableMorphItems?: RecordPickerPickableMorphItem[]; + loadMore?: boolean; + }) => { + const atomFamilyKey = { instanceId: multipleRecordPickerInstanceId }; - const paginationState = getLoadable( - multipleRecordPickerPaginationState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - ).getValue(); + const paginationState = jotaiStore.get( + multipleRecordPickerPaginationState.atomFamily(atomFamilyKey), + ); - set( - multipleRecordPickerIsLoadingComponentState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - true, + jotaiStore.set( + multipleRecordPickerIsLoadingComponentState.atomFamily(atomFamilyKey), + true, + ); + + jotaiStore.set( + multipleRecordPickerPaginationState.atomFamily(atomFamilyKey), + { + ...paginationState, + endCursor: loadMore ? paginationState.endCursor : null, + hasNextPage: loadMore ? paginationState.hasNextPage : true, + }, + ); + + const recordPickerSearchFilter = jotaiStore.get( + multipleRecordPickerSearchFilterComponentState.atomFamily( + atomFamilyKey, + ), + ); + + const searchFilter = forceSearchFilter ?? recordPickerSearchFilter; + + const recordPickerSearchableObjectMetadataItems = jotaiStore.get( + multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( + atomFamilyKey, + ), + ); + + const searchableObjectMetadataItems = + forceSearchableObjectMetadataItems.length > 0 + ? forceSearchableObjectMetadataItems + : recordPickerSearchableObjectMetadataItems; + + const recordPickerPickableMorphItems = jotaiStore.get( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily( + atomFamilyKey, + ), + ); + + const pickableMorphItems = + forcePickableMorphItems.length > 0 + ? forcePickableMorphItems + : recordPickerPickableMorphItems; + const selectedPickableMorphItems = pickableMorphItems.filter( + ({ isSelected }) => isSelected, + ); + + const filteredSearchableObjectMetadataItems = + searchableObjectMetadataItems.filter( + (objectMetadataItem) => + getObjectPermissionsFromMapByObjectMetadataId({ + objectPermissionsByObjectMetadataId, + objectMetadataId: objectMetadataItem.id, + }).canReadObjectRecords === true, ); - set( - multipleRecordPickerPaginationState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - { - ...paginationState, - endCursor: loadMore ? paginationState.endCursor : null, - hasNextPage: loadMore ? paginationState.hasNextPage : true, - }, - ); + const [ + searchRecordsFilteredOnPickedRecords, + searchRecordsExcludingPickedRecords, + pageInfo, + ] = await performSearchQueries({ + client: apolloCoreClient, + searchFilter, + searchableObjectMetadataItems: filteredSearchableObjectMetadataItems, + pickedRecordIds: selectedPickableMorphItems.map( + ({ recordId }) => recordId, + ), + after: loadMore ? paginationState.endCursor : null, + }); - const recordPickerSearchFilter = getLoadable( - multipleRecordPickerSearchFilterComponentState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - ).getValue(); + const existingMorphItems = jotaiStore.get( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily( + atomFamilyKey, + ), + ); - const searchFilter = forceSearchFilter ?? recordPickerSearchFilter; + const allPickedItems = [ + ...existingMorphItems.filter(({ isSelected }) => isSelected), + ...pickableMorphItems.filter(({ isSelected }) => isSelected), + ]; - const recordPickerSearchableObjectMetadataItems = getLoadable( - multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( - { instanceId: multipleRecordPickerInstanceId }, - ), - ).getValue(); + const uniquePickedItems = allPickedItems.reduce( + (acc, item) => { + if (!acc.some((existing) => existing.recordId === item.recordId)) { + acc.push(item); + } + return acc; + }, + [] as typeof allPickedItems, + ); - const searchableObjectMetadataItems = - forceSearchableObjectMetadataItems.length > 0 - ? forceSearchableObjectMetadataItems - : recordPickerSearchableObjectMetadataItems; + const updatedPickedItems = uniquePickedItems.map((morphItem) => { + if (!searchFilter) { + return { + ...morphItem, + isMatchingSearchFilter: true, + }; + } - const recordPickerPickableMorphItems = getLoadable( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - ).getValue(); - - const pickableMorphItems = - forcePickableMorphItems.length > 0 - ? forcePickableMorphItems - : recordPickerPickableMorphItems; - const selectedPickableMorphItems = pickableMorphItems.filter( - ({ isSelected }) => isSelected, - ); - - const filteredSearchableObjectMetadataItems = - searchableObjectMetadataItems.filter( - (objectMetadataItem) => - getObjectPermissionsFromMapByObjectMetadataId({ - objectPermissionsByObjectMetadataId, - objectMetadataId: objectMetadataItem.id, - }).canReadObjectRecords === true, + const isMatchingSearchFilter = + searchRecordsFilteredOnPickedRecords.some( + ({ recordId }) => recordId === morphItem.recordId, + ) || + searchRecordsExcludingPickedRecords.some( + ({ recordId }) => recordId === morphItem.recordId, ); - const [ - searchRecordsFilteredOnPickedRecords, - searchRecordsExcludingPickedRecords, - pageInfo, - ] = await performSearchQueries({ - client: apolloCoreClient, - searchFilter, - searchableObjectMetadataItems: filteredSearchableObjectMetadataItems, - pickedRecordIds: selectedPickableMorphItems.map( - ({ recordId }) => recordId, - ), - after: loadMore ? paginationState.endCursor : null, - }); + return { + ...morphItem, + isMatchingSearchFilter, + }; + }); - const existingMorphItems = getLoadable( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - ).getValue(); - - const allPickedItems = [ - ...existingMorphItems.filter(({ isSelected }) => isSelected), - ...pickableMorphItems.filter(({ isSelected }) => isSelected), - ]; - - const uniquePickedItems = allPickedItems.reduce( - (acc, item) => { - if (!acc.some((existing) => existing.recordId === item.recordId)) { - acc.push(item); - } - return acc; - }, - [] as typeof allPickedItems, - ); - - const updatedPickedItems = uniquePickedItems.map((morphItem) => { + const updatedNonPickedExistingItems = existingMorphItems + .filter((item) => !item.isSelected) + .map((morphItem) => { if (!searchFilter) { return { ...morphItem, @@ -168,211 +188,187 @@ export const useMultipleRecordPickerPerformSearch = () => { }; }); - const updatedNonPickedExistingItems = existingMorphItems - .filter((item) => !item.isSelected) - .map((morphItem) => { - if (!searchFilter) { - return { - ...morphItem, - isMatchingSearchFilter: true, - }; - } - - const isMatchingSearchFilter = - searchRecordsFilteredOnPickedRecords.some( - ({ recordId }) => recordId === morphItem.recordId, - ) || - searchRecordsExcludingPickedRecords.some( - ({ recordId }) => recordId === morphItem.recordId, - ); - - return { - ...morphItem, - isMatchingSearchFilter, - }; - }); - - const searchRecordsFilteredOnPickedRecordsWithoutDuplicates = - searchRecordsFilteredOnPickedRecords.filter( - (searchRecord) => - !updatedPickedItems.some( - ({ recordId }) => recordId === searchRecord.recordId, - ) && - !updatedNonPickedExistingItems.some( - ({ recordId }) => recordId === searchRecord.recordId, - ), - ); - - const searchRecordsExcludingPickedRecordsWithoutDuplicates = - searchRecordsExcludingPickedRecords.filter( - (searchRecord) => - !searchRecordsFilteredOnPickedRecords.some( - ({ recordId }) => recordId === searchRecord.recordId, - ) && - !updatedPickedItems.some( - ({ recordId }) => recordId === searchRecord.recordId, - ) && - !updatedNonPickedExistingItems.some( - ({ recordId }) => recordId === searchRecord.recordId, - ), - ); - - const newMorphItems = [ - ...updatedPickedItems, - ...updatedNonPickedExistingItems, - ...searchRecordsFilteredOnPickedRecordsWithoutDuplicates.map( - ({ recordId, objectNameSingular }) => ({ - isMatchingSearchFilter: true, - isSelected: true, - objectMetadataId: - searchableObjectMetadataItems.find( - (objectMetadata) => - objectMetadata.nameSingular === objectNameSingular, - )?.id ?? '', - recordId, - }), - ), - ...searchRecordsExcludingPickedRecordsWithoutDuplicates.map( - ({ recordId, objectNameSingular }) => ({ - isMatchingSearchFilter: true, - isSelected: false, - objectMetadataId: - searchableObjectMetadataItems.find( - (objectMetadata) => - objectMetadata.nameSingular === objectNameSingular, - )?.id ?? '', - recordId, - }), - ), - ]; - - const morphItems = loadMore - ? newMorphItems.reduce( - (acc, item) => { - if ( - !acc.some((existing) => existing.recordId === item.recordId) - ) { - acc.push(item); - } - return acc; - }, - [] as typeof newMorphItems, - ) - : newMorphItems; - - const sortedMorphItems = sortMorphItems(morphItems, [ - ...searchRecordsFilteredOnPickedRecords, - ...searchRecordsExcludingPickedRecords, - ]); - - set( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - sortedMorphItems, + const searchRecordsFilteredOnPickedRecordsWithoutDuplicates = + searchRecordsFilteredOnPickedRecords.filter( + (searchRecord) => + !updatedPickedItems.some( + ({ recordId }) => recordId === searchRecord.recordId, + ) && + !updatedNonPickedExistingItems.some( + ({ recordId }) => recordId === searchRecord.recordId, + ), ); - const searchRecords = [ - ...searchRecordsFilteredOnPickedRecords, - ...searchRecordsExcludingPickedRecordsWithoutDuplicates, - ]; + const searchRecordsExcludingPickedRecordsWithoutDuplicates = + searchRecordsExcludingPickedRecords.filter( + (searchRecord) => + !searchRecordsFilteredOnPickedRecords.some( + ({ recordId }) => recordId === searchRecord.recordId, + ) && + !updatedPickedItems.some( + ({ recordId }) => recordId === searchRecord.recordId, + ) && + !updatedNonPickedExistingItems.some( + ({ recordId }) => recordId === searchRecord.recordId, + ), + ); - searchRecords.forEach((searchRecord) => { - set( - searchRecordStoreFamilyState(searchRecord.recordId), - searchRecord, - ); - }); + const newMorphItems = [ + ...updatedPickedItems, + ...updatedNonPickedExistingItems, + ...searchRecordsFilteredOnPickedRecordsWithoutDuplicates.map( + ({ recordId, objectNameSingular }) => ({ + isMatchingSearchFilter: true, + isSelected: true, + objectMetadataId: + searchableObjectMetadataItems.find( + (objectMetadata) => + objectMetadata.nameSingular === objectNameSingular, + )?.id ?? '', + recordId, + }), + ), + ...searchRecordsExcludingPickedRecordsWithoutDuplicates.map( + ({ recordId, objectNameSingular }) => ({ + isMatchingSearchFilter: true, + isSelected: false, + objectMetadataId: + searchableObjectMetadataItems.find( + (objectMetadata) => + objectMetadata.nameSingular === objectNameSingular, + )?.id ?? '', + recordId, + }), + ), + ]; - if (searchRecords.length > 0) { - const filterPerMetadataItemFilteredOnRecordId = Object.fromEntries( - searchableObjectMetadataItems - .map(({ nameSingular }) => { - const recordIdsForMetadataItem = searchRecords - .filter( - ({ objectNameSingular }) => - objectNameSingular === nameSingular, - ) - .map(({ recordId }) => recordId); + const morphItems = loadMore + ? newMorphItems.reduce( + (acc, item) => { + if ( + !acc.some((existing) => existing.recordId === item.recordId) + ) { + acc.push(item); + } + return acc; + }, + [] as typeof newMorphItems, + ) + : newMorphItems; - if (!isNonEmptyArray(recordIdsForMetadataItem)) { - return null; + const sortedMorphItems = sortMorphItems(morphItems, [ + ...searchRecordsFilteredOnPickedRecords, + ...searchRecordsExcludingPickedRecords, + ]); + + jotaiStore.set( + multipleRecordPickerPickableMorphItemsComponentState.atomFamily( + atomFamilyKey, + ), + sortedMorphItems, + ); + + const searchRecords = [ + ...searchRecordsFilteredOnPickedRecords, + ...searchRecordsExcludingPickedRecordsWithoutDuplicates, + ]; + + searchRecords.forEach((searchRecord) => { + store.set( + searchRecordStoreFamilyState.atomFamily(searchRecord.recordId), + searchRecord, + ); + }); + + if (searchRecords.length > 0) { + const filterPerMetadataItemFilteredOnRecordId = Object.fromEntries( + searchableObjectMetadataItems + .map(({ nameSingular }) => { + const recordIdsForMetadataItem = searchRecords + .filter( + ({ objectNameSingular }) => + objectNameSingular === nameSingular, + ) + .map(({ recordId }) => recordId); + + if (!isNonEmptyArray(recordIdsForMetadataItem)) { + return null; + } + + return [ + `filter${capitalize(nameSingular)}`, + { + id: { + in: recordIdsForMetadataItem, + }, + }, + ]; + }) + .filter(isDefined), + ); + + const operationSignatures = searchableObjectMetadataItems + .filter(({ nameSingular }) => + isDefined( + filterPerMetadataItemFilteredOnRecordId[ + `filter${capitalize(nameSingular)}` + ], + ), + ) + .map((objectMetadataItem) => ({ + objectNameSingular: objectMetadataItem.nameSingular, + variables: { + filter: + filterPerMetadataItemFilteredOnRecordId[ + `filter${capitalize(objectMetadataItem.nameSingular)}` + ], + }, + })); + + performCombinedFindManyRecords({ operationSignatures }).then( + ({ result }) => { + Object.values(result) + .flat() + .forEach((objectRecord) => { + const searchRecord = searchRecords.find( + ({ recordId }) => recordId === objectRecord.id, + ); + + if (!searchRecord) { + return; } - return [ - `filter${capitalize(nameSingular)}`, + store.set( + searchRecordStoreFamilyState.atomFamily(objectRecord.id), { - id: { - in: recordIdsForMetadataItem, - }, - }, - ]; - }) - .filter(isDefined), - ); - - const operationSignatures = searchableObjectMetadataItems - .filter(({ nameSingular }) => - isDefined( - filterPerMetadataItemFilteredOnRecordId[ - `filter${capitalize(nameSingular)}` - ], - ), - ) - .map((objectMetadataItem) => ({ - objectNameSingular: objectMetadataItem.nameSingular, - variables: { - filter: - filterPerMetadataItemFilteredOnRecordId[ - `filter${capitalize(objectMetadataItem.nameSingular)}` - ], - }, - })); - - performCombinedFindManyRecords({ operationSignatures }).then( - ({ result }) => { - Object.values(result) - .flat() - .forEach((objectRecord) => { - const searchRecord = searchRecords.find( - ({ recordId }) => recordId === objectRecord.id, - ); - - if (!searchRecord) { - return; - } - - set(searchRecordStoreFamilyState(objectRecord.id), { ...searchRecord, record: objectRecord, - }); - }); - }, - ); - } - - set( - multipleRecordPickerPaginationState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - { - ...paginationState, - endCursor: pageInfo.endCursor, - hasNextPage: pageInfo.hasNextPage, + }, + ); + }); }, ); + } - set( - multipleRecordPickerIsLoadingComponentState.atomFamily({ - instanceId: multipleRecordPickerInstanceId, - }), - false, - ); - }, + jotaiStore.set( + multipleRecordPickerPaginationState.atomFamily(atomFamilyKey), + { + ...paginationState, + endCursor: pageInfo.endCursor, + hasNextPage: pageInfo.hasNextPage, + }, + ); + + jotaiStore.set( + multipleRecordPickerIsLoadingComponentState.atomFamily(atomFamilyKey), + false, + ); + }, [ apolloCoreClient, performCombinedFindManyRecords, objectPermissionsByObjectMetadataId, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsFetchingMoreComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsFetchingMoreComponentState.ts index e609cea843..e9b4c9e413 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsFetchingMoreComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsFetchingMoreComponentState.ts @@ -1,8 +1,8 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerIsFetchingMoreComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerIsFetchingMoreComponentState', defaultValue: false, componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsLoadingComponentState.ts index 635360cf2e..8cbeb7b69b 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerIsLoadingComponentState.ts @@ -1,8 +1,8 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerIsLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerIsLoadingComponentState', defaultValue: false, componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPaginationState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPaginationState.ts index 4236e06f1e..0d1f2c8e1b 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPaginationState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPaginationState.ts @@ -1,5 +1,5 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export type MultipleRecordPickerPaginationState = { endCursor: string | null; @@ -7,7 +7,7 @@ export type MultipleRecordPickerPaginationState = { }; export const multipleRecordPickerPaginationState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerPaginationState', defaultValue: { endCursor: null, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState.ts index 3421141b16..72af95c093 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState.ts @@ -1,9 +1,9 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerPickableMorphItemsComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerPickableMorphItemsComponentState', defaultValue: [], componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState.ts index 2ac8c6e9ed..df0ea42c8d 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState.ts @@ -1,8 +1,8 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerSearchFilterComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerSearchFilterComponentState', defaultValue: '', componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState.ts index 8f10985f8b..51c41c1ceb 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState.ts @@ -1,9 +1,9 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerSearchableObjectMetadataItemsComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerSearchableObjectMetadataItemsComponentState', defaultValue: [], componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowInitialLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowInitialLoadingComponentState.ts index 05cc1b7738..beb7383d78 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowInitialLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowInitialLoadingComponentState.ts @@ -1,8 +1,8 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerShouldShowInitialLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerShouldShowInitialLoadingComponentState', defaultValue: false, componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState.ts index 16360c9ddc..f7a6c4a5c6 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerShouldShowSkeletonComponentState.ts @@ -1,8 +1,8 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const multipleRecordPickerShouldShowSkeletonComponentState = - createComponentState({ + createComponentStateV2({ key: 'multipleRecordPickerShouldShowSkeletonComponentState', defaultValue: false, componentInstanceContext: MultipleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState.ts index 4b31531af0..2c92cb8a44 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState.ts @@ -1,8 +1,8 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { type SearchRecord } from '~/generated/graphql'; -export const searchRecordStoreFamilyState = createFamilyState< +export const searchRecordStoreFamilyState = createFamilyStateV2< (SearchRecord & { record?: ObjectRecord }) | undefined, string >({ diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerIsSelectedComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerIsSelectedComponentFamilySelector.ts index c90664b325..b68a2fd6a7 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerIsSelectedComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerIsSelectedComponentFamilySelector.ts @@ -1,18 +1,17 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; export const multipleRecordPickerIsSelectedComponentFamilySelector = - createComponentFamilySelector({ + createComponentFamilySelectorV2({ key: 'visibleRecordGroupIdsComponentFamilySelector', componentInstanceContext: MultipleRecordPickerComponentInstanceContext, get: ({ instanceId, familyKey: recordId }) => ({ get }) => { const pickableMorphItems = get( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId, - }), + multipleRecordPickerPickableMorphItemsComponentState, + { instanceId }, ); const pickableMorphItem = pickableMorphItems.find( diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPaginationSelector.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPaginationSelector.ts index 3f2fcfe7dc..6748b76506 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPaginationSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPaginationSelector.ts @@ -1,17 +1,15 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { multipleRecordPickerPaginationState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPaginationState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; -export const multipleRecordPickerPaginationSelector = createComponentSelector({ - key: 'multipleRecordPickerPaginationSelector', - componentInstanceContext: MultipleRecordPickerComponentInstanceContext, - get: - ({ instanceId }) => - ({ get }) => { - return get( - multipleRecordPickerPaginationState.atomFamily({ - instanceId, - }), - ); - }, -}); +export const multipleRecordPickerPaginationSelector = createComponentSelectorV2( + { + key: 'multipleRecordPickerPaginationSelector', + componentInstanceContext: MultipleRecordPickerComponentInstanceContext, + get: + (componentStateKey) => + ({ get }) => { + return get(multipleRecordPickerPaginationState, componentStateKey); + }, + }, +); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableMorphItemsLengthComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableMorphItemsLengthComponentSelector.ts index f46990122d..2018a9d448 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableMorphItemsLengthComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableMorphItemsLengthComponentSelector.ts @@ -1,18 +1,17 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const multipleRecordPickerPickableMorphItemsLengthComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'multipleRecordPickerPickableMorphItemsLengthComponentSelector', componentInstanceContext: MultipleRecordPickerComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { const pickableMorphItems = get( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId, - }), + multipleRecordPickerPickableMorphItemsComponentState, + { instanceId }, ); return pickableMorphItems.length; diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector.ts index 99506ae5a0..a63a0dd7cb 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector.ts @@ -1,18 +1,17 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector', componentInstanceContext: MultipleRecordPickerComponentInstanceContext, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { const pickableMorphItems = get( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId, - }), + multipleRecordPickerPickableMorphItemsComponentState, + componentStateKey, ); return pickableMorphItems diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerSinglePickableMorphItemComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerSinglePickableMorphItemComponentFamilySelector.ts index 8c2881486c..d7f6f0a7e8 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerSinglePickableMorphItemComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerSinglePickableMorphItemComponentFamilySelector.ts @@ -1,10 +1,10 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext'; import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; export const multipleRecordPickerSinglePickableMorphItemComponentFamilySelector = - createComponentFamilySelector< + createComponentFamilySelectorV2< RecordPickerPickableMorphItem | undefined, string >({ @@ -14,9 +14,8 @@ export const multipleRecordPickerSinglePickableMorphItemComponentFamilySelector ({ instanceId, familyKey: recordId }) => ({ get }) => { const pickableMorphItems = get( - multipleRecordPickerPickableMorphItemsComponentState.atomFamily({ - instanceId, - }), + multipleRecordPickerPickableMorphItemsComponentState, + { instanceId }, ); const pickableMorphItem = pickableMorphItems.find( diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPicker.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPicker.tsx index 0b573c3092..67113c1bdc 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPicker.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPicker.tsx @@ -9,7 +9,7 @@ import { singleRecordPickerSearchFilterComponentState } from '@/object-record/re import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const SINGLE_RECORD_PICKER_LISTENER_ID = 'single-record-select'; @@ -33,7 +33,7 @@ export const SingleRecordPicker = ({ }: SingleRecordPickerProps) => { const containerRef = useRef(null); - const setRecordPickerSearchFilter = useSetRecoilComponentState( + const setRecordPickerSearchFilter = useSetRecoilComponentStateV2( singleRecordPickerSearchFilterComponentState, componentInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerLoadingEffect.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerLoadingEffect.tsx index cd5a5c6b4f..5cba9b86c7 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerLoadingEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerLoadingEffect.tsx @@ -1,5 +1,5 @@ import { singleRecordPickerShouldShowSkeletonComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowSkeletonComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect, useState } from 'react'; import { useDebouncedCallback } from 'use-debounce'; @@ -10,7 +10,7 @@ export const SingleRecordPickerLoadingEffect = ({ }) => { const [previousLoading, setPreviousLoading] = useState(false); - const setSingleRecordPickerShouldShowSkeleton = useSetRecoilComponentState( + const setSingleRecordPickerShouldShowSkeleton = useSetRecoilComponentStateV2( singleRecordPickerShouldShowSkeletonComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx index 54518d7a68..ed51c9cd65 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx @@ -9,9 +9,9 @@ import { type RecordPickerPickableMorphItem } from '@/object-record/record-picke import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; -import { useRecoilValue } from 'recoil'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { Avatar } from 'twenty-ui/display'; import { MenuItemSelectAvatar } from 'twenty-ui/navigation'; @@ -45,11 +45,12 @@ export const SingleRecordPickerMenuItem = ({ selectableListComponentInstanceId, ); - const searchRecord = useRecoilValue( - searchRecordStoreFamilyState(morphItem.recordId), + const searchRecord = useFamilyRecoilValueV2( + searchRecordStoreFamilyState, + morphItem.recordId, ); - const searchableObjectMetadataItems = useRecoilComponentValue( + const searchableObjectMetadataItems = useRecoilComponentValueV2( singleRecordPickerSearchableObjectMetadataItemsComponentState, recordPickerComponentInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItems.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItems.tsx index 8de7ecf255..15d24a56ce 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItems.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItems.tsx @@ -18,8 +18,8 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { type IconComponent } from 'twenty-ui/display'; import { MenuItemSelect } from 'twenty-ui/navigation'; @@ -72,15 +72,15 @@ export const SingleRecordPickerMenuItems = ({ const selectableItemIds = pickableMorphItems.map( (morphItem) => morphItem.recordId, ); - const [selectedRecordId, setSelectedRecordId] = useRecoilComponentState( + const [selectedRecordId, setSelectedRecordId] = useRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, ); - const singleRecordPickerShouldShowSkeleton = useRecoilComponentValue( + const singleRecordPickerShouldShowSkeleton = useRecoilComponentValueV2( singleRecordPickerShouldShowSkeletonComponentState, ); - const singleRecordPickerShouldShowInitialLoading = useRecoilComponentValue( + const singleRecordPickerShouldShowInitialLoading = useRecoilComponentValueV2( singleRecordPickerShouldShowInitialLoadingComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch.tsx index 5d800bd82c..67bd208368 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch.tsx @@ -15,7 +15,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; import { t } from '@lingui/core/macro'; import { IconPlus } from 'twenty-ui/display'; @@ -49,7 +49,7 @@ export const SingleRecordPickerMenuItemsWithSearch = ({ SingleRecordPickerComponentInstanceContext, ); - const recordPickerSearchFilter = useRecoilComponentValue( + const recordPickerSearchFilter = useRecoilComponentValueV2( singleRecordPickerSearchFilterComponentState, recordPickerInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/__tests__/useSingleRecordPickerRecords.test.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/__tests__/useSingleRecordPickerRecords.test.tsx index 514b944da9..1b89de7e80 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/__tests__/useSingleRecordPickerRecords.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/__tests__/useSingleRecordPickerRecords.test.tsx @@ -5,7 +5,7 @@ import { RecoilRoot } from 'recoil'; import { useSingleRecordPickerSearch } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerSearch'; import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; const instanceId = 'instanceId'; const Wrapper = ({ children }: { children: React.ReactNode }) => ( @@ -19,7 +19,7 @@ describe('useSingleRecordPickerRecords', () => { const { result } = renderHook( () => { const recordSelectSearchHook = useSingleRecordPickerSearch(instanceId); - const internallyStoredFilter = useRecoilComponentValue( + const internallyStoredFilter = useRecoilComponentValueV2( singleRecordPickerSearchFilterComponentState, instanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen.ts index 6a7990c0cc..002f11ad8c 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen.ts @@ -1,37 +1,37 @@ import { singleRecordPickerShouldShowInitialLoadingComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowInitialLoadingComponentState'; import { singleRecordPickerShouldShowSkeletonComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowSkeletonComponentState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useSingleRecordPickerOpen = () => { - const openSingleRecordPicker = useRecoilCallback( - ({ set }) => - (recordPickerComponentInstanceId: string) => { - set( - singleRecordPickerShouldShowInitialLoadingComponentState.atomFamily({ - instanceId: recordPickerComponentInstanceId, - }), - true, - ); - set( - singleRecordPickerShouldShowSkeletonComponentState.atomFamily({ - instanceId: recordPickerComponentInstanceId, - }), - true, - ); - setTimeout(() => { - set( - singleRecordPickerShouldShowInitialLoadingComponentState.atomFamily( - { - instanceId: recordPickerComponentInstanceId, - }, - ), - false, - ); - }, 100); - }, + const setInitialLoading = useCallback( + (recordPickerComponentInstanceId: string, value: boolean) => { + jotaiStore.set( + singleRecordPickerShouldShowInitialLoadingComponentState.atomFamily({ + instanceId: recordPickerComponentInstanceId, + }), + value, + ); + }, [], ); + const openSingleRecordPicker = useCallback( + (recordPickerComponentInstanceId: string) => { + setInitialLoading(recordPickerComponentInstanceId, true); + jotaiStore.set( + singleRecordPickerShouldShowSkeletonComponentState.atomFamily({ + instanceId: recordPickerComponentInstanceId, + }), + true, + ); + setTimeout(() => { + setInitialLoading(recordPickerComponentInstanceId, false); + }, 100); + }, + [setInitialLoading], + ); + return { openSingleRecordPicker, }; diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerPerformSearch.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerPerformSearch.ts index c80ded8758..24380b8a89 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerPerformSearch.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerPerformSearch.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit'; import { useObjectRecordSearchRecords } from '@/object-record/hooks/useObjectRecordSearchRecords'; @@ -6,7 +9,6 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/reco import { singleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchableObjectMetadataItemsComponentState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilCallback } from 'recoil'; import { CustomError, isDefined } from 'twenty-shared/utils'; import { type SearchQuery } from '~/generated/graphql'; @@ -26,34 +28,42 @@ export const useSingleRecordPickerPerformSearch = ({ pickableMorphItems: RecordPickerPickableMorphItem[]; loading: boolean; } => { + const store = useStore(); const singleRecordPickerInstanceId = useAvailableComponentInstanceIdOrThrow( SingleRecordPickerComponentInstanceContext, ); const { objectMetadataItems } = useObjectMetadataItems(); - const onSearchRecordsCompleted = useRecoilCallback( - ({ set }) => - (data: SearchQuery) => { - const searchRecords = data.search.edges.map((edge) => edge.node); + const onSearchRecordsCompleted = useCallback( + (data: SearchQuery) => { + const searchRecords = data.search.edges.map((edge) => edge.node); - searchRecords.forEach((searchRecord) => { - set(searchRecordStoreFamilyState(searchRecord.recordId), { + searchRecords.forEach((searchRecord) => { + store.set( + searchRecordStoreFamilyState.atomFamily(searchRecord.recordId), + { ...searchRecord, record: undefined, - }); - }); - - set( - singleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( - { instanceId: singleRecordPickerInstanceId }, - ), - objectMetadataItems.filter((objectMetadataItem) => - objectNameSingulars.includes(objectMetadataItem.nameSingular), - ), + }, ); - }, - [objectMetadataItems, objectNameSingulars, singleRecordPickerInstanceId], + }); + + store.set( + singleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily( + { instanceId: singleRecordPickerInstanceId }, + ), + objectMetadataItems.filter((objectMetadataItem) => + objectNameSingulars.includes(objectMetadataItem.nameSingular), + ), + ); + }, + [ + store, + objectMetadataItems, + objectNameSingulars, + singleRecordPickerInstanceId, + ], ); const selectedIdsFilter = { id: { in: selectedIds } }; diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerRecords.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerRecords.ts index 4605511e7b..ad74014f1d 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerRecords.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerRecords.ts @@ -1,7 +1,7 @@ import { useSingleRecordPickerPerformSearch } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerPerformSearch'; import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState'; import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useSingleRecordPickerRecords = ({ objectNameSingulars, @@ -10,11 +10,11 @@ export const useSingleRecordPickerRecords = ({ objectNameSingulars: string[]; excludedRecordIds?: string[]; }) => { - const recordPickerSearchFilter = useRecoilComponentValue( + const recordPickerSearchFilter = useRecoilComponentValueV2( singleRecordPickerSearchFilterComponentState, ); - const selectedRecordId = useRecoilComponentValue( + const selectedRecordId = useRecoilComponentValueV2( singleRecordPickerSelectedIdComponentState, ); const { pickableMorphItems, loading } = useSingleRecordPickerPerformSearch({ diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerSearch.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerSearch.ts index 458d92f7ac..2050499af1 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerSearch.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerSearch.ts @@ -2,7 +2,7 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/reco import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState'; import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useDebouncedCallback } from 'use-debounce'; export const useSingleRecordPickerSearch = ( @@ -14,12 +14,12 @@ export const useSingleRecordPickerSearch = ( recordPickerComponentInstanceIdFromProps, ); - const setRecordPickerSearchFilter = useSetRecoilComponentState( + const setRecordPickerSearchFilter = useSetRecoilComponentStateV2( singleRecordPickerSearchFilterComponentState, recordPickerComponentInstanceId, ); - const setRecordPickerSelectedId = useSetRecoilComponentState( + const setRecordPickerSelectedId = useSetRecoilComponentStateV2( singleRecordPickerSelectedIdComponentState, recordPickerComponentInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState.ts index c3b92a5332..f1defa00d9 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState.ts @@ -1,8 +1,8 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const singleRecordPickerSearchFilterComponentState = - createComponentState({ + createComponentStateV2({ key: 'singleRecordPickerSearchFilterComponentState', defaultValue: '', componentInstanceContext: SingleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchQueryComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchQueryComponentState.ts index b5727e40c6..fa162a3941 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchQueryComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchQueryComponentState.ts @@ -1,9 +1,9 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; import { type RecordPickerSearchQuery } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerSearchQuery'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const singleRecordPickerSearchQueryComponentState = - createComponentState({ + createComponentStateV2({ key: 'singleRecordPickerSearchQueryComponentState', defaultValue: null, componentInstanceContext: SingleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchableObjectMetadataItemsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchableObjectMetadataItemsComponentState.ts index 485bb6f85d..2792cbb5c5 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchableObjectMetadataItemsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchableObjectMetadataItemsComponentState.ts @@ -1,9 +1,9 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const singleRecordPickerSearchableObjectMetadataItemsComponentState = - createComponentState({ + createComponentStateV2({ key: 'singleRecordPickerSearchableObjectMetadataItemsComponentState', defaultValue: [], componentInstanceContext: SingleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState.ts index 467fd2bcde..368a1102af 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState.ts @@ -1,10 +1,9 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const singleRecordPickerSelectedIdComponentState = createComponentState< - string | undefined ->({ - key: 'singleRecordPickerSelectedIdComponentState', - defaultValue: undefined, - componentInstanceContext: SingleRecordPickerComponentInstanceContext, -}); +export const singleRecordPickerSelectedIdComponentState = + createComponentStateV2({ + key: 'singleRecordPickerSelectedIdComponentState', + defaultValue: undefined, + componentInstanceContext: SingleRecordPickerComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowInitialLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowInitialLoadingComponentState.ts index 677c67753c..4fbf545d48 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowInitialLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowInitialLoadingComponentState.ts @@ -1,8 +1,8 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const singleRecordPickerShouldShowInitialLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'singleRecordPickerShouldShowInitialLoadingComponentState', defaultValue: false, componentInstanceContext: SingleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowSkeletonComponentState.ts b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowSkeletonComponentState.ts index 24a0218a04..6bcb0ba2a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowSkeletonComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/states/singleRecordPickerShouldShowSkeletonComponentState.ts @@ -1,8 +1,8 @@ import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const singleRecordPickerShouldShowSkeletonComponentState = - createComponentState({ + createComponentStateV2({ key: 'singleRecordPickerShouldShowSkeletonComponentState', defaultValue: false, componentInstanceContext: SingleRecordPickerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordIdState.ts b/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordIdState.ts index 9b8a8ab973..fd7495692b 100644 --- a/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordIdState.ts +++ b/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordIdState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const viewableRecordIdState = createState({ +export const viewableRecordIdState = createStateV2({ key: 'activities/viewable-record-id', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordNameSingularState.ts b/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordNameSingularState.ts index 9b40e65fe8..648b666faf 100644 --- a/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordNameSingularState.ts +++ b/packages/twenty-front/src/modules/object-record/record-right-drawer/states/viewableRecordNameSingularState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; // TODO: deprecate this state once we remove IS_COMMAND_MENU_V2_ENABLED flag -export const viewableRecordNameSingularState = createState({ +export const viewableRecordNameSingularState = createStateV2({ key: 'activities/viewable-record-name-singular', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/PageLayoutRecordPageRenderer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/PageLayoutRecordPageRenderer.tsx index ba3c1aca4a..3f14b3fa27 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/PageLayoutRecordPageRenderer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/PageLayoutRecordPageRenderer.tsx @@ -4,14 +4,14 @@ import { InformationBannerDeletedRecord } from '@/information-banner/components/ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordShowContainerContextStoreTargetedRecordsEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect'; import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { PageLayoutRenderer } from '@/page-layout/components/PageLayoutRenderer'; import { usePageLayoutIdForRecord } from '@/page-layout/hooks/usePageLayoutIdForRecord'; import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext'; import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier'; import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; import { PageLayoutType } from '~/generated-metadata/graphql'; @@ -43,12 +43,13 @@ export const PageLayoutRecordPageRenderer = ({ targetRecordIdentifier: TargetRecordIdentifier; isInRightDrawer: boolean; }) => { - const recordDeletedAt = useRecoilValue( - recordStoreFamilySelector({ + const recordDeletedAt = useFamilySelectorValueV2( + recordStoreFamilySelectorV2, + { recordId: targetRecordIdentifier.id, fieldName: 'deletedAt', - }), - ); + }, + ) as string | null; const { pageLayoutId } = usePageLayoutIdForRecord({ id: targetRecordIdentifier.id, diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect.tsx index ff78722e4f..d160a7186b 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect.tsx @@ -1,6 +1,6 @@ import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; export const RecordShowContainerContextStoreTargetedRecordsEffect = ({ @@ -8,11 +8,11 @@ export const RecordShowContainerContextStoreTargetedRecordsEffect = ({ }: { recordId: string; }) => { - const setContextStoreTargetedRecordsRule = useSetRecoilComponentState( + const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2( contextStoreTargetedRecordsRuleComponentState, ); - const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentState( + const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentStateV2( contextStoreNumberOfSelectedRecordsComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowEffect.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowEffect.tsx index 1f00b24e10..24a55fa1df 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowEffect.tsx @@ -6,8 +6,7 @@ import { recordStoreFamilyState } from '@/object-record/record-store/states/reco import { recordStoreFamilyStateV2 } from '@/object-record/record-store/states/recordStoreFamilyStateV2'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { useStore } from 'jotai'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; type RecordShowEffectProps = { @@ -37,18 +36,17 @@ export const RecordShowEffect = ({ withSoftDeleted: true, }); - const setRecordStore = useRecoilCallback( - ({ snapshot, set }) => - async (newRecord: ObjectRecord | null | undefined) => { - const previousRecordValue = snapshot - .getLoadable(recordStoreFamilyState(recordId)) - .getValue(); + const setRecordStore = useCallback( + async (newRecord: ObjectRecord | null | undefined) => { + const previousRecordValue = store.get( + recordStoreFamilyState.atomFamily(recordId), + ); - if (JSON.stringify(previousRecordValue) !== JSON.stringify(newRecord)) { - set(recordStoreFamilyState(recordId), newRecord); - store.set(recordStoreFamilyStateV2.atomFamily(recordId), newRecord); - } - }, + if (JSON.stringify(previousRecordValue) !== JSON.stringify(newRecord)) { + store.set(recordStoreFamilyState.atomFamily(recordId), newRecord); + store.set(recordStoreFamilyStateV2.atomFamily(recordId), newRecord); + } + }, [recordId, store], ); diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx index 0df777d76b..9ee0b7443c 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/SummaryCard.tsx @@ -7,15 +7,15 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldCont import { usePersonAvatarUpload } from '@/object-record/record-show/hooks/usePersonAvatarUpload'; import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions'; import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; -import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; +import { recordStoreIdentifierFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreIdentifierFamilySelectorV2'; import { RecordTitleCell } from '@/object-record/record-title-cell/components/RecordTitleCell'; import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType'; import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { FieldMetadataType, @@ -38,12 +38,10 @@ export const SummaryCard = ({ objectRecordId, }); - const recordCreatedAt = useRecoilValue( - recordStoreFamilySelector({ - recordId: objectRecordId, - fieldName: 'createdAt', - }), - ); + const recordCreatedAt = useFamilySelectorValueV2( + recordStoreFamilySelectorV2, + { recordId: objectRecordId, fieldName: 'createdAt' }, + ) as string | null; const allowRequestsToTwentyIcons = useRecoilValueV2( allowRequestsToTwentyIconsState, ); @@ -59,12 +57,13 @@ export const SummaryCard = ({ const isMobile = useIsMobile() || isInRightDrawer; - const recordIdentifier = useRecoilValue( - recordStoreIdentifierFamilySelector({ + const recordIdentifier = useFamilySelectorValueV2( + recordStoreIdentifierFamilySelectorV2, + { recordId: objectRecordId, allowRequestsToTwentyIcons, isFilesFieldMigrated, - }), + }, ); const { objectMetadataItem } = useObjectMetadataItem({ diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts index cc6694010c..1b51f553b9 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowContainerData.ts @@ -1,6 +1,6 @@ import { recordLoadingFamilyState } from '@/object-record/record-store/states/recordLoadingFamilyState'; import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; -import { useRecoilState } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; type UseRecordShowContainerDataProps = { objectRecordId: string; @@ -9,8 +9,9 @@ type UseRecordShowContainerDataProps = { export const useRecordShowContainerData = ({ objectRecordId, }: UseRecordShowContainerDataProps) => { - const [recordLoading] = useRecoilState( - recordLoadingFamilyState(objectRecordId), + const recordLoading = useFamilyRecoilValueV2( + recordLoadingFamilyState, + objectRecordId, ); const isPrefetchLoading = useIsPrefetchLoading(); diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts index 386c05c26f..b3167724ea 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPagePagination.ts @@ -2,11 +2,11 @@ import { isNonEmptyString } from '@sniptt/guards'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { useParams, useSearchParams } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { lastShowPageRecordIdState } from '@/object-record/record-field/ui/states/lastShowPageRecordId'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useRecordIdsFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery'; import { useQueryVariablesFromParentView } from '@/views/hooks/useQueryVariablesFromParentView'; import { AppPath } from 'twenty-shared/types'; @@ -27,7 +27,9 @@ export const useRecordShowPagePagination = ( const [searchParams] = useSearchParams(); const viewIdQueryParam = searchParams.get('viewId'); - const setLastShowPageRecordId = useSetRecoilState(lastShowPageRecordIdState); + const setLastShowPageRecordId = useSetRecoilStateV2( + lastShowPageRecordIdState, + ); const objectNameSingular = propsObjectNameSingular || paramObjectNameSingular; const objectRecordId = propsObjectRecordId || paramObjectRecordId; diff --git a/packages/twenty-front/src/modules/object-record/record-sort/hooks/useRemoveRecordSort.ts b/packages/twenty-front/src/modules/object-record/record-sort/hooks/useRemoveRecordSort.ts index 7a2c516997..9d956b9d24 100644 --- a/packages/twenty-front/src/modules/object-record/record-sort/hooks/useRemoveRecordSort.ts +++ b/packages/twenty-front/src/modules/object-record/record-sort/hooks/useRemoveRecordSort.ts @@ -1,27 +1,30 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useRemoveRecordSort = () => { - const currentRecordSortsCallbackState = useRecoilComponentCallbackState( + const currentRecordSortsAtom = useRecoilComponentStateCallbackStateV2( currentRecordSortsComponentState, ); - const removeRecordSort = useRecoilCallback( - ({ set, snapshot }) => - (fieldMetadataId: string) => { - const currentRecordSorts = getSnapshotValue( - snapshot, - currentRecordSortsCallbackState, - ); + const store = useStore(); - const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some( - (existingSort) => existingSort.fieldMetadataId === fieldMetadataId, - ); + const removeRecordSort = useCallback( + (fieldMetadataId: string) => { + const currentRecordSorts = store.get( + currentRecordSortsAtom, + ) as RecordSort[]; - if (hasFoundRecordSortInCurrentRecordSorts) { - set(currentRecordSortsCallbackState, (currentRecordSorts) => { + const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some( + (existingSort) => existingSort.fieldMetadataId === fieldMetadataId, + ); + + if (hasFoundRecordSortInCurrentRecordSorts) { + store.set( + currentRecordSortsAtom, + (currentRecordSorts: RecordSort[]) => { const newCurrentRecordSorts = [...currentRecordSorts]; const indexOfSortToRemove = newCurrentRecordSorts.findIndex( @@ -36,10 +39,11 @@ export const useRemoveRecordSort = () => { newCurrentRecordSorts.splice(indexOfSortToRemove, 1); return newCurrentRecordSorts; - }); - } - }, - [currentRecordSortsCallbackState], + }, + ); + } + }, + [currentRecordSortsAtom, store], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-sort/hooks/useUpsertRecordSort.ts b/packages/twenty-front/src/modules/object-record/record-sort/hooks/useUpsertRecordSort.ts index fe65e4171b..c957f5fde3 100644 --- a/packages/twenty-front/src/modules/object-record/record-sort/hooks/useUpsertRecordSort.ts +++ b/packages/twenty-front/src/modules/object-record/record-sort/hooks/useUpsertRecordSort.ts @@ -1,34 +1,36 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useUpsertRecordSort = () => { - const currentRecordSortsCallbackState = useRecoilComponentCallbackState( + const currentRecordSortsAtom = useRecoilComponentStateCallbackStateV2( currentRecordSortsComponentState, ); - const upsertRecordSort = useRecoilCallback( - ({ set, snapshot }) => - (recordSortToSet: RecordSort) => { - const currentRecordSorts = getSnapshotValue( - snapshot, - currentRecordSortsCallbackState, - ); + const store = useStore(); - const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some( - (existingSort) => - existingSort.fieldMetadataId === recordSortToSet.fieldMetadataId, - ); + const upsertRecordSort = useCallback( + (recordSortToSet: RecordSort) => { + const currentRecordSorts = store.get( + currentRecordSortsAtom, + ) as RecordSort[]; - if (!hasFoundRecordSortInCurrentRecordSorts) { - set(currentRecordSortsCallbackState, [ - ...currentRecordSorts, - recordSortToSet, - ]); - } else { - set(currentRecordSortsCallbackState, (currentRecordSorts) => { + const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some( + (existingSort) => + existingSort.fieldMetadataId === recordSortToSet.fieldMetadataId, + ); + + if (!hasFoundRecordSortInCurrentRecordSorts) { + store.set(currentRecordSortsAtom, [ + ...currentRecordSorts, + recordSortToSet, + ]); + } else { + store.set( + currentRecordSortsAtom, + (currentRecordSorts: RecordSort[]) => { const newCurrentRecordSorts = [...currentRecordSorts]; const indexOfSortToUpdate = newCurrentRecordSorts.findIndex( @@ -46,10 +48,11 @@ export const useUpsertRecordSort = () => { }; return newCurrentRecordSorts; - }); - } - }, - [currentRecordSortsCallbackState], + }, + ); + } + }, + [currentRecordSortsAtom, store], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-sort/states/currentRecordSortsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-sort/states/currentRecordSortsComponentState.ts index 1559e95f62..9ef5cda9b8 100644 --- a/packages/twenty-front/src/modules/object-record/record-sort/states/currentRecordSortsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-sort/states/currentRecordSortsComponentState.ts @@ -1,8 +1,8 @@ import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const currentRecordSortsComponentState = createComponentState< +export const currentRecordSortsComponentState = createComponentStateV2< RecordSort[] >({ key: 'currentRecordSortsComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-store/hooks/__tests__/useUpsertRecordsInStore.test.tsx b/packages/twenty-front/src/modules/object-record/record-store/hooks/__tests__/useUpsertRecordsInStore.test.tsx index f6a60a08c1..7ab5ec6c00 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/hooks/__tests__/useUpsertRecordsInStore.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-store/hooks/__tests__/useUpsertRecordsInStore.test.tsx @@ -1,12 +1,14 @@ import { act, renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider } from 'jotai'; import { type ReactNode } from 'react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; const Wrapper = ({ children }: { children: ReactNode }) => ( - {children} + {children} ); describe('useUpsertRecordsInStore', () => { @@ -15,7 +17,7 @@ describe('useUpsertRecordsInStore', () => { const { result } = renderHook( () => { - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const { upsertRecordsInStore } = useUpsertRecordsInStore(); return { record, upsertRecordsInStore }; @@ -51,7 +53,7 @@ describe('useUpsertRecordsInStore', () => { const { result } = renderHook( () => { - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const { upsertRecordsInStore } = useUpsertRecordsInStore(); return { record, upsertRecordsInStore }; @@ -109,7 +111,7 @@ describe('useUpsertRecordsInStore', () => { const { result } = renderHook( () => { - const record = useRecoilValue(recordStoreFamilyState(recordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const { upsertRecordsInStore } = useUpsertRecordsInStore(); return { record, upsertRecordsInStore }; diff --git a/packages/twenty-front/src/modules/object-record/record-store/hooks/useRecordFieldValue.tsx b/packages/twenty-front/src/modules/object-record/record-store/hooks/useRecordFieldValue.tsx index 8b41142c07..a4b7455696 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/hooks/useRecordFieldValue.tsx +++ b/packages/twenty-front/src/modules/object-record/record-store/hooks/useRecordFieldValue.tsx @@ -1,23 +1,22 @@ +import { useAtomValue } from 'jotai'; + import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { recordStoreFieldValueSelector } from '@/object-record/record-store/states/selectors/recordStoreFieldValueSelector'; -import { useRecoilValue } from 'recoil'; +import { recordStoreFieldValueSelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFieldValueSelectorV2'; export const useRecordFieldValue = ( recordId: string, fieldName: string, fieldDefinition: Pick, 'type' | 'metadata'>, ) => { - const recordFieldValue = useRecoilValue( - recordStoreFieldValueSelector({ - recordId, - fieldName, - fieldDefinition: { - type: fieldDefinition.type, - metadata: fieldDefinition.metadata, - }, - }), - ) as T | undefined; + const fieldValueAtom = recordStoreFieldValueSelectorV2({ + recordId, + fieldName, + fieldDefinition: { + type: fieldDefinition.type, + metadata: fieldDefinition.metadata, + }, + }); - return recordFieldValue; + return useAtomValue(fieldValueAtom) as T | undefined; }; diff --git a/packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts b/packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts index b4e3016377..b10b4ffd94 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/hooks/useUpsertRecordsInStore.ts @@ -1,10 +1,9 @@ -import { useRecoilCallback } from 'recoil'; - import { filterRecordOnGqlFields } from '@/object-record/cache/utils/filterRecordOnGqlFields'; import { type RecordGqlFields } from '@/object-record/graphql/record-gql-fields/types/RecordGqlFields'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyStateV2 } from '@/object-record/record-store/states/recordStoreFamilyStateV2'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { useCallback } from 'react'; import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -17,55 +16,60 @@ type UpsertRecordsInStoreProps = { export const useUpsertRecordsInStore = () => { const store = useStore(); - const upsertRecordsInStore = useRecoilCallback( - ({ set, snapshot }) => - ({ partialRecords, recordGqlFields }: UpsertRecordsInStoreProps) => { - for (const partialRecord of partialRecords) { - const currentRecord = snapshot - .getLoadable(recordStoreFamilyState(partialRecord.id)) - .getValue(); + const upsertRecordsInStore = useCallback( + ({ partialRecords, recordGqlFields }: UpsertRecordsInStoreProps) => { + for (const partialRecord of partialRecords) { + const currentRecord = store.get( + recordStoreFamilyState.atomFamily(partialRecord.id), + ); - const filteredPartialRecord = isDefined(recordGqlFields) - ? filterRecordOnGqlFields({ - record: partialRecord, - recordGqlFields, - }) - : partialRecord; + const filteredPartialRecord = isDefined(recordGqlFields) + ? filterRecordOnGqlFields({ + record: partialRecord, + recordGqlFields, + }) + : partialRecord; - if (!isDefined(currentRecord)) { - const newRecord = { - id: partialRecord.id, - __typename: partialRecord.__typename, - ...filteredPartialRecord, - }; - set(recordStoreFamilyState(partialRecord.id), newRecord); - store.set( - recordStoreFamilyStateV2.atomFamily(partialRecord.id), - newRecord, - ); - continue; - } - - const filteredCurrentRecord = isDefined(recordGqlFields) - ? filterRecordOnGqlFields({ - record: currentRecord, - recordGqlFields, - }) - : currentRecord; - - if (!isDeeplyEqual(filteredCurrentRecord, filteredPartialRecord)) { - const updatedRecord = { - ...currentRecord, - ...filteredPartialRecord, - }; - set(recordStoreFamilyState(partialRecord.id), updatedRecord); - store.set( - recordStoreFamilyStateV2.atomFamily(partialRecord.id), - updatedRecord, - ); - } + if (!isDefined(currentRecord)) { + const newRecord = { + id: partialRecord.id, + __typename: partialRecord.__typename, + ...filteredPartialRecord, + }; + store.set( + recordStoreFamilyState.atomFamily(partialRecord.id), + newRecord, + ); + store.set( + recordStoreFamilyStateV2.atomFamily(partialRecord.id), + newRecord, + ); + continue; } - }, + + const filteredCurrentRecord = isDefined(recordGqlFields) + ? filterRecordOnGqlFields({ + record: currentRecord, + recordGqlFields, + }) + : currentRecord; + + if (!isDeeplyEqual(filteredCurrentRecord, filteredPartialRecord)) { + const updatedRecord = { + ...currentRecord, + ...filteredPartialRecord, + }; + store.set( + recordStoreFamilyState.atomFamily(partialRecord.id), + updatedRecord, + ); + store.set( + recordStoreFamilyStateV2.atomFamily(partialRecord.id), + updatedRecord, + ); + } + } + }, [store], ); diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/recordLoadingFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-store/states/recordLoadingFamilyState.ts index cbfd3ebb02..48441be1f3 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/recordLoadingFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/recordLoadingFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const recordLoadingFamilyState = createFamilyState({ +export const recordLoadingFamilyState = createFamilyStateV2({ key: 'recordLoadingFamilyState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/recordStoreFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-store/states/recordStoreFamilyState.ts index bfc28e3b83..82b6fb4062 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/recordStoreFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/recordStoreFamilyState.ts @@ -1,7 +1,7 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const recordStoreFamilyState = createFamilyState< +export const recordStoreFamilyState = createFamilyStateV2< ObjectRecord | null | undefined, string >({ diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelector.ts deleted file mode 100644 index ffe3e9de5b..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelector.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { selectorFamily } from 'recoil'; - -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; - -export const recordStoreFamilySelector = selectorFamily({ - key: 'recordStoreFamilySelector', - get: - ({ fieldName, recordId }: { fieldName: string; recordId: string }) => - ({ get }) => - get(recordStoreFamilyState(recordId))?.[fieldName] as T, - set: - ({ fieldName, recordId }: { fieldName: string; recordId: string }) => - ({ set }, newValue: T) => - set(recordStoreFamilyState(recordId), (prevState) => - prevState - ? { ...prevState, [fieldName]: newValue } - : ({ [fieldName]: newValue } as ObjectRecord), - ), -}); diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelectorV2.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelectorV2.ts index aa539cce53..789cd9d7f7 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelectorV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFamilySelectorV2.ts @@ -1,4 +1,4 @@ -import { recordStoreFamilyStateV2 } from '@/object-record/record-store/states/recordStoreFamilyStateV2'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { createWritableFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createWritableFamilySelectorV2'; @@ -10,11 +10,11 @@ export const recordStoreFamilySelectorV2 = createWritableFamilySelectorV2< get: ({ recordId, fieldName }) => ({ get }) => - get(recordStoreFamilyStateV2, recordId)?.[fieldName], + get(recordStoreFamilyState, recordId)?.[fieldName], set: ({ recordId, fieldName }) => ({ set }, newValue) => { - set(recordStoreFamilyStateV2, recordId, (prev) => + set(recordStoreFamilyState, recordId, (prev) => prev ? { ...prev, [fieldName]: newValue } : ({ [fieldName]: newValue } as ObjectRecord), diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts deleted file mode 100644 index 72ccbac62e..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { selectorFamily } from 'recoil'; - -import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; -import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guards/isFieldMorphRelation'; -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { RelationType, type ObjectRecord } from 'twenty-shared/types'; -import { - computeMorphRelationFieldName, - CustomError, - isDefined, -} from 'twenty-shared/utils'; - -export const recordStoreFieldValueSelector = selectorFamily({ - key: 'recordStoreFieldValueSelector', - get: - ({ - recordId, - fieldName, - fieldDefinition, - }: { - recordId: string; - fieldName: string; - fieldDefinition: Pick< - FieldDefinition, - 'type' | 'metadata' - >; - }) => - ({ get }) => { - if (!isFieldMorphRelation(fieldDefinition)) { - return get(recordStoreFamilyState(recordId))?.[fieldName]; - } - - const morphRelations = fieldDefinition.metadata.morphRelations; - - if (!Array.isArray(morphRelations) || morphRelations.length === 0) { - throw new CustomError( - 'No morph relations found', - 'NO_MORPH_RELATIONS_FOUND', - ); - } - - const morphValuesWithObjectName = morphRelations.map((morphRelation) => { - const computedFieldName = computeMorphRelationFieldName({ - fieldName: morphRelation.sourceFieldMetadata.name, - relationType: morphRelation.type, - targetObjectMetadataNameSingular: - morphRelation.targetObjectMetadata.nameSingular, - targetObjectMetadataNamePlural: - morphRelation.targetObjectMetadata.namePlural, - }); - return { - objectNameSingular: morphRelation.targetObjectMetadata.nameSingular, - value: get(recordStoreFamilyState(recordId))?.[computedFieldName], - }; - }); - - const relationType = morphRelations[0].type; - - if (relationType === RelationType.ONE_TO_MANY) { - return morphValuesWithObjectName.map((morphValue) => ({ - ...morphValue, - value: morphValue.value ? morphValue.value : [], - })) as { - objectNameSingular: string; - value: ObjectRecord[]; - }[]; - } - - if (relationType === RelationType.MANY_TO_ONE) { - const morphValueFiltered = morphValuesWithObjectName.filter( - (morphValue) => isDefined(morphValue.value), - ); - return morphValueFiltered.length > 0 - ? (morphValueFiltered[0] as { - objectNameSingular: string; - value: ObjectRecord; - }) - : null; - } - - throw new CustomError( - `Unknown relation type: ${relationType}`, - 'UNKNOWN_RELATION_TYPE', - ); - }, -}); diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifierSelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifierFamilySelectorV2.ts similarity index 58% rename from packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifierSelector.ts rename to packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifierFamilySelectorV2.ts index 348821c34e..b34e4366af 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifierSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifierFamilySelectorV2.ts @@ -1,30 +1,34 @@ -import { selectorFamily } from 'recoil'; - import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier'; +import { type ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; import { uncapitalize } from 'twenty-shared/utils'; -export const recordStoreIdentifierFamilySelector = selectorFamily({ - key: 'recordStoreIdentifierFamilySelector', +type RecordStoreIdentifierFamilyKey = { + recordId: string; + allowRequestsToTwentyIcons: boolean; + isFilesFieldMigrated?: boolean; +}; + +export const recordStoreIdentifierFamilySelectorV2 = createFamilySelectorV2< + ObjectRecordIdentifier | null, + RecordStoreIdentifierFamilyKey +>({ + key: 'recordStoreIdentifierFamilySelectorV2', get: ({ recordId, allowRequestsToTwentyIcons, isFilesFieldMigrated, - }: { - recordId: string; - allowRequestsToTwentyIcons: boolean; - isFilesFieldMigrated?: boolean; - }) => + }: RecordStoreIdentifierFamilyKey) => ({ get }) => { - const recordFromStore = get(recordStoreFamilyState(recordId)); + const recordFromStore = get(recordStoreFamilyState, recordId); const objectNameSingular = uncapitalize( recordFromStore?.__typename ?? '', ); - const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); + const objectMetadataItems = get(objectMetadataItemsState); const objectMetadataItem = objectMetadataItems.find( (item) => item.nameSingular === objectNameSingular, diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifiersSelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifiersSelector.ts index 5410c80190..fd50ab1c3f 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifiersSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreIdentifiersSelector.ts @@ -1,6 +1,6 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier'; -import { recordStoreFamilyStateV2 } from '@/object-record/record-store/states/recordStoreFamilyStateV2'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier'; import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; import { isDefined, uncapitalize } from 'twenty-shared/utils'; @@ -20,7 +20,7 @@ export const recordStoreIdentifiersFamilySelector = createFamilySelectorV2< return recordIds .map((recordId) => { - const recordFromStore = get(recordStoreFamilyStateV2, recordId); + const recordFromStore = get(recordStoreFamilyState, recordId); const objectNameSingular = uncapitalize( recordFromStore?.__typename ?? '', ); diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2.ts similarity index 71% rename from packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector.ts rename to packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2.ts index cf3ae03970..e1c0aff684 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2.ts @@ -1,22 +1,25 @@ -import { selectorFamily } from 'recoil'; - import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; import { type RelationType } from 'twenty-shared/types'; import { computeMorphRelationFieldName } from 'twenty-shared/utils'; -export const recordStoreMorphOneToManyValueWithObjectNameFamilySelector = - selectorFamily({ - key: 'recordStoreMorphOneToManyValueWithObjectNameFamilySelector', +type MorphOneToManyFamilyKey = { + recordId: string; + morphRelations: FieldMetadataItemRelation[]; +}; + +type MorphValueWithObjectName = { + objectNameSingular: string; + value: ObjectRecord[] | ObjectRecord; +}; + +export const recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2 = + createFamilySelectorV2({ + key: 'recordStoreMorphOneToManyValueWithObjectNameFamilySelectorV2', get: - ({ - recordId, - morphRelations, - }: { - recordId: string; - morphRelations: FieldMetadataItemRelation[]; - }) => + ({ recordId, morphRelations }: MorphOneToManyFamilyKey) => ({ get }) => { const morphValuesWithObjectName = morphRelations.map( (morphRelation) => { @@ -31,7 +34,7 @@ export const recordStoreMorphOneToManyValueWithObjectNameFamilySelector = return { objectNameSingular: morphRelation.targetObjectMetadata.nameSingular, - value: (get(recordStoreFamilyState(recordId))?.[fieldName] || + value: (get(recordStoreFamilyState, recordId)?.[fieldName] || []) as ObjectRecord[] | ObjectRecord, }; }, diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelector.ts deleted file mode 100644 index 3224d57e9f..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelector.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { selectorFamily } from 'recoil'; - -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { isDefined } from 'twenty-shared/utils'; - -export const recordStoreRecordsSelector = selectorFamily({ - key: 'recordStoreRecordsSelector', - get: - ({ recordIds }: { recordIds: string[] }) => - ({ get }) => { - const records = recordIds - .map((recordId) => get(recordStoreFamilyState(recordId))) - .filter(isDefined); - return records; - }, -}); diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelectorV2.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelectorV2.ts new file mode 100644 index 0000000000..e1f7e54953 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreRecordsSelectorV2.ts @@ -0,0 +1,21 @@ +import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; +import { isDefined } from 'twenty-shared/utils'; + +type RecordStoreRecordsFamilyKey = { + recordIds: string[]; +}; + +export const recordStoreRecordsSelectorV2 = createFamilySelectorV2< + ObjectRecord[], + RecordStoreRecordsFamilyKey +>({ + key: 'recordStoreRecordsSelectorV2', + get: + ({ recordIds }: RecordStoreRecordsFamilyKey) => + ({ get }) => + recordIds + .map((recordId) => get(recordStoreFamilyState, recordId)) + .filter(isDefined), +}); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index f7b5d9d3f1..f5249b8df8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -14,7 +14,8 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const RecordTable = () => { const { recordTableId, objectNameSingular, objectMetadataItem } = @@ -30,17 +31,17 @@ export const RecordTable = () => { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID, ); - const isRecordTableInitialLoading = useRecoilComponentValue( + const isRecordTableInitialLoading = useRecoilComponentValueV2( isRecordTableInitialLoadingComponentState, recordTableId, ); - const recordTableHasRecords = useRecoilComponentValue( + const recordTableHasRecords = useRecoilComponentSelectorValueV2( recordIndexHasRecordsComponentSelector, recordTableId, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx index e0065981b9..cad1d1c9f6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx @@ -14,24 +14,24 @@ import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-t import { getRecordTableColumnFieldWidthCSSVariableName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthCSSVariableName'; import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable'; import { RECORD_TABLE_VIRTUALIZATION_BODY_PLACEHOLDER_WIDTH_CSS_VARIABLE_NAME } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const RecordTableColumnWidthEffect = () => { - const [resizedFieldMetadataItemId] = useRecoilComponentState( + const [resizedFieldMetadataItemId] = useRecoilComponentStateV2( resizedFieldMetadataIdComponentState, ); const { visibleRecordFields } = useRecordTableContextOrThrow(); - const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + const shouldCompactRecordTableFirstColumn = useRecoilComponentValueV2( shouldCompactRecordTableFirstColumnComponentState, ); - const recordTableWidth = useRecoilComponentValue( + const recordTableWidth = useRecoilComponentValueV2( recordTableWidthComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx index cca2c04d4e..5c6a1d6398 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx @@ -12,13 +12,12 @@ import { recordTableHoverPositionComponentState } from '@/object-record/record-t import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-select/constants/RecordIndecDragSelectBoundaryClass'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; -import { useRef, useState } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useRef, useState } from 'react'; +import { useStore } from 'jotai'; const StyledTableContainer = styled.div` display: flex; @@ -56,43 +55,41 @@ export const RecordTableContent = ({ handleDragSelectionEnd(); }; - const isRowSelectedCallbackFamilyState = - useRecoilComponentFamilyCallbackState(isRowSelectedComponentFamilyState); + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( + isRowSelectedComponentFamilyState, + recordTableId, + ); - const handleDragSelectionChange = useRecoilCallback( - ({ set }) => - (rowId: string, selected: boolean) => { - set(isRowSelectedCallbackFamilyState(rowId), selected); - }, - [isRowSelectedCallbackFamilyState], + const store = useStore(); + + const handleDragSelectionChange = useCallback( + (rowId: string, selected: boolean) => { + store.set(isRowSelectedFamilyState(rowId), selected); + }, + [isRowSelectedFamilyState, store], ); const recordTableScrollWrapperId = `record-table-scroll-${recordTableId}`; const { visibleRecordFields } = useRecordTableContextOrThrow(); - const setRecordTableHoverPosition = useSetRecoilComponentState( + const setRecordTableHoverPosition = useSetRecoilComponentStateV2( recordTableHoverPositionComponentState, + recordTableId, ); - const isSomeCellInEditModeCallbackState = useRecoilComponentCallbackState( + const isSomeCellInEditModeAtom = useRecoilComponentSelectorCallbackStateV2( isSomeCellInEditModeComponentSelector, + recordTableId, ); - const handleMouseLeave = useRecoilCallback( - ({ snapshot }) => - () => { - const isSomeCellInEditMode = getSnapshotValue( - snapshot, - isSomeCellInEditModeCallbackState, - ); + const handleMouseLeave = useCallback(() => { + const isSomeCellInEditMode = store.get(isSomeCellInEditModeAtom); - if (!isSomeCellInEditMode) { - setRecordTableHoverPosition(null); - } - }, - [isSomeCellInEditModeCallbackState, setRecordTableHoverPosition], - ); + if (!isSomeCellInEditMode) { + setRecordTableHoverPosition(null); + } + }, [store, isSomeCellInEditModeAtom, setRecordTableHoverPosition]); return ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx index 57adf61798..c647f553bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx @@ -9,9 +9,9 @@ import { visibleRecordFieldsComponentSelector } from '@/object-record/record-fie import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix'; import { RECORD_TABLE_COLUMN_MIN_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnMinWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { useRecoilValue } from 'recoil'; type RecordTableContextProviderProps = { viewBarId: string; @@ -36,12 +36,14 @@ export const RecordTableContextProvider = ({ objectMetadataItem.id, ); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, recordTableId, ); - const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); + const recordIndexOpenRecordIn = useRecoilValueV2( + recordIndexOpenRecordInState, + ); const triggerEvent = recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL ? 'CLICK' diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx index eb221d98d0..d0611c9033 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx @@ -15,7 +15,8 @@ import { resizeFieldOffsetComponentState } from '@/object-record/record-table/st import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable'; import { RecordTableVirtualizedDataChangedEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedDataChangedEffect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -32,21 +33,21 @@ export interface RecordTableEmptyProps { export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => { const { visibleRecordFields } = useRecordTableContextOrThrow(); - const recordTableWidth = useRecoilComponentValue( + const recordTableWidth = useRecoilComponentValueV2( recordTableWidthComponentState, ); - const resizedFieldMetadataId = useRecoilComponentValue( + const resizedFieldMetadataId = useRecoilComponentValueV2( resizedFieldMetadataIdComponentState, ); - const resizeFieldOffset = useRecoilComponentValue( + const resizeFieldOffset = useRecoilComponentValueV2( resizeFieldOffsetComponentState, ); const isResizing = isDefined(resizedFieldMetadataId); - const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + const shouldCompactRecordTableFirstColumn = useRecoilComponentValueV2( shouldCompactRecordTableFirstColumnComponentState, ); @@ -76,7 +77,7 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => { emptyTableContainerComputedWidth, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupAddNew.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupAddNew.tsx index c5cbfd3770..1ac33619c1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupAddNew.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupAddNew.tsx @@ -6,9 +6,10 @@ import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useC import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow'; import { useLoadRecordsToVirtualRows } from '@/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; @@ -25,39 +26,36 @@ export const RecordTableNoRecordGroupAddNew = () => { const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords; - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, ); - const totalNumberOfRecordsToVirtualize = useRecoilComponentValue( + const totalNumberOfRecordsToVirtualize = useRecoilComponentValueV2( totalNumberOfRecordsToVirtualizeComponentState, ); const { loadRecordsToVirtualRows } = useLoadRecordsToVirtualRows(); const { upsertRecordsInStore } = useUpsertRecordsInStore(); - const handleButtonClick = useRecoilCallback( - () => async () => { - const createdRecord = await createNewIndexRecord({ - position: 'last', + const handleButtonClick = useCallback(async () => { + const createdRecord = await createNewIndexRecord({ + position: 'last', + }); + + upsertRecordsInStore({ partialRecords: [createdRecord] }); + + if (isDefined(totalNumberOfRecordsToVirtualize)) { + loadRecordsToVirtualRows({ + records: [createdRecord], + startingRealIndex: totalNumberOfRecordsToVirtualize, }); - - upsertRecordsInStore({ partialRecords: [createdRecord] }); - - if (isDefined(totalNumberOfRecordsToVirtualize)) { - loadRecordsToVirtualRows({ - records: [createdRecord], - startingRealIndex: totalNumberOfRecordsToVirtualize, - }); - } - }, - [ - createNewIndexRecord, - upsertRecordsInStore, - loadRecordsToVirtualRows, - totalNumberOfRecordsToVirtualize, - ], - ); + } + }, [ + createNewIndexRecord, + upsertRecordsInStore, + loadRecordsToVirtualRows, + totalNumberOfRecordsToVirtualize, + ]); if (hasAnySoftDeleteFilterOnView) { return null; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupBodyContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupBodyContextProvider.tsx index d588fb00dd..b989635633 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupBodyContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupBodyContextProvider.tsx @@ -11,7 +11,7 @@ import { useTriggerActionMenuDropdown } from '@/object-record/record-table/recor import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { type MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type ReactNode } from 'react'; type RecordTableNoRecordGroupBodyContextProviderProps = { @@ -58,8 +58,9 @@ export const RecordTableNoRecordGroupBodyContextProvider = ({ triggerActionMenuDropdown(event, recordId); }; - const hasUserSelectedAllRows = useRecoilComponentValue( + const hasUserSelectedAllRows = useRecoilComponentValueV2( hasUserSelectedAllRowsComponentState, + recordTableId, ); return ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupRows.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupRows.tsx index c63f8777b2..d4a8e4cd76 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupRows.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableNoRecordGroupRows.tsx @@ -4,12 +4,12 @@ import { RecordTableVirtualizedBodyPlaceholder } from '@/object-record/record-ta import { RecordTableVirtualizedDebugHelper } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedDebugHelper'; import { NUMBER_OF_VIRTUALIZED_ROWS } from '@/object-record/record-table/virtualization/constants/NumberOfVirtualizedRows'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getContiguousIncrementalValues } from 'twenty-shared/utils'; export const RecordTableNoRecordGroupRows = () => { const totalNumberOfRecordsToVirtualize = - useRecoilComponentValue(totalNumberOfRecordsToVirtualizeComponentState) ?? + useRecoilComponentValueV2(totalNumberOfRecordsToVirtualizeComponentState) ?? 0; const numberOfRows = Math.min( diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx index d09c93259d..9da3ff0669 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx @@ -8,8 +8,8 @@ import { RecordTableRow } from '@/object-record/record-table/record-table-row/co import { RecordTableRecordGroupSectionAddNew } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew'; import { RecordTableRecordGroupSectionLoadMore } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore'; import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -18,16 +18,16 @@ export const RecordTableRecordGroupRows = () => { const shouldHide = useShouldHideRecordGroup(currentRecordGroupId); - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, ); - const recordIdsByGroup = useRecoilComponentFamilyValue( + const recordIdsByGroup = useRecoilComponentFamilyValueV2( recordIndexRecordIdsByGroupComponentFamilyState, currentRecordGroupId, ); - const isRecordGroupTableSectionToggled = useRecoilComponentFamilyValue( + const isRecordGroupTableSectionToggled = useRecoilComponentFamilyValueV2( isRecordGroupTableSectionToggledComponentState, currentRecordGroupId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx index 462d5962c1..d8f079bc00 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx @@ -7,8 +7,8 @@ import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-reco import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -20,18 +20,21 @@ export const RecordTableScrollAndZIndexEffect = () => { const [ isRecordTableScrolledHorizontally, setIsRecordTableScrolledHorizontally, - ] = useRecoilComponentState(isRecordTableScrolledHorizontallyComponentState); + ] = useRecoilComponentStateV2( + isRecordTableScrolledHorizontallyComponentState, + ); - const setShouldCompactRecordTableFirstColumn = useSetRecoilComponentState( + const setShouldCompactRecordTableFirstColumn = useSetRecoilComponentStateV2( shouldCompactRecordTableFirstColumnComponentState, ); - const setShouldCompactRecordIndexLabelIdentifier = useSetRecoilComponentState( - shouldCompactRecordIndexLabelIdentifierComponentState, - ); + const setShouldCompactRecordIndexLabelIdentifier = + useSetRecoilComponentStateV2( + shouldCompactRecordIndexLabelIdentifierComponentState, + ); const [isRecordTableScrolledVertically, setIsRecordTableScrolledVertically] = - useRecoilComponentState(isRecordTableScrolledVerticallyComponentState); + useRecoilComponentStateV2(isRecordTableScrolledVerticallyComponentState); useEffect(() => { if (!isDefined(scrollWrapperHTMLElement)) { diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedCellEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedCellEffect.tsx index 272b0efeb7..2d409a7142 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedCellEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedCellEffect.tsx @@ -2,19 +2,19 @@ import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/ import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { isRecordTableCellFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableCellFocusActiveComponentState'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const RecordTableScrollToFocusedCellEffect = () => { const { recordTableId } = useRecordTableContextOrThrow(); - const isRecordTableCellFocusActive = useRecoilComponentValue( + const isRecordTableCellFocusActive = useRecoilComponentValueV2( isRecordTableCellFocusActiveComponentState, recordTableId, ); - const focusPosition = useRecoilComponentValue( + const focusPosition = useRecoilComponentValueV2( recordTableFocusPositionComponentState, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedRowEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedRowEffect.tsx index 2e87a301b6..2fce856306 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedRowEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollToFocusedRowEffect.tsx @@ -3,24 +3,25 @@ import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/ import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { focusedRecordTableRowIndexComponentState } from '@/object-record/record-table/states/focusedRecordTableRowIndexComponentState'; import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const RecordTableScrollToFocusedRowEffect = () => { const { recordTableId } = useRecordTableContextOrThrow(); - const focusedRowIndex = useRecoilComponentValue( + const focusedRowIndex = useRecoilComponentValueV2( focusedRecordTableRowIndexComponentState, recordTableId, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, recordTableId, ); - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWidthEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWidthEffect.tsx index e131071914..486fd10953 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWidthEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWidthEffect.tsx @@ -1,18 +1,18 @@ import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { tableWidthResizeIsActiveState } from '@/object-record/record-table/states/tableWidthResizeIsActivedState'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const RecordTableWidthEffect = () => { - const setRecordTableWidth = useSetRecoilComponentState( + const setRecordTableWidth = useSetRecoilComponentStateV2( recordTableWidthComponentState, ); - const tableWidthResizeIsActive = useRecoilValue( + const tableWidthResizeIsActive = useRecoilValueV2( tableWidthResizeIsActiveState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx index a83f3c552b..51db5ba7cd 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx @@ -1,12 +1,12 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; @@ -29,22 +29,25 @@ import { RecordTableContextProvider } from '@/object-record/record-table/context import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ComponentDecorator } from 'twenty-ui/testing'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; const RelationFieldValueSetterEffect = () => { - const setEntity = useSetRecoilState( - recordStoreFamilyState(mockPerformance.recordId), + const setEntity = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + mockPerformance.recordId, ); - const setRelationEntity = useSetRecoilState( - recordStoreFamilyState(mockPerformance.relationRecordId), + const setRelationEntity = useSetFamilyRecoilStateV2( + recordStoreFamilyState, + mockPerformance.relationRecordId, ); - const setCurrentRecordFields = useSetRecoilComponentState( + const setCurrentRecordFields = useSetRecoilComponentStateV2( currentRecordFieldsComponentState, 'recordTableId', ); @@ -84,12 +87,12 @@ const meta: Meta = { MemoryRouterDecorator, ChipGeneratorsDecorator, (Story) => { - const currentRecordFields = useRecoilComponentValue( + const currentRecordFields = useRecoilComponentValueV2( currentRecordFieldsComponentState, 'recordTableId', ); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, 'recordTableId', ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyHandler.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyHandler.tsx index 2ea23f9efa..2beb538b73 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyHandler.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyHandler.tsx @@ -1,7 +1,8 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; type RecordTableEmptyHandlerProps = { recordTableId: string; @@ -12,12 +13,12 @@ export const RecordTableEmptyHandler = ({ recordTableId, children, }: RecordTableEmptyHandlerProps) => { - const isRecordTableInitialLoading = useRecoilComponentValue( + const isRecordTableInitialLoading = useRecoilComponentValueV2( isRecordTableInitialLoadingComponentState, recordTableId, ); - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyState.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyState.tsx index 2b606f3a58..5bdfd35ff8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyState.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyState.tsx @@ -7,7 +7,7 @@ import { RecordTableEmptyStateReadOnly } from '@/object-record/record-table/empt import { RecordTableEmptyStateRemote } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateRemote'; import { RecordTableEmptyStateSoftDelete } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete'; import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const RecordTableEmptyState = () => { const { recordTableId, objectNameSingular, objectMetadataItem } = @@ -18,7 +18,7 @@ export const RecordTableEmptyState = () => { const isRemote = objectMetadataItem.isRemote; - const isSoftDeleteActive = useRecoilComponentValue( + const isSoftDeleteActive = useRecoilComponentValueV2( isSoftDeleteFilterActiveComponentState, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx index 5a544e9af7..38e0d42acc 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx @@ -3,7 +3,7 @@ import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObje import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; import { type IconComponent } from 'twenty-ui/display'; @@ -61,7 +61,7 @@ export const RecordTableEmptyStateDisplay = ( objectMetadataItem, }); - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx index d727c7ab58..72d21233f7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete.tsx @@ -4,7 +4,7 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRe import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useLingui } from '@lingui/react/macro'; @@ -17,7 +17,7 @@ export const RecordTableEmptyStateSoftDelete = () => { const { objectMetadataItem, objectNameSingular, recordTableId } = useRecordTableContextOrThrow(); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts index 54d3a9ca59..2b7c824ba2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useCloseCurrentTableCellInEditMode.ts @@ -1,14 +1,16 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState'; import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId'; import { useRemoveLastFocusItemFromFocusStackByComponentType } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackByComponentType'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useCloseCurrentTableCellInEditMode = (recordTableId?: string) => { - const currentTableCellInEditModePositionState = - useRecoilComponentCallbackState( + const store = useStore(); + const currentTableCellInEditModePositionAtom = + useRecoilComponentStateCallbackStateV2( recordTableCellEditModePositionComponentState, recordTableId, ); @@ -19,22 +21,18 @@ export const useCloseCurrentTableCellInEditMode = (recordTableId?: string) => { const { removeLastFocusItemFromFocusStackByComponentType } = useRemoveLastFocusItemFromFocusStackByComponentType(); - return useRecoilCallback( - ({ set }) => { - return () => { - set(currentTableCellInEditModePositionState, null); + return useCallback(() => { + store.set(currentTableCellInEditModePositionAtom, null); - goBackToPreviousDropdownFocusId(); + goBackToPreviousDropdownFocusId(); - removeLastFocusItemFromFocusStackByComponentType({ - componentType: FocusComponentType.OPENED_FIELD_INPUT, - }); - }; - }, - [ - currentTableCellInEditModePositionState, - goBackToPreviousDropdownFocusId, - removeLastFocusItemFromFocusStackByComponentType, - ], - ); + removeLastFocusItemFromFocusStackByComponentType({ + componentType: FocusComponentType.OPENED_FIELD_INPUT, + }); + }, [ + store, + currentTableCellInEditModePositionAtom, + goBackToPreviousDropdownFocusId, + removeLastFocusItemFromFocusStackByComponentType, + ]); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useHandleContainerMouseEnter.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useHandleContainerMouseEnter.ts index ac9c452e87..40dd23f1c2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useHandleContainerMouseEnter.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useHandleContainerMouseEnter.ts @@ -1,10 +1,10 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell'; import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; export type HandleContainerMouseEnterArgs = { cellPosition: TableCellPosition; @@ -17,24 +17,23 @@ export const useHandleContainerMouseEnter = ({ }) => { const { moveHoverToCurrentCell } = useMoveHoverToCurrentCell(recordTableId); - const isSomeCellInEditModeSelector = useRecoilComponentCallbackState( - isSomeCellInEditModeComponentSelector, - recordTableId, - ); + const isSomeCellInEditModeSelector = + useRecoilComponentSelectorCallbackStateV2( + isSomeCellInEditModeComponentSelector, + recordTableId, + ); - const handleContainerMouseEnter = useRecoilCallback( - ({ snapshot }) => - ({ cellPosition }: HandleContainerMouseEnterArgs) => { - const isSomeCellInEditMode = getSnapshotValue( - snapshot, - isSomeCellInEditModeSelector, - ); + const store = useStore(); - if (!isSomeCellInEditMode) { - moveHoverToCurrentCell(cellPosition); - } - }, - [isSomeCellInEditModeSelector, moveHoverToCurrentCell], + const handleContainerMouseEnter = useCallback( + ({ cellPosition }: HandleContainerMouseEnterArgs) => { + const isSomeCellInEditMode = store.get(isSomeCellInEditModeSelector); + + if (!isSomeCellInEditMode) { + moveHoverToCurrentCell(cellPosition); + } + }, + [isSomeCellInEditModeSelector, moveHoverToCurrentCell, store], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts index 2729b4273a..4ad1b122b4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useLeaveTableFocus.ts @@ -7,7 +7,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-tabl import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const useLeaveTableFocus = (recordTableId?: string) => { const recordTableIdFromContext = useAvailableComponentInstanceIdOrThrow( @@ -17,12 +17,12 @@ export const useLeaveTableFocus = (recordTableId?: string) => { const { resetTableRowSelection } = useResetTableRowSelection(); - const setRecordTableHoverPosition = useSetRecoilComponentState( + const setRecordTableHoverPosition = useSetRecoilComponentStateV2( recordTableHoverPositionComponentState, recordTableIdFromContext, ); - const setRecordTableFocusPosition = useSetRecoilComponentState( + const setRecordTableFocusPosition = useSetRecoilComponentStateV2( recordTableFocusPositionComponentState, recordTableIdFromContext, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts index 9a7a13efd2..829fe2edf4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useResetTableRowSelection.ts @@ -1,16 +1,18 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; +import { lastSelectedRowIndexComponentState } from '@/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { lastSelectedRowIndexComponentState } from '@/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; export const useResetTableRowSelection = (recordTableId?: string) => { const recordTableIdFromContext = useAvailableComponentInstanceIdOrThrow( @@ -18,60 +20,54 @@ export const useResetTableRowSelection = (recordTableId?: string) => { recordTableId, ); - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( + const recordIndexAllRecordIdsAtom = useRecoilComponentSelectorCallbackStateV2( recordIndexAllRecordIdsComponentSelector, recordTableIdFromContext, ); - const isRowSelectedFamilyState = useRecoilComponentCallbackState( + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( isRowSelectedComponentFamilyState, recordTableIdFromContext, ); - const hasUserSelectedAllRowsState = useRecoilComponentCallbackState( + const hasUserSelectedAllRowsAtom = useRecoilComponentStateCallbackStateV2( hasUserSelectedAllRowsComponentState, recordTableIdFromContext, ); const lastSelectedRowIndexComponentCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( lastSelectedRowIndexComponentState, recordTableIdFromContext, ); const { closeDropdown } = useCloseDropdown(); + const store = useStore(); - const resetTableRowSelection = useRecoilCallback( - ({ set, snapshot }) => - () => { - const allRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); + const resetTableRowSelection = useCallback(() => { + const allRecordIds = store.get(recordIndexAllRecordIdsAtom); - for (const recordId of allRecordIds) { - set(isRowSelectedFamilyState(recordId), false); - } + for (const recordId of allRecordIds) { + store.set(isRowSelectedFamilyState(recordId), false); + } - set(hasUserSelectedAllRowsState, false); + store.set(hasUserSelectedAllRowsAtom, false); + store.set(lastSelectedRowIndexComponentCallbackState, null); - set(lastSelectedRowIndexComponentCallbackState, null); - - closeDropdown( - getActionMenuDropdownIdFromActionMenuId( - getActionMenuIdFromRecordIndexId(recordTableIdFromContext), - ), - ); - }, - [ - recordIndexAllRecordIdsSelector, - hasUserSelectedAllRowsState, - lastSelectedRowIndexComponentCallbackState, - isRowSelectedFamilyState, - closeDropdown, - recordTableIdFromContext, - ], - ); + closeDropdown( + getActionMenuDropdownIdFromActionMenuId( + getActionMenuIdFromRecordIndexId(recordTableIdFromContext), + ), + ); + }, [ + recordIndexAllRecordIdsAtom, + hasUserSelectedAllRowsAtom, + lastSelectedRowIndexComponentCallbackState, + isRowSelectedFamilyState, + closeDropdown, + recordTableIdFromContext, + store, + ]); return { resetTableRowSelection, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSelectAllRows.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSelectAllRows.ts index 996f45e8a3..d2ccd08cf9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSelectAllRows.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSelectAllRows.ts @@ -1,70 +1,64 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; export const useSelectAllRows = (recordTableId?: string) => { - const hasUserSelectedAllRowsCallbackState = useRecoilComponentCallbackState( + const hasUserSelectedAllRowsAtom = useRecoilComponentStateCallbackStateV2( hasUserSelectedAllRowsComponentState, recordTableId, ); - const allRowsSelectedStatusSelector = useRecoilComponentCallbackState( + const allRowsSelectedStatusAtom = useRecoilComponentSelectorCallbackStateV2( allRowsSelectedStatusComponentSelector, recordTableId, ); - const isRowSelectedFamilyState = useRecoilComponentCallbackState( + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( isRowSelectedComponentFamilyState, recordTableId, ); - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( + + const recordIndexAllRecordIdsAtom = useRecoilComponentSelectorCallbackStateV2( recordIndexAllRecordIdsComponentSelector, recordTableId, ); const { resetTableRowSelection } = useResetTableRowSelection(recordTableId); - const selectAllRows = useRecoilCallback( - ({ set, snapshot }) => - () => { - const allRowsSelectedStatus = getSnapshotValue( - snapshot, - allRowsSelectedStatusSelector, - ); + const store = useStore(); - const allRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); + const selectAllRows = useCallback(() => { + const allRowsSelectedStatus = store.get(allRowsSelectedStatusAtom); + const allRecordIds = store.get(recordIndexAllRecordIdsAtom); - if (allRowsSelectedStatus === 'all') { - resetTableRowSelection(); - } + if (allRowsSelectedStatus === 'all') { + resetTableRowSelection(); + } - for (const recordId of allRecordIds) { - const isSelected = - allRowsSelectedStatus === 'none' || - allRowsSelectedStatus === 'some'; + for (const recordId of allRecordIds) { + const isSelected = + allRowsSelectedStatus === 'none' || allRowsSelectedStatus === 'some'; - set(isRowSelectedFamilyState(recordId), isSelected); - } + store.set(isRowSelectedFamilyState(recordId), isSelected); + } - set(hasUserSelectedAllRowsCallbackState, true); - }, - [ - allRowsSelectedStatusSelector, - recordIndexAllRecordIdsSelector, - resetTableRowSelection, - isRowSelectedFamilyState, - hasUserSelectedAllRowsCallbackState, - ], - ); + store.set(hasUserSelectedAllRowsAtom, true); + }, [ + allRowsSelectedStatusAtom, + recordIndexAllRecordIdsAtom, + resetTableRowSelection, + isRowSelectedFamilyState, + hasUserSelectedAllRowsAtom, + store, + ]); return { selectAllRows, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts index 859c36f008..a8e8675820 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetAllRowSelectedState.ts @@ -1,19 +1,16 @@ -import { useRecoilCallback } from 'recoil'; - import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; export const useSetHasUserSelectedAllRows = (recordTableId?: string) => { - const hasUserSelectedAllRowsState = useRecoilComponentCallbackState( + const hasUserSelectedAllRowsAtom = useRecoilComponentStateCallbackStateV2( hasUserSelectedAllRowsComponentState, recordTableId, ); - return useRecoilCallback( - ({ set }) => - (selected: boolean) => { - set(hasUserSelectedAllRowsState, selected); - }, - [hasUserSelectedAllRowsState], - ); + const store = useStore(); + + return (selected: boolean) => { + store.set(hasUserSelectedAllRowsAtom, selected); + }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts index 4bc1824d59..5ee6b002ff 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts @@ -1,7 +1,11 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; -import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { + NO_RECORD_GROUP_FAMILY_KEY, + recordIndexAllRecordIdsComponentSelector, +} from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyStateV2 } from '@/object-record/record-store/states/recordStoreFamilyStateV2'; @@ -12,13 +16,12 @@ import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/ import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; -import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; +import { recordIdByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { useStore } from 'jotai'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -30,39 +33,38 @@ export const useSetRecordTableData = ({ recordTableId, }: useSetRecordTableDataProps) => { const recordIndexRecordIdsByGroupFamilyState = - useRecoilComponentFamilyCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, + ); + + const recordIndexAllRecordIdsSelector = + useRecoilComponentSelectorCallbackStateV2( + recordIndexAllRecordIdsComponentSelector, recordTableId, ); - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( - recordIndexAllRecordIdsComponentSelector, - recordTableId, - ); - - const isRowSelectedFamilyState = useRecoilComponentFamilyCallbackState( + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( isRowSelectedComponentFamilyState, recordTableId, ); - const hasUserSelectedAllRowsState = useRecoilComponentCallbackState( + const hasUserSelectedAllRowsAtom = useRecoilComponentStateCallbackStateV2( hasUserSelectedAllRowsComponentState, recordTableId, ); - const isRecordTableInitialLoadingCallbackState = - useRecoilComponentCallbackState( + const isRecordTableInitialLoadingAtom = + useRecoilComponentStateCallbackStateV2( isRecordTableInitialLoadingComponentState, recordTableId, ); - const recordIdByRealIndexCallbackSelector = - useRecoilComponentFamilyCallbackState( - recordIdByRealIndexComponentFamilySelector, - recordTableId, - ); + const recordIdByRealIndexAtom = useRecoilComponentStateCallbackStateV2( + recordIdByRealIndexComponentState, + recordTableId, + ); - const setRecordTableHoverPosition = useSetRecoilComponentState( + const setRecordTableHoverPosition = useSetRecoilComponentStateV2( recordTableHoverPositionComponentState, recordTableId, ); @@ -71,98 +73,95 @@ export const useSetRecordTableData = ({ const { unfocusRecordTableRow } = useFocusedRecordTableRow(recordTableId); const store = useStore(); - return useRecoilCallback( - ({ set, snapshot }) => - ({ - records, - currentRecordGroupId, - }: { - records: T[]; - currentRecordGroupId?: string; - }) => { - for (const record of records) { - // TODO: refactor with scoped state later - const currentRecord = snapshot - .getLoadable(recordStoreFamilyState(record.id)) - .getValue(); + return useCallback( + ({ + records, + currentRecordGroupId, + }: { + records: T[]; + currentRecordGroupId?: string; + }) => { + for (const record of records) { + const currentRecord = store.get( + recordStoreFamilyState.atomFamily(record.id), + ) as ObjectRecord | null | undefined; - if (JSON.stringify(currentRecord) !== JSON.stringify(record)) { - const newRecord = { - ...currentRecord, - ...record, - }; + if (JSON.stringify(currentRecord) !== JSON.stringify(record)) { + const newRecord = { + ...(currentRecord ?? {}), + ...record, + } as T; - set(recordStoreFamilyState(record.id), newRecord); - store.set( - recordStoreFamilyStateV2.atomFamily(record.id), - newRecord, - ); + store.set(recordStoreFamilyState.atomFamily(record.id), newRecord); + store.set(recordStoreFamilyStateV2.atomFamily(record.id), newRecord); + } + } + + const currentRowIds = currentRecordGroupId + ? (store.get( + recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId), + ) as string[]) + : (store.get(recordIndexAllRecordIdsSelector) as string[]); + + const hasUserSelectedAllRows = store.get(hasUserSelectedAllRowsAtom); + + const recordIds = records.map((record) => record.id); + + if (!isDeeplyEqual(currentRowIds, recordIds)) { + unfocusRecordTableCell(); + unfocusRecordTableRow(); + setRecordTableHoverPosition(null); + + if (hasUserSelectedAllRows) { + for (const rowId of recordIds) { + store.set(isRowSelectedFamilyState(rowId), true); } } - const currentRowIds = getSnapshotValue( - snapshot, - currentRecordGroupId - ? recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId) - : recordIndexAllRecordIdsSelector, - ); - - const hasUserSelectedAllRows = getSnapshotValue( - snapshot, - hasUserSelectedAllRowsState, - ); - - const recordIds = records.map((record) => record.id); - - if (!isDeeplyEqual(currentRowIds, recordIds)) { - unfocusRecordTableCell(); - unfocusRecordTableRow(); - setRecordTableHoverPosition(null); - - if (hasUserSelectedAllRows) { - for (const rowId of recordIds) { - set(isRowSelectedFamilyState(rowId), true); - } - } - - if (isDefined(currentRecordGroupId)) { - set( - recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId), - recordIds, - ); - } else { - set(recordIndexAllRecordIdsSelector, recordIds); - } - - const isTableInitialLoading = getSnapshotValue( - snapshot, - isRecordTableInitialLoadingCallbackState, + if (isDefined(currentRecordGroupId)) { + store.set( + recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId), + recordIds, ); + } else { + store.set( + recordIndexRecordIdsByGroupFamilyState(NO_RECORD_GROUP_FAMILY_KEY), + recordIds, + ); + } - if (isTableInitialLoading) { - for (const [realIndex, recordId] of recordIds.entries()) { - const currentRecordIdAtRealIndex = getSnapshotValue( - snapshot, - recordIdByRealIndexCallbackSelector(realIndex), - ); + const isTableInitialLoading = store.get( + isRecordTableInitialLoadingAtom, + ); - if (recordId !== currentRecordIdAtRealIndex) { - set(recordIdByRealIndexCallbackSelector(realIndex), recordId); - } + if (isTableInitialLoading) { + const currentMap = store.get(recordIdByRealIndexAtom); + const newMap = new Map(currentMap); + let mapChanged = false; + + for (const [realIndex, recordId] of recordIds.entries()) { + if (recordId !== currentMap.get(realIndex)) { + newMap.set(realIndex, recordId); + mapChanged = true; } } + + if (mapChanged) { + store.set(recordIdByRealIndexAtom, newMap); + } } - }, + } + }, [ recordIndexRecordIdsByGroupFamilyState, recordIndexAllRecordIdsSelector, - hasUserSelectedAllRowsState, + hasUserSelectedAllRowsAtom, unfocusRecordTableCell, unfocusRecordTableRow, setRecordTableHoverPosition, isRowSelectedFamilyState, - recordIdByRealIndexCallbackSelector, - isRecordTableInitialLoadingCallbackState, + recordIdByRealIndexAtom, + isRecordTableInitialLoadingAtom, store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useActiveRecordTableRow.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useActiveRecordTableRow.ts index 28b25730fe..0a51bcf358 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useActiveRecordTableRow.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useActiveRecordTableRow.ts @@ -1,58 +1,60 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { activeRecordTableRowIndexComponentState } from '@/object-record/record-table/states/activeRecordTableRowIndexComponentState'; import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useActiveRecordTableRow = (recordTableId?: string) => { - const isRowActiveState = useRecoilComponentCallbackState( + const isRowActiveState = useRecoilComponentFamilyStateCallbackStateV2( isRecordTableRowActiveComponentFamilyState, recordTableId, ); - const activeRowIndexState = useRecoilComponentCallbackState( + const activeRowIndexState = useRecoilComponentStateCallbackStateV2( activeRecordTableRowIndexComponentState, recordTableId, ); - const deactivateRecordTableRow = useRecoilCallback( - ({ set, snapshot }) => - () => { - const activeRowIndex = snapshot - .getLoadable(activeRowIndexState) - .getValue(); + const store = useStore(); - if (!isDefined(activeRowIndex)) { - return; - } + const deactivateRecordTableRow = useCallback(() => { + const activeRowIndex = store.get(activeRowIndexState) as + | number + | null + | undefined; - set(activeRowIndexState, null); + if (!isDefined(activeRowIndex)) { + return; + } - set(isRowActiveState(activeRowIndex), false); - }, - [activeRowIndexState, isRowActiveState], - ); + store.set(activeRowIndexState, null); - const activateRecordTableRow = useRecoilCallback( - ({ set, snapshot }) => - (rowIndex: number) => { - const activeRowIndex = snapshot - .getLoadable(activeRowIndexState) - .getValue(); + store.set(isRowActiveState(activeRowIndex), false); + }, [activeRowIndexState, isRowActiveState, store]); - if (activeRowIndex === rowIndex) { - return; - } + const activateRecordTableRow = useCallback( + (rowIndex: number) => { + const activeRowIndex = store.get(activeRowIndexState) as + | number + | null + | undefined; - if (isDefined(activeRowIndex)) { - set(isRowActiveState(activeRowIndex), false); - } + if (activeRowIndex === rowIndex) { + return; + } - set(activeRowIndexState, rowIndex); + if (isDefined(activeRowIndex)) { + store.set(isRowActiveState(activeRowIndex), false); + } - set(isRowActiveState(rowIndex), true); - }, - [activeRowIndexState, isRowActiveState], + store.set(activeRowIndexState, rowIndex); + + store.set(isRowActiveState(rowIndex), true); + }, + [activeRowIndexState, isRowActiveState, store], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useBuildRecordInputFromFilters.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useBuildRecordInputFromFilters.ts index 0c1a851825..173f525134 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useBuildRecordInputFromFilters.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useBuildRecordInputFromFilters.ts @@ -4,7 +4,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { buildRecordInputFromFilter } from '@/object-record/record-table/utils/buildRecordInputFromFilter'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; export const useBuildRecordInputFromFilters = ({ @@ -12,7 +12,7 @@ export const useBuildRecordInputFromFilters = ({ }: { objectMetadataItem: ObjectMetadataItem; }) => { - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useCreateNewIndexRecord.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useCreateNewIndexRecord.ts index 85ba975ffd..546002b184 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useCreateNewIndexRecord.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useCreateNewIndexRecord.ts @@ -15,11 +15,13 @@ import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { canOpenObjectInSidePanel } from '@/object-record/utils/canOpenObjectInSidePanel'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useStore } from 'jotai'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { AppPath } from 'twenty-shared/types'; import { findByProperty, isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; @@ -32,16 +34,17 @@ type UseCreateNewIndexRecordProps = { export const useCreateNewIndexRecord = ({ objectMetadataItem, }: UseCreateNewIndexRecordProps) => { - const recordGroupDefinitions = useRecoilComponentValue( + const recordGroupDefinitions = useRecoilComponentSelectorValueV2( recordGroupDefinitionsComponentSelector, ); + const store = useStore(); const recordIndexRecordIdsByGroupCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, ); - const recordIndexGroupFieldMetadataItem = useRecoilComponentValue( + const recordIndexGroupFieldMetadataItem = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); @@ -69,113 +72,110 @@ export const useCreateNewIndexRecord = ({ objectMetadataItem, }); - const createNewIndexRecord = useRecoilCallback( - ({ snapshot, set }) => - async (recordInput?: Partial) => { - const recordId = v4(); - const recordInputFromRLSPredicates = - buildRecordInputFromRLSPredicates(); - const recordInputFromFilters = buildRecordInputFromFilters(); + const createNewIndexRecord = useCallback( + async (recordInput?: Partial) => { + const recordId = v4(); + const recordInputFromRLSPredicates = buildRecordInputFromRLSPredicates(); + const recordInputFromFilters = buildRecordInputFromFilters(); - const mergedRecordInput = { - ...recordInputFromRLSPredicates, - ...recordInputFromFilters, - ...recordInput, - }; + const mergedRecordInput = { + ...recordInputFromRLSPredicates, + ...recordInputFromFilters, + ...recordInput, + }; - const recordIndexOpenRecordIn = snapshot - .getLoadable(recordIndexOpenRecordInState) - .getValue(); + const recordIndexOpenRecordIn = jotaiStore.get( + recordIndexOpenRecordInState.atom, + ); - const createdRecord = await createOneRecord({ - id: recordId, - ...mergedRecordInput, + const createdRecord = await createOneRecord({ + id: recordId, + ...mergedRecordInput, + }); + + if ( + recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL && + canOpenObjectInSidePanel(objectMetadataItem.nameSingular) + ) { + openRecordInCommandMenu({ + recordId, + objectNameSingular: objectMetadataItem.nameSingular, + isNewRecord: true, }); - if ( - recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL && - canOpenObjectInSidePanel(objectMetadataItem.nameSingular) - ) { - openRecordInCommandMenu({ + const labelIdentifierFieldMetadataItem = + getLabelIdentifierFieldMetadataItem(objectMetadataItem); + + if (isDefined(labelIdentifierFieldMetadataItem)) { + openRecordTitleCell({ recordId, - objectNameSingular: objectMetadataItem.nameSingular, - isNewRecord: true, - }); - - const labelIdentifierFieldMetadataItem = - getLabelIdentifierFieldMetadataItem(objectMetadataItem); - - if (isDefined(labelIdentifierFieldMetadataItem)) { - openRecordTitleCell({ + fieldMetadataItemId: labelIdentifierFieldMetadataItem.id, + instanceId: getRecordFieldInputInstanceId({ recordId, - fieldMetadataItemId: labelIdentifierFieldMetadataItem.id, - instanceId: getRecordFieldInputInstanceId({ - recordId, - fieldName: labelIdentifierFieldMetadataItem.name, - prefix: RecordTitleCellContainerType.PageHeader, - }), - }); - } - } else { - const labelIdentifierFieldMetadataItem = - getLabelIdentifierFieldMetadataItem(objectMetadataItem); + fieldName: labelIdentifierFieldMetadataItem.name, + prefix: RecordTitleCellContainerType.PageHeader, + }), + }); + } + } else { + const labelIdentifierFieldMetadataItem = + getLabelIdentifierFieldMetadataItem(objectMetadataItem); - closeCommandMenu(); - navigate( - AppPath.RecordShowPage, - { - objectNameSingular: objectMetadataItem.nameSingular, + closeCommandMenu(); + navigate( + AppPath.RecordShowPage, + { + objectNameSingular: objectMetadataItem.nameSingular, + objectRecordId: recordId, + }, + undefined, + { + state: { + isNewRecord: true, objectRecordId: recordId, + labelIdentifierFieldName: labelIdentifierFieldMetadataItem?.name, }, - undefined, - { - state: { - isNewRecord: true, - objectRecordId: recordId, - labelIdentifierFieldName: - labelIdentifierFieldMetadataItem?.name, - }, - }, - ); - } + }, + ); + } - if (isDefined(recordIndexGroupFieldMetadataItem)) { - const recordGroup = recordGroupDefinitions.find( - findByProperty( - 'value', - createdRecord[recordIndexGroupFieldMetadataItem.name], - ), - ); + if (isDefined(recordIndexGroupFieldMetadataItem)) { + const recordGroup = recordGroupDefinitions.find( + findByProperty( + 'value', + createdRecord[recordIndexGroupFieldMetadataItem.name], + ), + ); - if (isDefined(recordGroup)) { - const currentRecordIds = getSnapshotValue( - snapshot, + if (isDefined(recordGroup)) { + const currentRecordIds = store.get( + recordIndexRecordIdsByGroupCallbackState(recordGroup.id), + ) as string[]; + + if (recordInput?.position === 'first') { + const newRecordIds = [createdRecord.id, ...currentRecordIds]; + + store.set( recordIndexRecordIdsByGroupCallbackState(recordGroup.id), + newRecordIds, ); + } else { + const newRecordIds = [...currentRecordIds, createdRecord.id]; - if (recordInput?.position === 'first') { - const newRecordIds = [createdRecord.id, ...currentRecordIds]; - - set( - recordIndexRecordIdsByGroupCallbackState(recordGroup.id), - newRecordIds, - ); - } else { - const newRecordIds = [...currentRecordIds, createdRecord.id]; - - set( - recordIndexRecordIdsByGroupCallbackState(recordGroup.id), - newRecordIds, - ); - } + store.set( + recordIndexRecordIdsByGroupCallbackState(recordGroup.id), + newRecordIds, + ); } } + } - upsertRecordsInStore({ partialRecords: [createdRecord] }); + upsertRecordsInStore({ partialRecords: [createdRecord] }); - return createdRecord; - }, + return createdRecord; + }, [ + store, buildRecordInputFromRLSPredicates, buildRecordInputFromFilters, createOneRecord, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useFocusedRecordTableRow.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useFocusedRecordTableRow.ts index a74968bb27..a6ebdfc12a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useFocusedRecordTableRow.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useFocusedRecordTableRow.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useUnfocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell'; import { getRecordTableRowFocusId } from '@/object-record/record-table/record-table-row/utils/getRecordTableRowFocusId'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; @@ -10,8 +13,8 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useFocusedRecordTableRow = (recordTableId?: string) => { @@ -20,30 +23,32 @@ export const useFocusedRecordTableRow = (recordTableId?: string) => { recordTableId, ); - const isRowFocusedState = useRecoilComponentCallbackState( + const isRowFocusedState = useRecoilComponentFamilyStateCallbackStateV2( isRecordTableRowFocusedComponentFamilyState, recordTableIdFromContext, ); - const focusedRowIndexState = useRecoilComponentCallbackState( + const store = useStore(); + const focusedRowIndexAtom = useRecoilComponentStateCallbackStateV2( focusedRecordTableRowIndexComponentState, recordTableIdFromContext, ); - const isRowFocusActiveState = useRecoilComponentCallbackState( + const isRowFocusActiveAtom = useRecoilComponentStateCallbackStateV2( isRecordTableRowFocusActiveComponentState, recordTableIdFromContext, ); - const focusedCellPositionState = useRecoilComponentCallbackState( + const focusedCellPositionAtom = useRecoilComponentStateCallbackStateV2( recordTableFocusPositionComponentState, recordTableIdFromContext, ); - const isRecordTableCellFocusActiveState = useRecoilComponentCallbackState( - isRecordTableCellFocusActiveComponentState, - recordTableIdFromContext, - ); + const isRecordTableCellFocusActiveAtom = + useRecoilComponentStateCallbackStateV2( + isRecordTableCellFocusActiveComponentState, + recordTableIdFromContext, + ); const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); @@ -54,16 +59,46 @@ export const useFocusedRecordTableRow = (recordTableId?: string) => { recordTableIdFromContext, ); - const unfocusRecordTableRow = useRecoilCallback( - ({ set, snapshot }) => - () => { - const focusedRowIndex = snapshot - .getLoadable(focusedRowIndexState) - .getValue(); + const unfocusRecordTableRow = useCallback(() => { + const focusedRowIndex = store.get(focusedRowIndexAtom) as + | number + | null + | undefined; - if (!isDefined(focusedRowIndex)) { - return; - } + if (!isDefined(focusedRowIndex)) { + return; + } + + const focusId = getRecordTableRowFocusId({ + recordTableId: recordTableIdFromContext, + rowIndex: focusedRowIndex, + }); + + removeFocusItemFromFocusStackById({ + focusId, + }); + + store.set(focusedRowIndexAtom, null); + store.set(isRowFocusedState(focusedRowIndex), false); + store.set(isRowFocusActiveAtom, false); + }, [ + store, + focusedRowIndexAtom, + isRowFocusedState, + isRowFocusActiveAtom, + recordTableIdFromContext, + removeFocusItemFromFocusStackById, + ]); + + const focusRecordTableRow = useCallback( + (rowIndex: number) => { + const focusedRowIndex = store.get(focusedRowIndexAtom) as + | number + | null + | undefined; + + if (isDefined(focusedRowIndex) && focusedRowIndex !== rowIndex) { + store.set(isRowFocusedState(focusedRowIndex), false); const focusId = getRecordTableRowFocusId({ recordTableId: recordTableIdFromContext, @@ -73,100 +108,68 @@ export const useFocusedRecordTableRow = (recordTableId?: string) => { removeFocusItemFromFocusStackById({ focusId, }); + } - set(focusedRowIndexState, null); - set(isRowFocusedState(focusedRowIndex), false); - set(isRowFocusActiveState, false); - }, + const focusId = getRecordTableRowFocusId({ + recordTableId: recordTableIdFromContext, + rowIndex, + }); + + pushFocusItemToFocusStack({ + focusId, + component: { + type: FocusComponentType.RECORD_TABLE_ROW, + instanceId: focusId, + }, + }); + + store.set(focusedRowIndexAtom, rowIndex); + store.set(isRowFocusedState(rowIndex), true); + store.set(isRowFocusActiveAtom, true); + }, [ - focusedRowIndexState, - isRowFocusedState, - isRowFocusActiveState, - recordTableIdFromContext, - removeFocusItemFromFocusStackById, - ], - ); - - const focusRecordTableRow = useRecoilCallback( - ({ set, snapshot }) => - (rowIndex: number) => { - const focusedRowIndex = snapshot - .getLoadable(focusedRowIndexState) - .getValue(); - - if (isDefined(focusedRowIndex) && focusedRowIndex !== rowIndex) { - set(isRowFocusedState(focusedRowIndex), false); - - const focusId = getRecordTableRowFocusId({ - recordTableId: recordTableIdFromContext, - rowIndex: focusedRowIndex, - }); - - removeFocusItemFromFocusStackById({ - focusId, - }); - } - - const focusId = getRecordTableRowFocusId({ - recordTableId: recordTableIdFromContext, - rowIndex, - }); - - pushFocusItemToFocusStack({ - focusId, - component: { - type: FocusComponentType.RECORD_TABLE_ROW, - instanceId: focusId, - }, - }); - - set(focusedRowIndexState, rowIndex); - set(isRowFocusedState(rowIndex), true); - set(isRowFocusActiveState, true); - }, - [ - focusedRowIndexState, + store, + focusedRowIndexAtom, recordTableIdFromContext, pushFocusItemToFocusStack, isRowFocusedState, - isRowFocusActiveState, + isRowFocusActiveAtom, removeFocusItemFromFocusStackById, ], ); - const restoreRecordTableRowFocusFromCellPosition = useRecoilCallback( - ({ snapshot }) => - () => { - const focusedRowIndex = snapshot - .getLoadable(focusedRowIndexState) - .getValue(); + const restoreRecordTableRowFocusFromCellPosition = useCallback(() => { + const focusedRowIndex = store.get(focusedRowIndexAtom) as + | number + | null + | undefined; - const focusedCellPosition = snapshot - .getLoadable(focusedCellPositionState) - .getValue(); + const focusedCellPosition = store.get(focusedCellPositionAtom) as + | { row: number; column: number } + | null + | undefined; - const isRecordTableCellFocusActive = snapshot - .getLoadable(isRecordTableCellFocusActiveState) - .getValue(); + const isRecordTableCellFocusActive = store.get( + isRecordTableCellFocusActiveAtom, + ); - if (!isDefined(focusedCellPosition) || !isRecordTableCellFocusActive) { - return; - } + if (!isDefined(focusedCellPosition) || !isRecordTableCellFocusActive) { + return; + } - unfocusRecordTableCell(); + unfocusRecordTableCell(); - if (isDefined(focusedRowIndex)) { - focusRecordTableRow(focusedCellPosition.row); - } - }, - [ - focusedRowIndexState, - focusedCellPositionState, - isRecordTableCellFocusActiveState, - unfocusRecordTableCell, - focusRecordTableRow, - ], - ); + if (isDefined(focusedRowIndex)) { + focusRecordTableRow(focusedCellPosition.row); + } + }, [ + store, + focusedRowIndexAtom, + focusedCellPositionAtom, + isRecordTableCellFocusActiveAtom, + unfocusRecordTableCell, + focusRecordTableRow, + ]); return { focusRecordTableRow, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts index bab0e5c406..eb4908fab7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts @@ -2,16 +2,16 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; import { computeLastRecordTableColumnWidth } from '@/object-record/record-table/utils/computeLastRecordTableColumnWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useRecordTableLastColumnWidthToFill = () => { const { visibleRecordFields } = useRecordTableContextOrThrow(); - const recordTableWidth = useRecoilComponentValue( + const recordTableWidth = useRecoilComponentValueV2( recordTableWidthComponentState, ); - const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + const shouldCompactRecordTableFirstColumn = useRecoilComponentValueV2( shouldCompactRecordTableFirstColumnComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedCell.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedCell.ts index 8ab5957701..e3fbe90967 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedCell.ts @@ -1,186 +1,163 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { type MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useFocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; export const useRecordTableMoveFocusedCell = (recordTableId?: string) => { const { focusRecordTableCell } = useFocusRecordTableCell(recordTableId); - const focusPositionState = useRecoilComponentCallbackState( + const focusPositionAtom = useRecoilComponentStateCallbackStateV2( recordTableFocusPositionComponentState, recordTableId, ); - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( + const recordIndexAllRecordIdsAtom = useRecoilComponentSelectorCallbackStateV2( recordIndexAllRecordIdsComponentSelector, recordTableId, ); - const moveUp = useRecoilCallback( - ({ snapshot }) => - () => { - const focusPosition = getSnapshotValue(snapshot, focusPositionState); + const store = useStore(); - if (!isDefined(focusPosition)) { - return; - } + const moveUp = useCallback(() => { + const focusPosition = store.get(focusPositionAtom); - let newRowIndex = focusPosition.row - 1; + if (!isDefined(focusPosition)) { + return; + } - if (newRowIndex < 0) { - newRowIndex = 0; - } + let newRowIndex = focusPosition.row - 1; - focusRecordTableCell({ - ...focusPosition, - row: newRowIndex, - }); - }, - [focusPositionState, focusRecordTableCell], - ); + if (newRowIndex < 0) { + newRowIndex = 0; + } - const moveDown = useRecoilCallback( - ({ snapshot }) => - () => { - const allRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); - const focusPosition = getSnapshotValue(snapshot, focusPositionState); + focusRecordTableCell({ + ...focusPosition, + row: newRowIndex, + }); + }, [store, focusPositionAtom, focusRecordTableCell]); - if (!isDefined(focusPosition)) { - return; - } + const moveDown = useCallback(() => { + const allRecordIds = store.get(recordIndexAllRecordIdsAtom); + const focusPosition = store.get(focusPositionAtom); - let newRowIndex = focusPosition.row + 1; + if (!isDefined(focusPosition)) { + return; + } - if (newRowIndex >= allRecordIds.length) { - newRowIndex = allRecordIds.length - 1; - } + let newRowIndex = focusPosition.row + 1; - focusRecordTableCell({ - ...focusPosition, - row: newRowIndex, - }); - }, - [recordIndexAllRecordIdsSelector, focusRecordTableCell, focusPositionState], - ); + if (newRowIndex >= allRecordIds.length) { + newRowIndex = allRecordIds.length - 1; + } - const currentRecordFieldsCallbackState = useRecoilComponentCallbackState( + focusRecordTableCell({ + ...focusPosition, + row: newRowIndex, + }); + }, [ + recordIndexAllRecordIdsAtom, + focusRecordTableCell, + focusPositionAtom, + store, + ]); + + const currentRecordFieldsAtom = useRecoilComponentStateCallbackStateV2( currentRecordFieldsComponentState, recordTableId, ); - const moveRight = useRecoilCallback( - ({ snapshot }) => - () => { - const allRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); + const moveRight = useCallback(() => { + const allRecordIds = store.get(recordIndexAllRecordIdsAtom); - const focusPosition = getSnapshotValue(snapshot, focusPositionState); + const focusPosition = store.get(focusPositionAtom); - if (!isDefined(focusPosition)) { - return; - } + if (!isDefined(focusPosition)) { + return; + } - const numberOfRecordFields = getSnapshotValue( - snapshot, - currentRecordFieldsCallbackState, - ).length; + const numberOfRecordFields = store.get(currentRecordFieldsAtom).length; - const currentColumnIndex = focusPosition.column; - const currentRowIndex = focusPosition.row; + const currentColumnIndex = focusPosition.column; + const currentRowIndex = focusPosition.row; - const isLastRowAndLastColumn = - currentColumnIndex === numberOfRecordFields - 1 && - currentRowIndex === allRecordIds.length - 1; + const isLastRowAndLastColumn = + currentColumnIndex === numberOfRecordFields - 1 && + currentRowIndex === allRecordIds.length - 1; - const isLastColumnButNotLastRow = - currentColumnIndex === numberOfRecordFields - 1 && - currentRowIndex !== allRecordIds.length - 1; + const isLastColumnButNotLastRow = + currentColumnIndex === numberOfRecordFields - 1 && + currentRowIndex !== allRecordIds.length - 1; - const isNotLastColumn = currentColumnIndex !== numberOfRecordFields - 1; + const isNotLastColumn = currentColumnIndex !== numberOfRecordFields - 1; - if (isLastRowAndLastColumn) { - return; - } + if (isLastRowAndLastColumn) { + return; + } - if (isNotLastColumn) { - focusRecordTableCell({ - row: currentRowIndex, - column: currentColumnIndex + 1, - }); - } else if (isLastColumnButNotLastRow) { - focusRecordTableCell({ - row: currentRowIndex + 1, - column: 0, - }); - } - }, - [ - recordIndexAllRecordIdsSelector, - focusPositionState, - currentRecordFieldsCallbackState, - focusRecordTableCell, - ], - ); + if (isNotLastColumn) { + focusRecordTableCell({ + row: currentRowIndex, + column: currentColumnIndex + 1, + }); + } else if (isLastColumnButNotLastRow) { + focusRecordTableCell({ + row: currentRowIndex + 1, + column: 0, + }); + } + }, [ + recordIndexAllRecordIdsAtom, + store, + focusPositionAtom, + currentRecordFieldsAtom, + focusRecordTableCell, + ]); - const moveLeft = useRecoilCallback( - ({ snapshot }) => - () => { - const focusPosition = getSnapshotValue(snapshot, focusPositionState); + const moveLeft = useCallback(() => { + const focusPosition = store.get(focusPositionAtom); - if (!isDefined(focusPosition)) { - return; - } + if (!isDefined(focusPosition)) { + return; + } - const numberOfRecordFields = getSnapshotValue( - snapshot, - currentRecordFieldsCallbackState, - ).length; + const numberOfRecordFields = store.get(currentRecordFieldsAtom).length; - const currentColumnIndex = focusPosition.column; - const currentRowIndex = focusPosition.row; + const currentColumnIndex = focusPosition.column; + const currentRowIndex = focusPosition.row; - const isFirstRowAndFirstColumn = - currentColumnIndex === 0 && currentRowIndex === 0; + const isFirstRowAndFirstColumn = + currentColumnIndex === 0 && currentRowIndex === 0; - const isFirstColumnButNotFirstRow = - currentColumnIndex === 0 && currentRowIndex > 0; + const isFirstColumnButNotFirstRow = + currentColumnIndex === 0 && currentRowIndex > 0; - const isNotFirstColumn = currentColumnIndex > 0; + const isNotFirstColumn = currentColumnIndex > 0; - if (isFirstRowAndFirstColumn) { - return; - } + if (isFirstRowAndFirstColumn) { + return; + } - if (isNotFirstColumn) { - focusRecordTableCell({ - row: currentRowIndex, - column: currentColumnIndex - 1, - }); - } else if (isFirstColumnButNotFirstRow) { - focusRecordTableCell({ - row: currentRowIndex - 1, - column: numberOfRecordFields - 1, - }); - } - }, - [ - currentRecordFieldsCallbackState, - focusPositionState, - focusRecordTableCell, - ], - ); + if (isNotFirstColumn) { + focusRecordTableCell({ + row: currentRowIndex, + column: currentColumnIndex - 1, + }); + } else if (isFirstColumnButNotFirstRow) { + focusRecordTableCell({ + row: currentRowIndex - 1, + column: numberOfRecordFields - 1, + }); + } + }, [currentRecordFieldsAtom, focusPositionAtom, focusRecordTableCell, store]); const moveFocus = (direction: MoveFocusDirection) => { switch (direction) { diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedRow.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedRow.ts index 65d72e2068..6cd636d4d8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedRow.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocusedRow.ts @@ -1,81 +1,73 @@ -import { useRecoilCallback } from 'recoil'; - import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/useFocusedRecordTableRow'; import { focusedRecordTableRowIndexComponentState } from '@/object-record/record-table/states/focusedRecordTableRowIndexComponentState'; import { type MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRecordTableMoveFocusedRow = (recordTableId?: string) => { const { focusRecordTableRow } = useFocusedRecordTableRow(recordTableId); - const focusedRowIndexState = useRecoilComponentCallbackState( + const focusedRowIndexAtom = useRecoilComponentStateCallbackStateV2( focusedRecordTableRowIndexComponentState, recordTableId, ); - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( + const recordIndexAllRecordIdsAtom = useRecoilComponentSelectorCallbackStateV2( recordIndexAllRecordIdsComponentSelector, recordTableId, ); - const moveFocusedRowUp = useRecoilCallback( - ({ snapshot }) => - () => { - const focusedRowIndex = getSnapshotValue( - snapshot, - focusedRowIndexState, - ); + const store = useStore(); - if (!isDefined(focusedRowIndex)) { - focusRecordTableRow(0); - return; - } + const moveFocusedRowUp = useCallback(() => { + const focusedRowIndex = store.get(focusedRowIndexAtom) as + | number + | null + | undefined; - let newRowIndex = focusedRowIndex - 1; + if (!isDefined(focusedRowIndex)) { + focusRecordTableRow(0); + return; + } - if (newRowIndex < 0) { - newRowIndex = 0; - } + let newRowIndex = focusedRowIndex - 1; - focusRecordTableRow(newRowIndex); - }, - [focusedRowIndexState, focusRecordTableRow], - ); + if (newRowIndex < 0) { + newRowIndex = 0; + } - const moveFocusedRowDown = useRecoilCallback( - ({ snapshot }) => - () => { - const allRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); - const focusedRowIndex = getSnapshotValue( - snapshot, - focusedRowIndexState, - ); + focusRecordTableRow(newRowIndex); + }, [store, focusedRowIndexAtom, focusRecordTableRow]); - if (!isDefined(focusedRowIndex)) { - focusRecordTableRow(0); - return; - } + const moveFocusedRowDown = useCallback(() => { + const allRecordIds = store.get(recordIndexAllRecordIdsAtom); + const focusedRowIndex = store.get(focusedRowIndexAtom) as + | number + | null + | undefined; - let newRowIndex = focusedRowIndex + 1; + if (!isDefined(focusedRowIndex)) { + focusRecordTableRow(0); + return; + } - if (newRowIndex >= allRecordIds.length) { - newRowIndex = allRecordIds.length - 1; - } + let newRowIndex = focusedRowIndex + 1; - focusRecordTableRow(newRowIndex); - }, - [ - recordIndexAllRecordIdsSelector, - focusedRowIndexState, - focusRecordTableRow, - ], - ); + if (newRowIndex >= allRecordIds.length) { + newRowIndex = allRecordIds.length - 1; + } + + focusRecordTableRow(newRowIndex); + }, [ + recordIndexAllRecordIdsAtom, + focusedRowIndexAtom, + focusRecordTableRow, + store, + ]); const moveFocusedRow = (direction: MoveFocusDirection) => { if (direction === 'up') { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEscapeHotkeyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEscapeHotkeyEffect.tsx index 75f276d4c9..12d6a66a46 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEscapeHotkeyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEscapeHotkeyEffect.tsx @@ -4,12 +4,12 @@ import { useResetTableRowSelection } from '@/object-record/record-table/hooks/in import { isAtLeastOneTableRowSelectedSelector } from '@/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector'; import { PageFocusId } from '@/types/PageFocusId'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; export const RecordTableBodyEscapeHotkeyEffect = () => { const { resetTableRowSelection } = useResetTableRowSelection(); - const isAtLeastOneRecordSelected = useRecoilComponentValue( + const isAtLeastOneRecordSelected = useRecoilComponentSelectorValueV2( isAtLeastOneTableRowSelectedSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyNoRecordGroupDragDropContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyNoRecordGroupDragDropContextProvider.tsx index 5b9a31c8d2..b4bca62b5f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyNoRecordGroupDragDropContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyNoRecordGroupDragDropContextProvider.tsx @@ -3,12 +3,12 @@ import { type DragStart, type DropResult, } from '@hello-pangea/dnd'; -import { type ReactNode } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { type ReactNode, useCallback } from 'react'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; import { useEndRecordDrag } from '@/object-record/record-drag/hooks/useEndRecordDrag'; import { useProcessTableWithoutGroupRecordDrop } from '@/object-record/record-drag/hooks/useProcessTableWithoutGroupRecordDrop'; @@ -20,33 +20,34 @@ export const RecordTableBodyNoRecordGroupDragDropContextProvider = ({ }: { children: ReactNode; }) => { + const { recordIndexId } = useRecordIndexContextOrThrow(); const { recordTableId } = useRecordTableContextOrThrow(); - const selectedRowIdsSelector = useRecoilComponentCallbackState( + const selectedRowIdsAtom = useRecoilComponentSelectorCallbackStateV2( selectedRowIdsComponentSelector, recordTableId, ); - const { startRecordDrag } = useStartRecordDrag(); - const { endRecordDrag } = useEndRecordDrag(); + const store = useStore(); + + const { startRecordDrag } = useStartRecordDrag(recordIndexId); + const { endRecordDrag } = useEndRecordDrag(recordIndexId); const { processTableWithoutGroupRecordDrop } = useProcessTableWithoutGroupRecordDrop(); - const handleDragStart = useRecoilCallback( - ({ snapshot }) => - (start: DragStart) => { - const currentSelectedRecordIds = getSnapshotValue( - snapshot, - selectedRowIdsSelector, - ); + const handleDragStart = useCallback( + (start: DragStart) => { + const currentSelectedRecordIds = store.get( + selectedRowIdsAtom, + ) as string[]; - startRecordDrag(start, currentSelectedRecordIds); - }, - [selectedRowIdsSelector, startRecordDrag], + startRecordDrag(start, currentSelectedRecordIds); + }, + [selectedRowIdsAtom, startRecordDrag, store], ); - const handleDragEnd = useRecoilCallback( - () => (result: DropResult) => { + const handleDragEnd = useCallback( + (result: DropResult) => { processTableWithoutGroupRecordDrop(result); endRecordDrag(); }, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx index 9ce344bfee..bafff7d382 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx @@ -1,51 +1,52 @@ import { useEndRecordDrag } from '@/object-record/record-drag/hooks/useEndRecordDrag'; import { useProcessTableWithGroupRecordDrop } from '@/object-record/record-drag/hooks/useProcessTableWithGroupRecordDrop'; import { useStartRecordDrag } from '@/object-record/record-drag/hooks/useStartRecordDrag'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useStore } from 'jotai'; import { DragDropContext, type DragStart, type DropResult, } from '@hello-pangea/dnd'; -import { type ReactNode } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { type ReactNode, useCallback } from 'react'; export const RecordTableBodyRecordGroupDragDropContextProvider = ({ children, }: { children: ReactNode; }) => { + const { recordIndexId } = useRecordIndexContextOrThrow(); const { recordTableId } = useRecordTableContextOrThrow(); - const selectedRowIdsSelector = useRecoilComponentCallbackState( + const selectedRowIdsAtom = useRecoilComponentSelectorCallbackStateV2( selectedRowIdsComponentSelector, recordTableId, ); - const { startRecordDrag } = useStartRecordDrag(); - const { endRecordDrag } = useEndRecordDrag(); + const store = useStore(); + + const { startRecordDrag } = useStartRecordDrag(recordIndexId); + const { endRecordDrag } = useEndRecordDrag(recordIndexId); const { processTableWithGroupRecordDrop } = useProcessTableWithGroupRecordDrop(); - const handleDragStart = useRecoilCallback( - ({ snapshot }) => - (start: DragStart) => { - const currentSelectedRecordIds = getSnapshotValue( - snapshot, - selectedRowIdsSelector, - ); + const handleDragStart = useCallback( + (start: DragStart) => { + const currentSelectedRecordIds = store.get( + selectedRowIdsAtom, + ) as string[]; - startRecordDrag(start, currentSelectedRecordIds); - }, - [selectedRowIdsSelector, startRecordDrag], + startRecordDrag(start, currentSelectedRecordIds); + }, + [selectedRowIdsAtom, startRecordDrag, store], ); - const handleDragEnd = useRecoilCallback( - () => (result: DropResult) => { + const handleDragEnd = useCallback( + (result: DropResult) => { processTableWithGroupRecordDrop(result); endRecordDrag(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx index e823073745..1fc9763d3b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx @@ -26,7 +26,7 @@ import { useIsTableRowSecondaryDragged } from '@/object-record/record-table/reco import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; import { getRecordTableColumnFieldWidthCSSVariableName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthCSSVariableName'; import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { @@ -147,7 +147,7 @@ export const RecordTableBodyVirtualizedDraggableClone = ({ const theme = useTheme(); - const recordId = useRecoilComponentFamilyValue( + const recordId = useRecoilComponentFamilySelectorValueV2( recordIdByRealIndexComponentFamilySelector, realIndex, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody.tsx index 3f72760c5a..1b6672e57d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody.tsx @@ -11,14 +11,15 @@ import { isRecordTableInitialLoadingComponentState } from '@/object-record/recor import { RecordTableVirtualizedDataChangedEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedDataChangedEffect'; import { RecordTableVirtualizedSSESubscribeEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedSSESubscribeEffect'; import { RecordTableVirtualizedRowTreadmillEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const RecordTableNoRecordGroupBody = () => { - const recordTableHasRecords = useRecoilComponentValue( + const recordTableHasRecords = useRecoilComponentSelectorValueV2( recordIndexHasRecordsComponentSelector, ); - const isRecordTableInitialLoading = useRecoilComponentValue( + const isRecordTableInitialLoading = useRecoilComponentValueV2( isRecordTableInitialLoadingComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx index a6e9322f7a..9994d21d28 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; -import { useRecoilState } from 'recoil'; import { lastShowPageRecordIdState } from '@/object-record/record-field/ui/states/lastShowPageRecordId'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; import { useRecordIndexTableQuery } from '@/object-record/record-index/hooks/useRecordIndexTableQuery'; import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState'; @@ -11,8 +11,8 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte import { useSetRecordTableData } from '@/object-record/record-table/hooks/internal/useSetRecordTableData'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition'; -import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentFamilyStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isNonEmptyString } from '@sniptt/guards'; export const RecordTableRecordGroupBodyEffect = () => { @@ -23,7 +23,7 @@ export const RecordTableRecordGroupBodyEffect = () => { recordTableId, }); - const setIsRecordTableInitialLoading = useSetRecoilComponentState( + const setIsRecordTableInitialLoading = useSetRecoilComponentStateV2( isRecordTableInitialLoadingComponentState, ); @@ -33,12 +33,12 @@ export const RecordTableRecordGroupBodyEffect = () => { useRecordIndexTableQuery(objectNameSingular); const setHasRecordFetchedAllRecordsComponents = - useSetRecoilComponentFamilyState( + useSetRecoilComponentFamilyStateV2( recordIndexHasFetchedAllRecordsByGroupComponentState, recordGroupId, ); - const [lastShowPageRecordId] = useRecoilState(lastShowPageRecordIdState); + const lastShowPageRecordId = useRecoilValueV2(lastShowPageRecordIdState); const { scrollToPosition } = useScrollToPosition(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects.tsx index c8e7dd90cc..eb7f4cddf3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects.tsx @@ -1,10 +1,12 @@ import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext'; import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { RecordTableRecordGroupBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const RecordTableRecordGroupBodyEffects = () => { - const recordGroupIds = useRecoilComponentValue(recordGroupIdsComponentState); + const recordGroupIds = useRecoilComponentValueV2( + recordGroupIdsComponentState, + ); return recordGroupIds.map((recordGroupId) => ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx index 651a26365b..8092776da4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx @@ -10,20 +10,21 @@ import { RecordTableBodyRecordGroupDroppable } from '@/object-record/record-tabl import { RecordTableCellPortals } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortals'; import { RecordTableRecordGroupSection } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { ViewType } from '@/views/types/ViewType'; export const RecordTableRecordGroupsBody = () => { - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, ); - const isRecordTableInitialLoading = useRecoilComponentValue( + const isRecordTableInitialLoading = useRecoilComponentValueV2( isRecordTableInitialLoadingComponentState, ); - const visibleRecordGroupIds = useRecoilComponentFamilyValue( + const visibleRecordGroupIds = useRecoilComponentFamilySelectorValueV2( visibleRecordGroupIdsComponentFamilySelector, ViewType.Table, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx index 4c0752676a..543db097b3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditMode.tsx @@ -7,8 +7,8 @@ import { RecordTableCellContext } from '@/object-record/record-table/contexts/Re import { useFocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell'; import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { autoUpdate, @@ -45,19 +45,19 @@ export type RecordTableCellEditModeProps = { export const RecordTableCellEditMode = ({ children, }: RecordTableCellEditModeProps) => { - const isFieldInError = useRecoilComponentValue( + const isFieldInError = useRecoilComponentValueV2( recordFieldInputIsFieldInErrorComponentState, ); const recordFieldComponentInstanceId = useAvailableComponentInstanceIdOrThrow( RecordFieldComponentInstanceContext, ); - const setFieldInputLayoutDirection = useSetRecoilComponentState( + const setFieldInputLayoutDirection = useSetRecoilComponentStateV2( recordFieldInputLayoutDirectionComponentState, recordFieldComponentInstanceId, ); - const setFieldInputLayoutDirectionLoading = useSetRecoilComponentState( + const setFieldInputLayoutDirectionLoading = useSetRecoilComponentStateV2( recordFieldInputLayoutDirectionLoadingComponentState, recordFieldComponentInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditModePortal.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditModePortal.tsx index 5bf67064ab..f61c9167ec 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditModePortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellEditModePortal.tsx @@ -1,5 +1,6 @@ import { RecordTableCellPortalWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortalWrapper'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector'; import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex'; @@ -13,15 +14,15 @@ import { recordTableFocusPositionComponentState } from '@/object-record/record-t import { isDefined } from 'twenty-shared/utils'; export const RecordTableCellEditModePortal = () => { - const focusedCellPosition = useRecoilComponentValue( + const focusedCellPosition = useRecoilComponentValueV2( recordTableFocusPositionComponentState, ); - const currentTableCellInEditModePosition = useRecoilComponentValue( + const currentTableCellInEditModePosition = useRecoilComponentValueV2( recordTableCellEditModePositionComponentState, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx index 5123fff210..cc96039e87 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx @@ -7,7 +7,7 @@ import { RecordUpdateContext } from '@/object-record/record-table/contexts/Entit import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext, type ReactNode } from 'react'; type RecordTableCellFieldContextLabelIdentifierProps = { @@ -33,7 +33,7 @@ export const RecordTableCellFieldContextLabelIdentifier = ({ objectMetadataItem.id, ); - const shouldCompactRecordIndexLabelIdentifier = useRecoilComponentValue( + const shouldCompactRecordIndexLabelIdentifier = useRecoilComponentValueV2( shouldCompactRecordIndexLabelIdentifierComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFirstRowFirstColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFirstRowFirstColumn.tsx index 6ce1f007c8..5c4cfdb69b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFirstRowFirstColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFirstRowFirstColumn.tsx @@ -4,8 +4,8 @@ import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/r import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { type DraggableProvidedDragHandleProps } from '@hello-pangea/dnd'; import { cx } from '@linaria/core'; @@ -33,11 +33,11 @@ export const RecordTableCellFirstRowFirstColumn = ({ } & (Partial | null)) => { const { theme } = useContext(ThemeContext); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordTableHoverPositionComponentState, ); - const focusPosition = useRecoilComponentValue( + const focusPosition = useRecoilComponentValueV2( recordTableFocusPositionComponentState, ); @@ -47,7 +47,7 @@ export const RecordTableCellFirstRowFirstColumn = ({ const isHoveredPortalOnThisCell = hoverPosition?.column === 0 && hoverPosition.row === 0; - const [isRecordTableScrolledVertically] = useRecoilComponentState( + const [isRecordTableScrolledVertically] = useRecoilComponentStateV2( isRecordTableScrolledVerticallyComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortal.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortal.tsx index 943272e1bf..bb9f047de9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortal.tsx @@ -1,5 +1,6 @@ import { RecordTableCellPortalWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortalWrapper'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector'; import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex'; @@ -12,23 +13,23 @@ import { recordTableHoverPositionComponentState } from '@/object-record/record-t import { isDefined } from 'twenty-shared/utils'; export const RecordTableCellFocusedPortal = () => { - const focusPosition = useRecoilComponentValue( + const focusPosition = useRecoilComponentValueV2( recordTableFocusPositionComponentState, ); - const isRecordTableScrolledVertically = useRecoilComponentValue( + const isRecordTableScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isRecordTableScrolledHorizontally = useRecoilComponentValue( + const isRecordTableScrolledHorizontally = useRecoilComponentValueV2( isRecordTableScrolledHorizontallyComponentState, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordTableHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortalContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortalContent.tsx index a3089793f8..abe827fa57 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortalContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFocusedPortalContent.tsx @@ -7,8 +7,8 @@ import { RecordTableCellDisplayMode } from '@/object-record/record-table/record- import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; import { BORDER_COMMON } from 'twenty-ui/theme'; @@ -35,16 +35,16 @@ export const RecordTableCellFocusedPortalContent = () => { const { rowIndex } = useRecordTableRowContextOrThrow(); const { onMoveHoverToCurrentCell } = useRecordTableBodyContextOrThrow(); - const focusPosition = useRecoilComponentValue( + const focusPosition = useRecoilComponentValueV2( recordTableFocusPositionComponentState, ); - const isRowActive = useRecoilComponentFamilyValue( + const isRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, rowIndex, ); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordTableHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortal.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortal.tsx index d51dfe060f..0644dfe9be 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortal.tsx @@ -1,6 +1,7 @@ import { RecordTableCellPortalWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellPortalWrapper'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector'; import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex'; @@ -11,19 +12,19 @@ import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/r import { isDefined } from 'twenty-shared/utils'; export const RecordTableCellHoveredPortal = () => { - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordTableHoverPositionComponentState, ); - const isRecordTableScrolledVertically = useRecoilComponentValue( + const isRecordTableScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isRecordTableScrolledHorizontally = useRecoilComponentValue( + const isRecordTableScrolledHorizontally = useRecoilComponentValueV2( isRecordTableScrolledHorizontallyComponentState, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx index 7131df7670..f893fa0d3c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx @@ -10,8 +10,8 @@ import { RecordTableCellFieldInput } from '@/object-record/record-table/record-t import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { useContext } from 'react'; import { BORDER_COMMON } from 'twenty-ui/theme'; @@ -45,7 +45,7 @@ const StyledRecordTableCellHoveredPortalContent = styled.div<{ `; export const RecordTableCellHoveredPortalContent = () => { - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordTableHoverPositionComponentState, ); @@ -66,7 +66,7 @@ export const RecordTableCellHoveredPortalContent = () => { const { rowIndex } = useRecordTableRowContextOrThrow(); - const isRowActive = useRecoilComponentFamilyValue( + const isRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, rowIndex, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortalContexts.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortalContexts.tsx index 9847fdb740..314f5fe6c3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortalContexts.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortalContexts.tsx @@ -7,7 +7,7 @@ import { RecordTableCellContext } from '@/object-record/record-table/contexts/Re import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; export const RecordTableCellPortalContexts = ({ @@ -17,13 +17,13 @@ export const RecordTableCellPortalContexts = ({ position: TableCellPosition; children: React.ReactNode; }) => { - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, ); const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortals.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortals.tsx index 367089548c..e59c92dc2b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortals.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellPortals.tsx @@ -5,13 +5,13 @@ import { RecordTableCellFocusedPortal } from '@/object-record/record-table/recor import { RecordTableCellHoveredPortal } from '@/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortal'; import { useCurrentlyFocusedRecordTableCellFocusId } from '@/object-record/record-table/record-table-cell/hooks/useCurrentlyFocusedRecordTableCellFocusId'; import { isRecordTableCellFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableCellFocusActiveComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const RecordTableCellPortals = () => { const { recordTableId } = useRecordTableContextOrThrow(); - const isRecordTableFocusActive = useRecoilComponentValue( + const isRecordTableFocusActive = useRecoilComponentValueV2( isRecordTableCellFocusActiveComponentState, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveHoverToCurrentCell.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveHoverToCurrentCell.test.tsx index 2a1c0fc944..f871ef62fa 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveHoverToCurrentCell.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveHoverToCurrentCell.test.tsx @@ -1,8 +1,10 @@ import { renderHook } from '@testing-library/react'; +import { Provider as JotaiProvider, useAtomValue } from 'jotai'; import { act } from 'react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; @@ -15,26 +17,30 @@ import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-t import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; const Wrapper = ({ children }: { children: React.ReactNode }) => ( - - - - - - {children} - - - - - + + + + + + + {children} + + + + + + ); describe('useMoveHoverToCurrentCell', () => { it('should work as expected', () => { const { result } = renderHook( () => { - const recordTableHoverPosition = useRecoilValue( + const recordTableHoverPosition = useAtomValue( recordTableHoverPositionComponentState.atomFamily({ instanceId: 'test-record-table-instance-id', }), diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSetIsRecordTableFocusActive.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSetIsRecordTableFocusActive.test.tsx index 219a9a0f1d..6b9b31e0ca 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSetIsRecordTableFocusActive.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useSetIsRecordTableFocusActive.test.tsx @@ -1,12 +1,14 @@ import { renderHook } from '@testing-library/react'; +import { useAtomValue } from 'jotai'; import React, { act } from 'react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { useSetIsRecordTableCellFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableCellFocusActive'; import { isRecordTableCellFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableCellFocusActiveComponentState'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; const mockClassList = { add: jest.fn(), @@ -15,26 +17,10 @@ const mockClassList = { const mockGetElementById = jest.spyOn(document, 'getElementById'); +const instanceId = { instanceId: 'test-table-id' }; + const Wrapper = ({ children }: { children: React.ReactNode }) => ( - { - set( - isRecordTableCellFocusActiveComponentState.atomFamily({ - instanceId: 'test-table-id', - }), - false, - ); - set( - recordTableFocusPositionComponentState.atomFamily({ - instanceId: 'test-table-id', - }), - { - column: 1, - row: 0, - }, - ); - }} - > + {children} @@ -47,16 +33,12 @@ const renderHooks = () => { const { setIsRecordTableCellFocusActive } = useSetIsRecordTableCellFocusActive('test-table-id'); - const isRecordTableFocusActive = useRecoilValue( - isRecordTableCellFocusActiveComponentState.atomFamily({ - instanceId: 'test-table-id', - }), + const isRecordTableFocusActive = useAtomValue( + isRecordTableCellFocusActiveComponentState.atomFamily(instanceId), ); - const focusPosition = useRecoilValue( - recordTableFocusPositionComponentState.atomFamily({ - instanceId: 'test-table-id', - }), + const focusPosition = useAtomValue( + recordTableFocusPositionComponentState.atomFamily(instanceId), ); return { setIsRecordTableCellFocusActive, @@ -74,6 +56,15 @@ describe('useSetIsRecordTableFocusActive', () => { beforeEach(() => { jest.clearAllMocks(); + jotaiStore.set( + isRecordTableCellFocusActiveComponentState.atomFamily(instanceId), + false, + ); + jotaiStore.set( + recordTableFocusPositionComponentState.atomFamily(instanceId), + { column: 1, row: 0 }, + ); + mockGetElementById.mockReturnValue({ classList: mockClassList, } as unknown as HTMLElement); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx index dfc044446e..151e194418 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx @@ -20,7 +20,7 @@ import { import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup'; import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; @@ -78,8 +78,9 @@ describe('useCloseRecordTableCellInGroup', () => { it('should work as expected', async () => { const { result } = renderHook( () => { - const currentTableCellInEditModePosition = useRecoilComponentValue( + const currentTableCellInEditModePosition = useRecoilComponentValueV2( recordTableCellEditModePositionComponentState, + recordTableId, ); return { ...useCloseRecordTableCellInGroup(), diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx index e27604d98f..11c2889431 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx @@ -20,7 +20,7 @@ import { import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup'; import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; @@ -79,8 +79,9 @@ describe('useCloseRecordTableCellNoGroup', () => { it('should work as expected', async () => { const { result } = renderHook( () => { - const currentTableCellInEditModePosition = useRecoilComponentValue( + const currentTableCellInEditModePosition = useRecoilComponentValueV2( recordTableCellEditModePositionComponentState, + recordTableId, ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentlyFocusedRecordTableCellFocusId.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentlyFocusedRecordTableCellFocusId.ts index 8ae23dbbf6..74904bef37 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentlyFocusedRecordTableCellFocusId.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useCurrentlyFocusedRecordTableCellFocusId.ts @@ -1,13 +1,13 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { getRecordTableCellFocusId } from '@/object-record/record-table/record-table-cell/utils/getRecordTableCellFocusId'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useCurrentlyFocusedRecordTableCellFocusId = () => { const { recordTableId } = useRecordTableContextOrThrow(); - const focusPosition = useRecoilComponentValue( + const focusPosition = useRecoilComponentValueV2( recordTableFocusPositionComponentState, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell.ts index 700eae2e6a..18183c4b23 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell.ts @@ -5,8 +5,9 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; import { useSetIsRecordTableCellFocusActive } from './useSetIsRecordTableCellFocusActive'; @@ -17,7 +18,8 @@ export const useFocusRecordTableCell = (recordTableId?: string) => { recordTableId, ); - const focusPositionCallbackState = useRecoilComponentCallbackState( + const store = useStore(); + const focusPositionAtom = useRecoilComponentStateCallbackStateV2( recordTableFocusPositionComponentState, recordTableIdFromProps, ); @@ -29,45 +31,45 @@ export const useFocusRecordTableCell = (recordTableId?: string) => { const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const focusRecordTableCell = useRecoilCallback( - ({ snapshot }) => { - return (newPosition: TableCellPosition) => { - const currentPosition = snapshot - .getLoadable(focusPositionCallbackState) - .getValue(); + const focusRecordTableCell = useCallback( + (newPosition: TableCellPosition) => { + const currentPosition = store.get(focusPositionAtom) as + | TableCellPosition + | null + | undefined; - if (isDefined(currentPosition)) { - const currentCellFocusId = getRecordTableCellFocusId({ - recordTableId: recordTableIdFromProps, - cellPosition: currentPosition, - }); - - removeFocusItemFromFocusStackById({ - focusId: currentCellFocusId, - }); - } - - setIsRecordTableCellFocusActive({ - isRecordTableFocusActive: true, - cellPosition: newPosition, - }); - - const cellFocusId = getRecordTableCellFocusId({ + if (isDefined(currentPosition)) { + const currentCellFocusId = getRecordTableCellFocusId({ recordTableId: recordTableIdFromProps, - cellPosition: newPosition, + cellPosition: currentPosition, }); - pushFocusItemToFocusStack({ - focusId: cellFocusId, - component: { - type: FocusComponentType.RECORD_TABLE_CELL, - instanceId: cellFocusId, - }, + removeFocusItemFromFocusStackById({ + focusId: currentCellFocusId, }); - }; + } + + setIsRecordTableCellFocusActive({ + isRecordTableFocusActive: true, + cellPosition: newPosition, + }); + + const cellFocusId = getRecordTableCellFocusId({ + recordTableId: recordTableIdFromProps, + cellPosition: newPosition, + }); + + pushFocusItemToFocusStack({ + focusId: cellFocusId, + component: { + type: FocusComponentType.RECORD_TABLE_CELL, + instanceId: cellFocusId, + }, + }); }, [ - focusPositionCallbackState, + store, + focusPositionAtom, recordTableIdFromProps, removeFocusItemFromFocusStackById, setIsRecordTableCellFocusActive, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell.ts index 82b56c37f8..77f944d0b7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell.ts @@ -1,37 +1,35 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useStore } from 'jotai'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const useMoveHoverToCurrentCell = (recordTableId: string) => { - const setHoverPosition = useSetRecoilComponentState( + const setHoverPosition = useSetRecoilComponentStateV2( recordTableHoverPositionComponentState, recordTableId, ); - const isSomeCellInEditModeSelector = useRecoilComponentCallbackState( + const isSomeCellInEditModeAtom = useRecoilComponentSelectorCallbackStateV2( isSomeCellInEditModeComponentSelector, recordTableId, ); - const moveHoverToCurrentCell = useRecoilCallback( - ({ snapshot }) => - (cellPosition: TableCellPosition) => { - const isSomeCellInEditMode = getSnapshotValue( - snapshot, - isSomeCellInEditModeSelector, - ); + const store = useStore(); - if (!isSomeCellInEditMode) { - setHoverPosition(cellPosition); - } - }, - [isSomeCellInEditModeSelector, setHoverPosition], + const moveHoverToCurrentCell = useCallback( + (cellPosition: TableCellPosition) => { + const isSomeCellInEditMode = store.get(isSomeCellInEditModeAtom); + + if (!isSomeCellInEditMode) { + setHoverPosition(cellPosition); + } + }, + [store, isSomeCellInEditModeAtom, setHoverPosition], ); return { moveHoverToCurrentCell }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell.ts index 901a44a75a..b39a63693a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell.ts @@ -1,20 +1,17 @@ -import { useRecoilCallback } from 'recoil'; - import { useInitDraftValue } from '@/object-record/record-field/ui/hooks/useInitDraftValue'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldValueEmpty } from '@/object-record/record-field/ui/utils/isFieldValueEmpty'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { FOCUS_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/FocusClickOutsideListenerId'; import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix'; import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/useLeaveTableFocus'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; - import { useOpenFieldInputEditMode } from '@/object-record/record-field/ui/hooks/useOpenFieldInputEditMode'; import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId'; import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState'; import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField'; @@ -28,8 +25,9 @@ import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/use import { useFocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell'; import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; export type OpenTableCellArgs = { @@ -45,7 +43,7 @@ export const useOpenRecordTableCell = (recordTableId: string) => { const { scopeInstanceId } = useRecordFieldsScopeContextOrThrow(); const store = useStore(); - const setCurrentTableCellInEditModePosition = useSetRecoilComponentState( + const setCurrentTableCellInEditModePosition = useSetRecoilComponentStateV2( recordTableCellEditModePositionComponentState, recordTableId, ); @@ -69,7 +67,7 @@ export const useOpenRecordTableCell = (recordTableId: string) => { const { unfocusRecordTableRow } = useFocusedRecordTableRow(recordTableId); - const setIsRowFocusActive = useSetRecoilComponentState( + const setIsRowFocusActive = useSetRecoilComponentStateV2( isRecordTableRowFocusActiveComponentState, recordTableId, ); @@ -78,98 +76,94 @@ export const useOpenRecordTableCell = (recordTableId: string) => { const { openRecordFromIndexView } = useOpenRecordFromIndexView(); - const openTableCell = useRecoilCallback( - ({ snapshot }) => - ({ - initialValue, - cellPosition, - isReadOnly, + const openTableCell = useCallback( + ({ + initialValue, + cellPosition, + isReadOnly, + fieldDefinition, + recordId, + isNavigating, + }: OpenTableCellArgs) => { + store.set( + clickOutsideListenerIsActivatedComponentState.atomFamily({ + instanceId: RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID, + }), + false, + ); + + const isFirstColumnCell = cellPosition.column === 0; + + const fieldValue = store.get( + recordStoreFamilySelectorV2.selectorFamily({ + recordId, + fieldName: fieldDefinition.metadata.fieldName, + }), + ); + + const isEmpty = isFieldValueEmpty({ + fieldDefinition, + fieldValue, + }); + + if ((isFirstColumnCell && !isEmpty) || isNavigating) { + leaveTableFocus(); + + const openRecordIn = jotaiStore.get(recordIndexOpenRecordInState.atom); + + if (openRecordIn === ViewOpenRecordInType.SIDE_PANEL) { + activateRecordTableRow(cellPosition.row); + unfocusRecordTableRow(); + } + + openRecordFromIndexView({ recordId }); + + return; + } + + // Block editing for read-only records, but allow navigation (handled above) + if (isReadOnly) { + return; + } + + deactivateRecordTableRow(); + + focusRecordTableCell(cellPosition); + + setIsRowFocusActive(false); + + setDragSelectionStartEnabled(false); + + openFieldInput({ fieldDefinition, recordId, - isNavigating, - }: OpenTableCellArgs) => { - store.set( - clickOutsideListenerIsActivatedComponentState.atomFamily({ - instanceId: RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID, - }), - false, - ); + prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX, + }); - const isFirstColumnCell = cellPosition.column === 0; + setCurrentTableCellInEditModePosition(cellPosition); - const fieldValue = getSnapshotValue( - snapshot, - recordStoreFamilySelector({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - }), - ); - - const isEmpty = isFieldValueEmpty({ - fieldDefinition, - fieldValue, - }); - - if ((isFirstColumnCell && !isEmpty) || isNavigating) { - leaveTableFocus(); - - const openRecordIn = snapshot - .getLoadable(recordIndexOpenRecordInState) - .getValue(); - - if (openRecordIn === ViewOpenRecordInType.SIDE_PANEL) { - activateRecordTableRow(cellPosition.row); - unfocusRecordTableRow(); - } - - openRecordFromIndexView({ recordId }); - - return; - } - - // Block editing for read-only records, but allow navigation (handled above) - if (isReadOnly) { - return; - } - - deactivateRecordTableRow(); - - focusRecordTableCell(cellPosition); - - setIsRowFocusActive(false); - - setDragSelectionStartEnabled(false); - - openFieldInput({ - fieldDefinition, + initDraftValue({ + value: initialValue, + recordId, + fieldDefinition, + fieldComponentInstanceId: getRecordFieldInputInstanceId({ recordId, + fieldName: fieldDefinition.metadata.fieldName, prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX, - }); + }), + }); - setCurrentTableCellInEditModePosition(cellPosition); + toggleClickOutside(false); - initDraftValue({ - value: initialValue, + setActiveDropdownFocusIdAndMemorizePrevious( + getDropdownFocusIdForRecordField({ recordId, - fieldDefinition, - fieldComponentInstanceId: getRecordFieldInputInstanceId({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX, - }), - }); - - toggleClickOutside(false); - - setActiveDropdownFocusIdAndMemorizePrevious( - getDropdownFocusIdForRecordField({ - recordId, - fieldMetadataId: fieldDefinition.fieldMetadataId, - componentType: 'table-cell', - instanceId: scopeInstanceId, - }), - ); - }, + fieldMetadataId: fieldDefinition.fieldMetadataId, + componentType: 'table-cell', + instanceId: scopeInstanceId, + }), + ); + }, [ deactivateRecordTableRow, focusRecordTableCell, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableCellFocusActive.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableCellFocusActive.ts index 25d5268ad3..69af691336 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableCellFocusActive.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableCellFocusActive.ts @@ -1,41 +1,41 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { isRecordTableCellFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableCellFocusActiveComponentState'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useSetIsRecordTableCellFocusActive = (recordTableId?: string) => { - const isRecordTableFocusActiveCallbackState = useRecoilComponentCallbackState( - isRecordTableCellFocusActiveComponentState, - recordTableId, - ); + const store = useStore(); + const isRecordTableCellFocusActiveAtom = + useRecoilComponentStateCallbackStateV2( + isRecordTableCellFocusActiveComponentState, + recordTableId, + ); - const recordTableFocusPositionCallbackState = useRecoilComponentCallbackState( + const recordTableFocusPositionAtom = useRecoilComponentStateCallbackStateV2( recordTableFocusPositionComponentState, recordTableId, ); - const setIsRecordTableCellFocusActive = useRecoilCallback( - ({ set }) => - ({ - isRecordTableFocusActive, - cellPosition, - }: { - isRecordTableFocusActive: boolean; - cellPosition: TableCellPosition; - }) => { - if (isRecordTableFocusActive) { - set(isRecordTableFocusActiveCallbackState, true); - set(recordTableFocusPositionCallbackState, cellPosition); - } else { - set(isRecordTableFocusActiveCallbackState, false); - set(recordTableFocusPositionCallbackState, null); - } - }, - [ - isRecordTableFocusActiveCallbackState, - recordTableFocusPositionCallbackState, - ], + const setIsRecordTableCellFocusActive = useCallback( + ({ + isRecordTableFocusActive, + cellPosition, + }: { + isRecordTableFocusActive: boolean; + cellPosition: TableCellPosition; + }) => { + if (isRecordTableFocusActive) { + store.set(isRecordTableCellFocusActiveAtom, true); + store.set(recordTableFocusPositionAtom, cellPosition); + } else { + store.set(isRecordTableCellFocusActiveAtom, false); + store.set(recordTableFocusPositionAtom, null); + } + }, + [store, isRecordTableCellFocusActiveAtom, recordTableFocusPositionAtom], ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts index 73417b813d..1fe70f0e9f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts @@ -1,4 +1,5 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; @@ -7,8 +8,8 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; export const useTriggerActionMenuDropdown = ({ recordTableId, @@ -19,7 +20,7 @@ export const useTriggerActionMenuDropdown = ({ ActionMenuComponentInstanceContext, ); - const isRowSelectedFamilyState = useRecoilComponentCallbackState( + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( isRowSelectedComponentFamilyState, recordTableId, ); @@ -28,46 +29,43 @@ export const useTriggerActionMenuDropdown = ({ getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId); const recordIndexActionMenuDropdownPositionCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( recordIndexActionMenuDropdownPositionComponentState, actionMenuDropdownId, ); const { openDropdown } = useOpenDropdown(); - const { closeCommandMenu } = useCommandMenu(); + const store = useStore(); - const triggerActionMenuDropdown = useRecoilCallback( - ({ set, snapshot }) => - (event: React.MouseEvent, recordId: string) => { - event.preventDefault(); + const triggerActionMenuDropdown = useCallback( + (event: React.MouseEvent, recordId: string) => { + event.preventDefault(); - set(recordIndexActionMenuDropdownPositionCallbackState, { - x: event.pageX, - y: event.pageY, - }); + store.set(recordIndexActionMenuDropdownPositionCallbackState, { + x: event.pageX, + y: event.pageY, + }); - const isRowSelected = getSnapshotValue( - snapshot, - isRowSelectedFamilyState(recordId), - ); + const isRowSelected = store.get(isRowSelectedFamilyState(recordId)); - if (isRowSelected !== true) { - set(isRowSelectedFamilyState(recordId), true); - } + if (isRowSelected !== true) { + store.set(isRowSelectedFamilyState(recordId), true); + } - closeCommandMenu(); + closeCommandMenu(); - openDropdown({ - dropdownComponentInstanceIdFromProps: actionMenuDropdownId, - }); - }, + openDropdown({ + dropdownComponentInstanceIdFromProps: actionMenuDropdownId, + }); + }, [ recordIndexActionMenuDropdownPositionCallbackState, isRowSelectedFamilyState, closeCommandMenu, openDropdown, actionMenuDropdownId, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell.ts index ebf5ddfba8..bdb98e2063 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell.ts @@ -1,11 +1,12 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { getRecordTableCellFocusId } from '@/object-record/record-table/record-table-cell/utils/getRecordTableCellFocusId'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useStore } from 'jotai'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; import { useSetIsRecordTableCellFocusActive } from './useSetIsRecordTableCellFocusActive'; @@ -15,7 +16,8 @@ export const useUnfocusRecordTableCell = (recordTableId?: string) => { recordTableId, ); - const focusPositionState = useRecoilComponentCallbackState( + const store = useStore(); + const focusPositionAtom = useRecoilComponentStateCallbackStateV2( recordTableFocusPositionComponentState, recordTableIdFromProps, ); @@ -26,39 +28,36 @@ export const useUnfocusRecordTableCell = (recordTableId?: string) => { const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const unfocusRecordTableCell = useRecoilCallback( - ({ snapshot }) => { - return () => { - const currentPosition = snapshot - .getLoadable(focusPositionState) - .getValue(); + const unfocusRecordTableCell = useCallback(() => { + const currentPosition = store.get(focusPositionAtom) as + | { row: number; column: number } + | null + | undefined; - if (!isDefined(currentPosition)) { - return; - } + if (!isDefined(currentPosition)) { + return; + } - const currentCellFocusId = getRecordTableCellFocusId({ - recordTableId: recordTableIdFromProps, - cellPosition: currentPosition, - }); + const currentCellFocusId = getRecordTableCellFocusId({ + recordTableId: recordTableIdFromProps, + cellPosition: currentPosition, + }); - removeFocusItemFromFocusStackById({ - focusId: currentCellFocusId, - }); + removeFocusItemFromFocusStackById({ + focusId: currentCellFocusId, + }); - setIsRecordTableCellFocusActive({ - isRecordTableFocusActive: false, - cellPosition: currentPosition, - }); - }; - }, - [ - focusPositionState, - recordTableIdFromProps, - removeFocusItemFromFocusStackById, - setIsRecordTableCellFocusActive, - ], - ); + setIsRecordTableCellFocusActive({ + isRecordTableFocusActive: false, + cellPosition: currentPosition, + }); + }, [ + store, + focusPositionAtom, + recordTableIdFromProps, + removeFocusItemFromFocusStackById, + setIsRecordTableCellFocusActive, + ]); return { unfocusRecordTableCell }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx index 86db833b3f..b5bec75593 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell.tsx @@ -5,12 +5,12 @@ import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/rec import { RecordTableColumnAggregateFooterValue } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValue'; import { hasAggregateOperationForViewFieldFamilySelector } from '@/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useContext, useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { IconChevronDown } from 'twenty-ui/display'; const StyledCell = styled.div<{ isUnfolded: boolean; isFirstCell: boolean }>` @@ -68,13 +68,12 @@ export const RecordTableColumnAggregateFooterValueCell = ({ RecordTableColumnAggregateFooterCellContext, ); - const hasAggregateOperationForViewField = useRecoilValue( - hasAggregateOperationForViewFieldFamilySelector({ - viewFieldId, - }), + const hasAggregateOperationForViewField = useFamilySelectorValueV2( + hasAggregateOperationForViewFieldFamilySelector, + { viewFieldId }, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx index 019f41ffc1..c64d90cc6d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx @@ -14,10 +14,11 @@ import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/rec import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { UserContext } from '@/users/contexts/UserContext'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { FIELD_FOR_TOTAL_COUNT_AGGREGATE_OPERATION } from 'twenty-shared/constants'; import { computeRecordGqlOperationFilter, @@ -26,7 +27,7 @@ import { isFieldMetadataDateKind, turnAnyFieldFilterIntoRecordGqlFilter, } from 'twenty-shared/utils'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; export const useAggregateRecordsForRecordTableColumnFooter = ( aggregateFieldMetadataId: string, @@ -34,15 +35,15 @@ export const useAggregateRecordsForRecordTableColumnFooter = ( const { objectMetadataItem } = useRecordTableContextOrThrow(); const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const { filterValueDependencies } = useFilterValueDependencies(); @@ -65,7 +66,7 @@ export const useAggregateRecordsForRecordTableColumnFooter = ( // see problem with view id not being set early enoughby Effect component in context store, // This happens here when switching from a view to another. const aggregateOperationForViewFieldWithProbableImpossibleValues = - useRecoilValue(viewFieldAggregateOperationState({ viewFieldId })); + useFamilyRecoilValueV2(viewFieldAggregateOperationState, { viewFieldId }); const isAggregateOperationImpossibleForDateField = isDefined(fieldMetadataItem) && @@ -95,7 +96,7 @@ export const useAggregateRecordsForRecordTableColumnFooter = ( } : {}; - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation.tsx index 717ed5dd33..cb511b2ab7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation.tsx @@ -3,11 +3,11 @@ import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-record/utils/convertExtendedAggregateOperationToAggregateOperation'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { usePerformViewFieldAPIPersist } from '@/views/hooks/internal/usePerformViewFieldAPIPersist'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const useViewFieldAggregateOperation = () => { @@ -52,10 +52,9 @@ export const useViewFieldAggregateOperation = () => { refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); }; - const currentViewFieldAggregateOperation = useRecoilValue( - viewFieldAggregateOperationState({ - viewFieldId: currentViewField?.id ?? '', - }), + const currentViewFieldAggregateOperation = useFamilyRecoilValueV2( + viewFieldAggregateOperationState, + { viewFieldId: currentViewField?.id ?? '' }, ); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector.ts index c93655556b..8f9e165f55 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector.ts @@ -1,21 +1,17 @@ import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState'; -import { selectorFamily } from 'recoil'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; import { isDefined } from 'twenty-shared/utils'; -export const hasAggregateOperationForViewFieldFamilySelector = selectorFamily< - boolean, - { viewFieldId: string } ->({ - key: 'hasAggregateOperationForViewField', - get: - ({ viewFieldId }) => - ({ get }) => { - const aggregateOperation = get( - viewFieldAggregateOperationState({ +export const hasAggregateOperationForViewFieldFamilySelector = + createFamilySelectorV2({ + key: 'hasAggregateOperationForViewField', + get: + ({ viewFieldId }) => + ({ get }) => { + const aggregateOperation = get(viewFieldAggregateOperationState, { viewFieldId, - }), - ); + }); - return isDefined(aggregateOperation); - }, -}); + return isDefined(aggregateOperation); + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState.ts index 7139727865..91ec2dfa47 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState.ts @@ -1,7 +1,7 @@ import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const viewFieldAggregateOperationState = createFamilyState< +export const viewFieldAggregateOperationState = createFamilyStateV2< ExtendedAggregateOperations | null | undefined, { viewFieldId: string } >({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx index 193e71fcff..14df6cfb86 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx @@ -5,7 +5,7 @@ import { fieldMetadataItemByIdSelector } from '@/object-metadata/states/fieldMet import { isFieldMetadataItemLabelIdentifierSelector } from '@/object-metadata/states/isFieldMetadataItemLabelIdentifierSelector'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useIcons } from 'twenty-ui/display'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; @@ -69,7 +69,7 @@ export const RecordTableColumnHead = ({ { fieldMetadataItemId: recordField.fieldMetadataItemId }, ); - const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + const shouldCompactRecordTableFirstColumn = useRecoilComponentValueV2( shouldCompactRecordTableFirstColumnComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx index 1ab02e37de..8a67c55e6a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx @@ -13,8 +13,9 @@ import { isRecordTableRowFocusActiveComponentState } from '@/object-record/recor import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import { cx } from '@linaria/core'; import { IconPlus } from 'twenty-ui/display'; @@ -61,28 +62,28 @@ const StyledDropdownContainer = styled.div` export const RecordTableHeaderAddColumnButton = () => { const theme = useTheme(); - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx index d83a96cd7d..2314d0be86 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx @@ -11,8 +11,9 @@ import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/rec import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { cx } from '@linaria/core'; import { isDefined } from 'twenty-shared/utils'; @@ -27,32 +28,32 @@ export const RecordTableHeaderCell = ({ }: RecordTableHeaderCellProps) => { const { objectMetadataItem } = useRecordTableContextOrThrow(); - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); - const resizedFieldMetadataItemId = useRecoilComponentValue( + const resizedFieldMetadataItemId = useRecoilComponentValueV2( resizedFieldMetadataIdComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx index e633d428bf..5ca3ff81a0 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx @@ -15,8 +15,9 @@ import { isRecordTableRowFocusActiveComponentState } from '@/object-record/recor import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { cx } from '@linaria/core'; import { Checkbox } from 'twenty-ui/input'; @@ -48,7 +49,7 @@ const StyledColumnHeaderCell = styled.div` `; export const RecordTableHeaderCheckboxColumn = () => { - const allRowsSelectedStatus = useRecoilComponentValue( + const allRowsSelectedStatus = useRecoilComponentSelectorValueV2( allRowsSelectedStatusComponentSelector, ); @@ -62,12 +63,12 @@ export const RecordTableHeaderCheckboxColumn = () => { const { recordTableId } = useRecordTableContextOrThrow(); - const isRecordTableInitialLoading = useRecoilComponentValue( + const isRecordTableInitialLoading = useRecoilComponentValueV2( isRecordTableInitialLoadingComponentState, recordTableId, ); - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, recordTableId, ); @@ -83,28 +84,28 @@ export const RecordTableHeaderCheckboxColumn = () => { } }; - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx index 2c4a5578a8..f5c388c1ba 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn.tsx @@ -6,8 +6,9 @@ import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/reco import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { cx } from '@linaria/core'; import { useContext } from 'react'; @@ -35,20 +36,20 @@ const StyledDragDropHeaderCell = styled.div<{ export const RecordTableHeaderDragDropColumn = () => { const { theme } = useContext(ThemeContext); - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); @@ -56,7 +57,7 @@ export const RecordTableHeaderDragDropColumn = () => { const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstCell.tsx index 2c4cb6bdfe..b007c58977 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstCell.tsx @@ -16,8 +16,9 @@ import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/rec import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { cx } from '@linaria/core'; import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -35,34 +36,34 @@ export const RecordTableHeaderFirstCell = () => { const [iconIsVisible, setIconIsVisible] = useState(false); - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); const recordField = getVisibleFieldWithLowestPosition(visibleRecordFields); - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); - const resizedFieldMetadataItemId = useRecoilComponentValue( + const resizedFieldMetadataItemId = useRecoilComponentValueV2( resizedFieldMetadataIdComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx index 67e82ac8e1..9377f70a29 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx @@ -15,8 +15,9 @@ import { isRecordTableScrolledHorizontallyComponentState } from '@/object-record import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { cx } from '@linaria/core'; import { filterOutByProperty, isDefined } from 'twenty-shared/utils'; @@ -24,12 +25,12 @@ export const RecordTableHeaderFirstScrollableCell = () => { const { objectMetadataItem, visibleRecordFields } = useRecordTableContextOrThrow(); - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); @@ -43,22 +44,22 @@ export const RecordTableHeaderFirstScrollableCell = () => { ), )[0] as RecordField | undefined; - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const isRecordTableScrolledVertically = useRecoilComponentValue( + const isRecordTableScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isRecordTableScrolledHorizontally = useRecoilComponentValue( + const isRecordTableScrolledHorizontally = useRecoilComponentValueV2( isRecordTableScrolledHorizontallyComponentState, ); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); @@ -88,14 +89,14 @@ export const RecordTableHeaderFirstScrollableCell = () => { const zIndex = hasRecordGroups ? zIndexWithGroups : zIndexWithoutGroups; - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); const shouldDisplayBorderBottom = hasRecordGroups || !isFirstRowActiveOrFocused || isScrolledVertically; - const resizedFieldMetadataItemId = useRecoilComponentValue( + const resizedFieldMetadataItemId = useRecoilComponentValueV2( resizedFieldMetadataIdComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx index 5ae9473c98..36888b4518 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx @@ -2,7 +2,7 @@ import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObje import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import styled from '@emotion/styled'; import { IconPlus } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; @@ -33,7 +33,7 @@ export const RecordTableHeaderLabelIdentifierCellPlusButton = () => { objectMetadataItem, }); - const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + const hasAnySoftDeleteFilterOnView = useRecoilComponentSelectorValueV2( hasAnySoftDeleteFilterOnViewComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastEmptyColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastEmptyColumn.tsx index 28f9382806..ebd01b798f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastEmptyColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastEmptyColumn.tsx @@ -5,8 +5,9 @@ import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/reco import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { cx } from '@linaria/core'; @@ -29,28 +30,28 @@ const StyledLastColumnHeader = styled.div<{ `; export const RecordTableHeaderLastEmptyColumn = () => { - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); - const isFirstRowActive = useRecoilComponentFamilyValue( + const isFirstRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, 0, ); - const isFirstRowFocused = useRecoilComponentFamilyValue( + const isFirstRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, 0, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); const isFirstRowActiveOrFocused = isFirstRowActive || (isFirstRowFocused && isRowFocusActive); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx index b3e2d5ef1b..b89532bdf6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx @@ -2,7 +2,7 @@ import { type RecordField } from '@/object-record/record-field/types/RecordField import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import styled from '@emotion/styled'; import { useIsMobile } from 'twenty-ui/utilities'; @@ -54,7 +54,7 @@ export const RecordTableHeaderResizeHandler = ({ const columnResizeDisabled = isMobile; const [resizedFieldMetadataItemId, setResizedFieldMetadataItemId] = - useRecoilComponentState(resizedFieldMetadataIdComponentState); + useRecoilComponentStateV2(resizedFieldMetadataIdComponentState); const isResizing = recordField?.fieldMetadataItemId === resizedFieldMetadataItemId; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts index 1eac209e08..84b36578a0 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useOpenRecordFilterChipFromTableHeader.ts @@ -3,7 +3,7 @@ import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-re import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getEditableChipDropdownId } from '@/views/editable-chip/utils/getEditableChipDropdownId'; import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates'; import { isDefined } from 'twenty-shared/utils'; @@ -12,7 +12,7 @@ export const useOpenRecordFilterChipFromTableHeader = () => { const { filterableFieldMetadataItems } = useFilterableFieldMetadataItemsInRecordIndexContext(); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts index 9fbf61d0a1..6c0c1a9a6f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts @@ -16,14 +16,13 @@ import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer'; import { type PointerEventListener } from '@/ui/utilities/pointer-event/types/PointerEventListener'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useSaveRecordFields } from '@/views/hooks/useSaveRecordFields'; +import { useStore } from 'jotai'; import { useCallback, useState } from 'react'; -import { useRecoilCallback } from 'recoil'; import { findById, findByProperty, @@ -31,14 +30,16 @@ import { } from 'twenty-shared/utils'; export const useResizeTableHeader = () => { - const { visibleRecordFields } = useRecordTableContextOrThrow(); + const { recordTableId, visibleRecordFields } = useRecordTableContextOrThrow(); - const resizeFieldOffsetCallbackState = useRecoilComponentCallbackState( + const resizeFieldOffsetAtom = useRecoilComponentStateCallbackStateV2( resizeFieldOffsetComponentState, + recordTableId, ); - const setResizeFieldOffset = useSetRecoilComponentState( + const setResizeFieldOffset = useSetRecoilComponentStateV2( resizeFieldOffsetComponentState, + recordTableId, ); const [initialPointerPositionX, setInitialPointerPositionX] = useState< @@ -46,7 +47,7 @@ export const useResizeTableHeader = () => { >(null); const [resizedFieldMetadataItemId, setResizedFieldMetadataItemId] = - useRecoilComponentState(resizedFieldMetadataIdComponentState); + useRecoilComponentStateV2(resizedFieldMetadataIdComponentState); const recordField = visibleRecordFields.find( findByProperty('fieldMetadataItemId', resizedFieldMetadataItemId), @@ -58,12 +59,14 @@ export const useResizeTableHeader = () => { const { updateRecordField } = useUpdateRecordField(); - const recordTableWidth = useRecoilComponentValue( + const recordTableWidth = useRecoilComponentValueV2( recordTableWidthComponentState, + recordTableId, ); - const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + const shouldCompactRecordTableFirstColumn = useRecoilComponentValueV2( shouldCompactRecordTableFirstColumnComponentState, + recordTableId, ); const handleResizeHandlerStart = useCallback( @@ -136,52 +139,45 @@ export const useResizeTableHeader = () => { const { setDragSelectionStartEnabled } = useDragSelect(); - const handleResizeHandlerEnd = useRecoilCallback( - ({ snapshot, set }) => - async () => { - throwIfNotDefined(recordField, 'recordField'); + const store = useStore(); - if (!resizedFieldMetadataItemId) return; + const handleResizeHandlerEnd = useCallback(async () => { + throwIfNotDefined(recordField, 'recordField'); - const resizeFieldOffset = getSnapshotValue( - snapshot, - resizeFieldOffsetCallbackState, - ); + if (!resizedFieldMetadataItemId) return; - const nextWidth = Math.round( - Math.max( - recordField.size + resizeFieldOffset, - RECORD_TABLE_COLUMN_MIN_WIDTH, - ), - ); + const resizeFieldOffset = store.get(resizeFieldOffsetAtom); - set(resizeFieldOffsetCallbackState, 0); - setInitialPointerPositionX(null); - setResizedFieldMetadataItemId(null); + const nextWidth = Math.round( + Math.max( + recordField.size + resizeFieldOffset, + RECORD_TABLE_COLUMN_MIN_WIDTH, + ), + ); - if (nextWidth !== recordField.size) { - const updatedRecordField = updateRecordField( - resizedFieldMetadataItemId, - { - size: nextWidth, - }, - ); + store.set(resizeFieldOffsetAtom, 0); + setInitialPointerPositionX(null); + setResizedFieldMetadataItemId(null); - saveRecordFields([updatedRecordField]); - } + if (nextWidth !== recordField.size) { + const updatedRecordField = updateRecordField(resizedFieldMetadataItemId, { + size: nextWidth, + }); - setDragSelectionStartEnabled(true); - }, - [ - saveRecordFields, - resizedFieldMetadataItemId, - resizeFieldOffsetCallbackState, - setResizedFieldMetadataItemId, - updateRecordField, - setDragSelectionStartEnabled, - recordField, - ], - ); + saveRecordFields([updatedRecordField]); + } + + setDragSelectionStartEnabled(true); + }, [ + saveRecordFields, + resizedFieldMetadataItemId, + resizeFieldOffsetAtom, + store, + setResizedFieldMetadataItemId, + updateRecordField, + setDragSelectionStartEnabled, + recordField, + ]); useTrackPointer({ shouldTrackPointer: resizedFieldMetadataItemId !== null, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTrFirstRowOfGroup.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTrFirstRowOfGroup.tsx index f103d38901..0c5d1cfcec 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTrFirstRowOfGroup.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTrFirstRowOfGroup.tsx @@ -8,7 +8,7 @@ import { RecordTableTr } from '@/object-record/record-table/record-table-row/com import { useIsTableRowSecondaryDragged } from '@/object-record/record-table/record-table-row/hooks/useIsRecordSecondaryDragged'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; type RecordTableDraggableTrFirstRowOfGroupProps = { className?: string; @@ -33,7 +33,7 @@ export const RecordTableDraggableTrFirstRowOfGroup = ({ const { isSecondaryDragged } = useIsTableRowSecondaryDragged(recordId); - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFieldsCells.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFieldsCells.tsx index 5f2af780b0..521716dfed 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFieldsCells.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFieldsCells.tsx @@ -7,7 +7,7 @@ import { RecordTableCellFirstRowFirstColumn } from '@/object-record/record-table import { RecordTableCellStyleWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellStyleWrapper'; import { RecordTableCellWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellWrapper'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { isDefined, isNonEmptyArray } from 'twenty-shared/utils'; export const RecordTableFieldsCells = () => { @@ -17,7 +17,7 @@ export const RecordTableFieldsCells = () => { const { visibleRecordFields } = useRecordTableContextOrThrow(); - const hasRecordGroups = useRecoilComponentValue( + const hasRecordGroups = useRecoilComponentSelectorValueV2( hasRecordGroupsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFirstRowOfGroup.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFirstRowOfGroup.tsx index 37abc2ed05..4e443b1784 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFirstRowOfGroup.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableFirstRowOfGroup.tsx @@ -1,6 +1,6 @@ import { RecordTableRowDiv } from '@/object-record/record-table/record-table-row/components/RecordTableRowDiv'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isActive } from '@tiptap/core'; import { forwardRef, type ReactNode } from 'react'; @@ -33,7 +33,7 @@ export const RecordTableFirstRowOfGroup = forwardRef< }, ref, ) => { - const isScrolledVertically = useRecoilComponentValue( + const isScrolledVertically = useRecoilComponentValueV2( isRecordTableScrolledVerticallyComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx index 6ead1db831..9c778a4c33 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx @@ -8,10 +8,11 @@ import { RecordTableDraggableTrFirstRowOfGroup } from '@/object-record/record-ta import { RecordTableFieldsCells } from '@/object-record/record-table/record-table-row/components/RecordTableFieldsCells'; import { RecordTableRowArrowKeysEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowArrowKeysEffect'; import { RecordTableRowHotkeyEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowHotkeyEffect'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; type RecordTableRowProps = { recordId: string; @@ -26,12 +27,15 @@ export const RecordTableRow = ({ rowIndexForDrag, isFirstRowOfGroup, }: RecordTableRowProps) => { - const isFocused = useRecoilComponentFamilyValue( + const { recordTableId } = useRecordTableContextOrThrow(); + + const isFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, rowIndexForFocus, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, + recordTableId, ); return isFirstRowOfGroup ? ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragCounterChip.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragCounterChip.tsx index 544964e854..844f688aa2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragCounterChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragCounterChip.tsx @@ -1,5 +1,5 @@ import { originalDragSelectionComponentState } from '@/object-record/record-drag/states/originalDragSelectionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { NotificationCounter } from 'twenty-ui/navigation'; @@ -11,7 +11,7 @@ const StyledNotificationCounter = styled(NotificationCounter)` `; export const RecordTableRowMultiDragCounterChip = () => { - const originalDragSelection = useRecoilComponentValue( + const originalDragSelection = useRecoilComponentValueV2( originalDragSelectionComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragPreview.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragPreview.tsx index db6e097737..80cab7c066 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragPreview.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowMultiDragPreview.tsx @@ -1,12 +1,12 @@ import { isRecordIdPrimaryDragMultipleComponentFamilyState } from '@/object-record/record-drag/states/isRecordIdPrimaryDragMultipleComponentFamilyState'; import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableRowMultiDragCounterChip } from '@/object-record/record-table/record-table-row/components/RecordTableRowMultiDragCounterChip'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; export const RecordTableRowMultiDragPreview = () => { const { recordId } = useRecordTableRowContextOrThrow(); - const isRecordIdPrimaryDragMultiple = useRecoilComponentFamilyValue( + const isRecordIdPrimaryDragMultiple = useRecoilComponentFamilyValueV2( isRecordIdPrimaryDragMultipleComponentFamilyState, { recordId }, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx index 08d4532ad3..2b2cb70f41 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx @@ -11,8 +11,9 @@ import { isRecordTableRowFocusActiveComponentState } from '@/object-record/recor import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { forwardRef, type ReactNode } from 'react'; type RecordTableTrProps = { @@ -40,41 +41,41 @@ export const RecordTableTr = forwardRef( ) => { const { objectMetadataItem } = useRecordTableContextOrThrow(); - const currentRowSelected = useRecoilComponentFamilyValue( + const currentRowSelected = useRecoilComponentFamilyValueV2( isRowSelectedComponentFamilyState, recordId, ); - const isActive = useRecoilComponentFamilyValue( + const isActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, focusIndex, ); - const isNextRowActive = useRecoilComponentFamilyValue( + const isNextRowActive = useRecoilComponentFamilyValueV2( isRecordTableRowActiveComponentFamilyState, focusIndex + 1, ); - const nextRecordId = useRecoilComponentFamilyValue( + const nextRecordId = useRecoilComponentFamilySelectorValueV2( recordIdByRealIndexComponentFamilySelector, focusIndex + 1, ); - const isNextRecordIdFirstOfGroup = useRecoilComponentFamilyValue( + const isNextRecordIdFirstOfGroup = useRecoilComponentFamilySelectorValueV2( isRecordIdFirstOfGroupComponentFamilySelector, - nextRecordId, + nextRecordId ?? '', ); - const isFocused = useRecoilComponentFamilyValue( + const isFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, focusIndex, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, ); - const isNextRowFocused = useRecoilComponentFamilyValue( + const isNextRowFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, focusIndex + 1, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useIsRecordSecondaryDragged.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useIsRecordSecondaryDragged.ts index 733b23e6f3..a9b2e352be 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useIsRecordSecondaryDragged.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useIsRecordSecondaryDragged.ts @@ -1,9 +1,9 @@ import { isRecordIdSecondaryDragMultipleComponentFamilyState } from '@/object-record/record-drag/states/isRecordIdSecondaryDragMultipleComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { type Nullable } from 'twenty-shared/types'; export const useIsTableRowSecondaryDragged = (recordId: Nullable) => { - const isSecondaryDragged = useRecoilComponentFamilyValue( + const isSecondaryDragged = useRecoilComponentFamilyValueV2( isRecordIdSecondaryDragMultipleComponentFamilyState, { recordId: recordId ?? '' }, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useRecordTableRowHotkeys.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useRecordTableRowHotkeys.ts index a5a3e252b9..484417f8f9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useRecordTableRowHotkeys.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useRecordTableRowHotkeys.ts @@ -13,8 +13,8 @@ import { isRecordTableRowFocusActiveComponentState } from '@/object-record/recor import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { Key } from 'ts-key-enum'; export const useRecordTableRowHotkeys = (focusId: string) => { @@ -27,7 +27,7 @@ export const useRecordTableRowHotkeys = (focusId: string) => { const { activateRecordTableRow } = useActiveRecordTableRow(); - const setIsRowFocusActive = useSetRecoilComponentState( + const setIsRowFocusActive = useSetRecoilComponentStateV2( isRecordTableRowFocusActiveComponentState, ); @@ -86,8 +86,9 @@ export const useRecordTableRowHotkeys = (focusId: string) => { const { unfocusRecordTableRow } = useFocusedRecordTableRow(recordTableId); - const isAtLeastOneRecordSelected = useRecoilComponentValue( + const isAtLeastOneRecordSelected = useRecoilComponentSelectorValueV2( isAtLeastOneTableRowSelectedSelector, + recordTableId, ); const handleEscape = () => { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts index f53f60b7b7..fea9d6c68f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts @@ -1,78 +1,79 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { lastSelectedRowIndexComponentState } from '@/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useSetCurrentRowSelected = () => { const { recordId, rowIndex } = useRecordTableRowContextOrThrow(); - const isRowSelectedFamilyState = useRecoilComponentCallbackState( + + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( isRowSelectedComponentFamilyState, ); - const recordIndexAllRecordIdsState = useRecoilComponentCallbackState( + const recordIndexAllRecordIdsAtom = useRecoilComponentSelectorCallbackStateV2( recordIndexAllRecordIdsComponentSelector, ); const lastSelectedRowIndexComponentCallbackState = - useRecoilComponentCallbackState(lastSelectedRowIndexComponentState); + useRecoilComponentStateCallbackStateV2(lastSelectedRowIndexComponentState); - const setCurrentRowSelected = useRecoilCallback( - ({ set, snapshot }) => - ({ - newSelectedState, - shouldSelectRange = false, - }: { - newSelectedState: boolean; - shouldSelectRange?: boolean; - }) => { - const allRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsState, - ); + const store = useStore(); - const isCurrentRowSelected = getSnapshotValue( - snapshot, - isRowSelectedFamilyState(recordId), - ); + const setCurrentRowSelected = useCallback( + ({ + newSelectedState, + shouldSelectRange = false, + }: { + newSelectedState: boolean; + shouldSelectRange?: boolean; + }) => { + const allRecordIds = store.get(recordIndexAllRecordIdsAtom); - const lastSelectedIndex = snapshot - .getLoadable(lastSelectedRowIndexComponentCallbackState) - .getValue(); + const isCurrentRowSelected = store.get( + isRowSelectedFamilyState(recordId), + ); - if (shouldSelectRange && isDefined(lastSelectedIndex)) { - const startIndex = Math.min(lastSelectedIndex, rowIndex); - const endIndex = Math.max(lastSelectedIndex, rowIndex); + const lastSelectedIndex = store.get( + lastSelectedRowIndexComponentCallbackState, + ); - const shouldSelect = !isCurrentRowSelected; + if (shouldSelectRange && isDefined(lastSelectedIndex)) { + const startIndex = Math.min(lastSelectedIndex, rowIndex); + const endIndex = Math.max(lastSelectedIndex, rowIndex); - for (let i = startIndex; i <= endIndex; i++) { - set(isRowSelectedFamilyState(allRecordIds[i]), shouldSelect); - } + const shouldSelect = !isCurrentRowSelected; - set(lastSelectedRowIndexComponentCallbackState, rowIndex); - return; + for (let i = startIndex; i <= endIndex; i++) { + store.set(isRowSelectedFamilyState(allRecordIds[i]), shouldSelect); } - if (isCurrentRowSelected !== newSelectedState) { - set(isRowSelectedFamilyState(recordId), newSelectedState); + store.set(lastSelectedRowIndexComponentCallbackState, rowIndex); + return; + } - set( - lastSelectedRowIndexComponentCallbackState, - newSelectedState ? rowIndex : null, - ); - } - }, + if (isCurrentRowSelected !== newSelectedState) { + store.set(isRowSelectedFamilyState(recordId), newSelectedState); + + store.set( + lastSelectedRowIndexComponentCallbackState, + newSelectedState ? rowIndex : null, + ); + } + }, [ - recordIndexAllRecordIdsState, + recordIndexAllRecordIdsAtom, isRowSelectedFamilyState, recordId, lastSelectedRowIndexComponentCallbackState, rowIndex, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState.ts index 288493f2df..807912a443 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const hasUserSelectedAllRowsComponentState = - createComponentState({ + createComponentStateV2({ key: 'hasUserSelectedAllRowsFamilyState', defaultValue: false, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector.ts index b80808cc6d..351421bb49 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector.ts @@ -1,28 +1,24 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const isAtLeastOneTableRowSelectedSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'isAtLeastOneTableRowSelectedSelector', componentInstanceContext: RecordTableComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); - const isAnyRecordSelected = allRecordIds.some((recordId) => - get( - isRowSelectedComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordId, - }), - ), + const isAnyRecordSelected = allRecordIds.some((recordId: string) => + get(isRowSelectedComponentFamilyState, { + instanceId, + familyKey: recordId, + }), ); return isAnyRecordSelected; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRecordIdFirstOfGroupComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRecordIdFirstOfGroupComponentFamilySelector.ts index e6d68526b6..8552f99117 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRecordIdFirstOfGroupComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRecordIdFirstOfGroupComponentFamilySelector.ts @@ -1,23 +1,20 @@ import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; -import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; +import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -import { type Nullable } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const isRecordIdFirstOfGroupComponentFamilySelector = - createComponentFamilySelector>({ + createComponentFamilySelectorV2({ key: 'isRecordIdFirstOfGroupComponentFamilySelector', componentInstanceContext: ViewComponentInstanceContext, get: - ({ familyKey, instanceId }) => + ({ instanceId, familyKey }) => ({ get }) => { - const recordGroupIds = get( - recordGroupIdsComponentState.atomFamily({ - instanceId, - }), - ); + const recordGroupIds = get(recordGroupIdsComponentState, { + instanceId, + }); const hasRecordGroups = recordGroupIds.length > 0; @@ -25,27 +22,25 @@ export const isRecordIdFirstOfGroupComponentFamilySelector = return false; } + const recordIdToCheck = familyKey; + if (hasRecordGroups) { for (const recordGroupId of recordGroupIds) { const recordIdsForThisGroup = get( - recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordGroupId, - }), + recordIndexRecordIdsByGroupComponentFamilyState, + { instanceId, familyKey: recordGroupId }, ); - if (recordIdsForThisGroup[0] === familyKey) { + if (recordIdsForThisGroup[0] === recordIdToCheck) { return true; } } } else { - const allRecordIds = get( - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); - if (allRecordIds[0] === familyKey) { + if (allRecordIds[0] === recordIdToCheck) { return true; } } diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState.ts index 67f387c5e5..eb67af95bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState.ts @@ -1,7 +1,7 @@ +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; -export const isRowSelectedComponentFamilyState = createComponentFamilyState< +export const isRowSelectedComponentFamilyState = createComponentFamilyStateV2< boolean, string >({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState.ts index a9cb253418..f38282725f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const lastSelectedRowIndexComponentState = createComponentState< +export const lastSelectedRowIndexComponentState = createComponentStateV2< number | null | undefined >({ key: 'record-table/last-selected-row-index', diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection.tsx index 2ec08785a8..961a097374 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection.tsx @@ -23,10 +23,11 @@ import { RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE } from '@/object-r import { recordIndexAggregateDisplayLabelComponentState } from '@/object-record/record-index/states/recordIndexAggregateDisplayLabelComponentState'; import { recordIndexAggregateDisplayValueForGroupValueComponentFamilyState } from '@/object-record/record-index/states/recordIndexAggregateDisplayValueForGroupValueComponentFamilyState'; import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilValue } from 'recoil'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { filterOutByProperty, findByProperty, @@ -122,23 +123,24 @@ export const RecordTableRecordGroupSection = () => { const { objectMetadataItem } = useRecordTableContextOrThrow(); - const recordGroup = useRecoilValue( - recordGroupDefinitionFamilyState(currentRecordGroupId), + const recordGroup = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + currentRecordGroupId, ); const recordIndexAggregateDisplayValueForGroupValue = - useRecoilComponentFamilyValue( + useRecoilComponentFamilyValueV2( recordIndexAggregateDisplayValueForGroupValueComponentFamilyState, { groupValue: recordGroup?.value ?? '' }, ); - const recordIndexAggregateDisplayLabel = useRecoilComponentValue( + const recordIndexAggregateDisplayLabel = useRecoilComponentValueV2( recordIndexAggregateDisplayLabelComponentState, ); const { labelIdentifierFieldMetadataItem } = useRecordIndexContextOrThrow(); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); @@ -156,7 +158,7 @@ export const RecordTableRecordGroupSection = () => { const [ isRecordGroupTableSectionToggled, setIsRecordGroupTableSectionToggled, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( isRecordGroupTableSectionToggledComponentState, currentRecordGroupId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx index 48d6147877..15be7b5859 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx @@ -5,9 +5,9 @@ import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { IconPlus } from 'twenty-ui/display'; export const RecordTableRecordGroupSectionAddNew = () => { @@ -15,11 +15,12 @@ export const RecordTableRecordGroupSectionAddNew = () => { const currentRecordGroupId = useCurrentRecordGroupId(); - const recordGroup = useRecoilValue( - recordGroupDefinitionFamilyState(currentRecordGroupId), + const recordGroup = useFamilyRecoilValueV2( + recordGroupDefinitionFamilyState, + currentRecordGroupId, ); - const mainGroupByFieldMetadata = useRecoilComponentValue( + const mainGroupByFieldMetadata = useRecoilComponentValueV2( recordIndexGroupFieldMetadataItemComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx index 57947656e8..9b32a46d2c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx @@ -3,7 +3,7 @@ import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { t } from '@lingui/core/macro'; import { IconArrowDown } from 'twenty-ui/display'; @@ -15,7 +15,7 @@ export const RecordTableRecordGroupSectionLoadMore = () => { const { fetchMoreRecordsLazy } = useRecordIndexTableFetchMore(objectNameSingular); - const hasFetchedAllRecords = useRecoilComponentFamilyValue( + const hasFetchedAllRecords = useRecoilComponentFamilyValueV2( recordIndexHasFetchedAllRecordsByGroupComponentState, currentRecordGroupId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState.ts index f034092be8..1d6d4ec384 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState.ts @@ -1,9 +1,9 @@ import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const isRecordGroupTableSectionToggledComponentState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordGroupTableSectionToggledComponentState', defaultValue: true, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/activeRecordTableRowIndexComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/activeRecordTableRowIndexComponentState.ts index 701282b052..45f61f0b74 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/activeRecordTableRowIndexComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/activeRecordTableRowIndexComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const activeRecordTableRowIndexComponentState = createComponentState< +export const activeRecordTableRowIndexComponentState = createComponentStateV2< number | null >({ key: 'activeRecordTableRowIndexComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/focusedRecordTableRowIndexComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/focusedRecordTableRowIndexComponentState.ts index b849dce7f9..ac6ed6d88a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/focusedRecordTableRowIndexComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/focusedRecordTableRowIndexComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const focusedRecordTableRowIndexComponentState = createComponentState< +export const focusedRecordTableRowIndexComponentState = createComponentStateV2< number | null >({ key: 'focusedRecordTableRowIndexComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableCellFocusActiveComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableCellFocusActiveComponentState.ts index 4c8a7cff8d..70a521fa5d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableCellFocusActiveComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableCellFocusActiveComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordTableCellFocusActiveComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordTableCellFocusActiveComponentState', defaultValue: false, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableInitialLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableInitialLoadingComponentState.ts index b4ab3fd5f6..079be9a623 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableInitialLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableInitialLoadingComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordTableInitialLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordTableInitialLoadingComponentState', defaultValue: true, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState.ts index d84dc0988e..a34384ae2e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const isRecordTableRowActiveComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordTableRowActiveComponentFamilyState', defaultValue: false, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusActiveComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusActiveComponentState.ts index 62194b392e..4f4d82329b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusActiveComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusActiveComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordTableRowFocusActiveComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordTableRowFocusActiveComponentState', defaultValue: false, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState.ts index c810623248..1b57f575b2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const isRecordTableRowFocusedComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'isRecordTableRowFocusedComponentFamilyState', defaultValue: false, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState.ts index 105faa4151..6b3de5ecf8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordTableScrolledHorizontallyComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordTableScrolledHorizontallyComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: false, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState.ts index 683116ac4c..fa3b0682d5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isRecordTableScrolledVerticallyComponentState = - createComponentState({ + createComponentStateV2({ key: 'isRecordTableScrolledVerticallyComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: false, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isSoftDeleteFilterActiveComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isSoftDeleteFilterActiveComponentState.ts index 7a538ac7b5..0889083cd3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isSoftDeleteFilterActiveComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/isSoftDeleteFilterActiveComponentState.ts @@ -1,8 +1,8 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isSoftDeleteFilterActiveComponentState = - createComponentState({ + createComponentStateV2({ key: 'isSoftDeleteFilterActiveComponentState', defaultValue: false, componentInstanceContext: RecordFiltersComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/numberOfTableRowsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/numberOfTableRowsComponentState.ts index 7bfbc4c4ca..e0cb274347 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/numberOfTableRowsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/numberOfTableRowsComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const numberOfTableRowsComponentState = createComponentState({ +export const numberOfTableRowsComponentState = createComponentStateV2({ key: 'numberOfTableRowsComponentState', defaultValue: 0, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableCellEditModePositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableCellEditModePositionComponentState.ts index 7d477bfe24..8267e8d606 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableCellEditModePositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableCellEditModePositionComponentState.ts @@ -1,9 +1,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordTableCellEditModePositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordTableCellEditModePositionComponentState', defaultValue: null, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableFocusPositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableFocusPositionComponentState.ts index 444b192b0f..036f04d9c3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableFocusPositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableFocusPositionComponentState.ts @@ -1,9 +1,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordTableFocusPositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordTableFocusPositionComponentState', defaultValue: null, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableHoverPositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableHoverPositionComponentState.ts index af536a1744..c14935c1b7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableHoverPositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableHoverPositionComponentState.ts @@ -1,9 +1,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; import { type TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const recordTableHoverPositionComponentState = - createComponentState({ + createComponentStateV2({ key: 'recordTableHoverPositionComponentState', defaultValue: null, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableWidthComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableWidthComponentState.ts index 7321d456e3..d200eb6cb2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/recordTableWidthComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/recordTableWidthComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const recordTableWidthComponentState = createComponentState({ +export const recordTableWidthComponentState = createComponentStateV2({ key: 'recordTableWidthComponentState', defaultValue: 0, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/resizeFieldOffsetComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/resizeFieldOffsetComponentState.ts index e71629cbfc..efaf9ac1cd 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/resizeFieldOffsetComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/resizeFieldOffsetComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const resizeFieldOffsetComponentState = createComponentState({ +export const resizeFieldOffsetComponentState = createComponentStateV2({ key: 'resizeFieldOffsetComponentState', defaultValue: 0, componentInstanceContext: RecordTableComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/resizedFieldMetadataIdComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/resizedFieldMetadataIdComponentState.ts index 7ace7819d5..1e70922050 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/resizedFieldMetadataIdComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/resizedFieldMetadataIdComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type Nullable } from 'twenty-shared/types'; -export const resizedFieldMetadataIdComponentState = createComponentState< +export const resizedFieldMetadataIdComponentState = createComponentStateV2< Nullable >({ key: 'resizedFieldMetadataIdComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts index fcf94c6721..617993e546 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector.ts @@ -1,29 +1,23 @@ -import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; - import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { type AllRowsSelectedStatus } from '@/object-record/record-table/types/AllRowSelectedStatus'; export const allRowsSelectedStatusComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'allRowsSelectedStatusComponentSelector', componentInstanceContext: RecordTableComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - // TODO: Working because instanceId is the same, but we're not in the same context, should be changed ! - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); - const selectedRowIds = get( - selectedRowIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const selectedRowIds = get(selectedRowIdsComponentSelector, { + instanceId, + }); const numberOfSelectedRows = selectedRowIds.length; diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isAtLeastOneTableRowSelectedSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isAtLeastOneTableRowSelectedSelector.ts new file mode 100644 index 0000000000..4fe33ea12e --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isAtLeastOneTableRowSelectedSelector.ts @@ -0,0 +1,26 @@ +import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; +import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; + +export const isAtLeastOneTableRowSelectedSelector = + createComponentSelectorV2({ + key: 'isAtLeastOneTableRowSelectedSelector', + componentInstanceContext: RecordTableComponentInstanceContext, + get: + ({ instanceId }) => + ({ get }) => { + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); + + const isAnyRecordSelected = allRecordIds.some((recordId) => + get(isRowSelectedComponentFamilyState, { + instanceId, + familyKey: recordId, + }), + ); + + return isAnyRecordSelected; + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector.ts index 450f4855b0..ca1c91d346 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector.ts @@ -1,20 +1,20 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { recordTableCellEditModePositionComponentState } from '@/object-record/record-table/states/recordTableCellEditModePositionComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { isDefined } from 'twenty-shared/utils'; -export const isSomeCellInEditModeComponentSelector = createComponentSelector({ - key: 'isSomeCellInEditModeComponentSelector', - componentInstanceContext: RecordTableComponentInstanceContext, - get: - ({ instanceId }) => - ({ get }) => { - const currentTableCellInEditModePosition = get( - recordTableCellEditModePositionComponentState.atomFamily({ - instanceId, - }), - ); +export const isSomeCellInEditModeComponentSelector = + createComponentSelectorV2({ + key: 'isSomeCellInEditModeComponentSelector', + componentInstanceContext: RecordTableComponentInstanceContext, + get: + ({ instanceId }) => + ({ get }) => { + const currentTableCellInEditModePosition = get( + recordTableCellEditModePositionComponentState, + { instanceId }, + ); - return isDefined(currentTableCellInEditModePosition); - }, -}); + return isDefined(currentTableCellInEditModePosition); + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/selectedRowIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/selectedRowIdsComponentSelector.ts index aaccc71392..4b9ce486a5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/selectedRowIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/selectedRowIdsComponentSelector.ts @@ -1,9 +1,9 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; -export const selectedRowIdsComponentSelector = createComponentSelector< +export const selectedRowIdsComponentSelector = createComponentSelectorV2< string[] >({ key: 'selectedRowIdsComponentSelector', @@ -11,21 +11,16 @@ export const selectedRowIdsComponentSelector = createComponentSelector< get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - // TODO: Working because instanceId is the same, but we're not in the same context, should be changed ! - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); return allRecordIds.filter( (recordId) => - get( - isRowSelectedComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordId, - }), - ) === true, + get(isRowSelectedComponentFamilyState, { + instanceId, + familyKey: recordId, + }) === true, ); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts index f24161a6bc..ae9e35917b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector.ts @@ -1,9 +1,9 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; -export const unselectedRowIdsComponentSelector = createComponentSelector< +export const unselectedRowIdsComponentSelector = createComponentSelectorV2< string[] >({ key: 'unselectedRowIdsComponentSelector', @@ -11,21 +11,16 @@ export const unselectedRowIdsComponentSelector = createComponentSelector< get: ({ instanceId }) => ({ get }) => { - const allRecordIds = get( - // TODO: Working because instanceId is the same, but we're not in the same context, should be changed ! - recordIndexAllRecordIdsComponentSelector.selectorFamily({ - instanceId, - }), - ); + const allRecordIds = get(recordIndexAllRecordIdsComponentSelector, { + instanceId, + }); return allRecordIds.filter( (recordId) => - get( - isRowSelectedComponentFamilyState.atomFamily({ - instanceId, - familyKey: recordId, - }), - ) === false, + get(isRowSelectedComponentFamilyState, { + instanceId, + familyKey: recordId, + }) === false, ); }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts index 8d22de113c..427bfb307a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts @@ -1,9 +1,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const shouldCompactRecordTableFirstColumnComponentState = - createComponentState({ + createComponentStateV2({ key: 'shouldCompactRecordTableFirstColumnComponentState', - componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: false, + componentInstanceContext: RecordTableComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/tableWidthResizeIsActivedState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/tableWidthResizeIsActivedState.ts index 9eb6a25fc9..f7f7274aad 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/states/tableWidthResizeIsActivedState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/states/tableWidthResizeIsActivedState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const tableWidthResizeIsActiveState = createState({ +export const tableWidthResizeIsActiveState = createStateV2({ key: 'tableWidthResizeIsActiveState', defaultValue: true, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableNoRecordGroupScrollToPreviousRecordEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableNoRecordGroupScrollToPreviousRecordEffect.tsx index b7742c694a..c86b63c181 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableNoRecordGroupScrollToPreviousRecordEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableNoRecordGroupScrollToPreviousRecordEffect.tsx @@ -6,19 +6,19 @@ import { useProcessTreadmillScrollTop } from '@/object-record/record-table/virtu import { useTriggerFetchPages } from '@/object-record/record-table/virtualization/hooks/useTriggerFetchPages'; import { useTriggerInitialRecordTableDataLoad } from '@/object-record/record-table/virtualization/hooks/useTriggerInitialRecordTableDataLoad'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { isNonEmptyString } from '@sniptt/guards'; import { useEffect, useState } from 'react'; -import { useRecoilState } from 'recoil'; export const RecordTableNoRecordGroupScrollToPreviousRecordEffect = () => { const { getScrollWrapperElement } = useScrollWrapperHTMLElement(); - const allRecordIds = useRecoilComponentValue( + const allRecordIds = useRecoilComponentSelectorValueV2( recordIndexAllRecordIdsComponentSelector, ); - const [lastShowPageRecordId, setLastShowPageRecordId] = useRecoilState( + const [lastShowPageRecordId, setLastShowPageRecordId] = useRecoilStateV2( lastShowPageRecordIdState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedContainer.tsx index 7a2f1ca70b..7b72312fd9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedContainer.tsx @@ -6,8 +6,8 @@ import { TABLE_VIRTUALIZATION_DEBUG_ACTIVATED } from '@/object-record/record-tab import { realIndexByVirtualIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; @@ -26,13 +26,13 @@ type RecordTableRowVirtualizedContainerProps = { export const RecordTableRowVirtualizedContainer = ({ virtualIndex, }: RecordTableRowVirtualizedContainerProps) => { - const realIndex = useRecoilComponentFamilyValue( + const realIndex = useRecoilComponentFamilyValueV2( realIndexByVirtualIndexComponentFamilyState, { virtualIndex }, ); const totalNumberOfRecordsToVirtualize = - useRecoilComponentValue(totalNumberOfRecordsToVirtualizeComponentState) ?? + useRecoilComponentValueV2(totalNumberOfRecordsToVirtualizeComponentState) ?? 0; if (!isDefined(realIndex) || realIndex >= totalNumberOfRecordsToVirtualize) { diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedDebugRowHelper.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedDebugRowHelper.tsx index 4ed35cdff2..be1f7f1bf8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedDebugRowHelper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedDebugRowHelper.tsx @@ -1,15 +1,16 @@ import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { dataLoadingStatusByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector'; import { realIndexByVirtualIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState'; import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; const StyledDebugRow = styled.div` @@ -45,17 +46,17 @@ type RecordTableRowVirtualizedDebugRowHelperProps = { export const RecordTableRowVirtualizedDebugRowHelper = ({ virtualIndex, }: RecordTableRowVirtualizedDebugRowHelperProps) => { - const realIndex = useRecoilComponentFamilyValue( + const realIndex = useRecoilComponentFamilyValueV2( realIndexByVirtualIndexComponentFamilyState, { virtualIndex }, ); - const recordId = useRecoilComponentFamilyValue( + const recordId = useRecoilComponentFamilySelectorValueV2( recordIdByRealIndexComponentFamilySelector, realIndex, ); - const dataLoadingStatus = useRecoilComponentFamilyValue( + const dataLoadingStatus = useRecoilComponentFamilySelectorValueV2( dataLoadingStatusByRealIndexComponentFamilySelector, realIndex, ); @@ -64,7 +65,7 @@ export const RecordTableRowVirtualizedDebugRowHelper = ({ (realIndex ?? 0) * (RECORD_TABLE_ROW_HEIGHT + 1) + (RECORD_TABLE_ROW_HEIGHT + 1); - const record = useRecoilValue(recordStoreFamilyState(recordId ?? '')); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, recordId ?? ''); const { objectMetadataItem } = useRecordTableContextOrThrow(); const labelIdentifierFieldMetadataItem = getLabelIdentifierFieldMetadataItem(objectMetadataItem); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedFullData.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedFullData.tsx index e7a13c9094..11486e5292 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedFullData.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedFullData.tsx @@ -6,13 +6,15 @@ import { RecordTableDraggableTr } from '@/object-record/record-table/record-tabl import { RecordTableFieldsCells } from '@/object-record/record-table/record-table-row/components/RecordTableFieldsCells'; import { RecordTableRowArrowKeysEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowArrowKeysEffect'; import { RecordTableRowHotkeyEffect } from '@/object-record/record-table/record-table-row/components/RecordTableRowHotkeyEffect'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { RecordTableRowVirtualizedSkeleton } from '@/object-record/record-table/virtualization/components/RecordTableRowVirtualizedSkeleton'; import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; type RecordTableRowVirtualizedFullDataProps = { @@ -23,16 +25,19 @@ type RecordTableRowVirtualizedFullDataProps = { export const RecordTableRowVirtualizedFullData = ({ realIndex, }: RecordTableRowVirtualizedFullDataProps) => { - const isFocused = useRecoilComponentFamilyValue( + const { recordTableId } = useRecordTableContextOrThrow(); + + const isFocused = useRecoilComponentFamilyValueV2( isRecordTableRowFocusedComponentFamilyState, realIndex, ); - const isRowFocusActive = useRecoilComponentValue( + const isRowFocusActive = useRecoilComponentValueV2( isRecordTableRowFocusActiveComponentState, + recordTableId, ); - const recordId = useRecoilComponentFamilyValue( + const recordId = useRecoilComponentFamilySelectorValueV2( recordIdByRealIndexComponentFamilySelector, realIndex, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel1.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel1.tsx index 4c5d8d55b3..68e95670ad 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel1.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel1.tsx @@ -2,7 +2,7 @@ import { RecordTableRowVirtualizedRouterLevel2 } from '@/object-record/record-ta import { RecordTableRowVirtualizedSkeleton } from '@/object-record/record-table/virtualization/components/RecordTableRowVirtualizedSkeleton'; import { lowDetailsActivatedComponentState } from '@/object-record/record-table/virtualization/states/lowDetailsActivatedComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; type RecordTableRowVirtualizedRouterLevel1Props = { realIndex: number; @@ -11,11 +11,11 @@ type RecordTableRowVirtualizedRouterLevel1Props = { export const RecordTableRowVirtualizedRouterLevel1 = ({ realIndex, }: RecordTableRowVirtualizedRouterLevel1Props) => { - const lowDetailsActivated = useRecoilComponentValue( + const lowDetailsActivated = useRecoilComponentValueV2( lowDetailsActivatedComponentState, ); - if (lowDetailsActivated) { + if (lowDetailsActivated === true) { return ; } diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel2.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel2.tsx index 91e47be2c2..d420a1247d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel2.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableRowVirtualizedRouterLevel2.tsx @@ -3,7 +3,7 @@ import { RecordTableRowVirtualizedFullData } from '@/object-record/record-table/ import { RecordTableRowVirtualizedSkeleton } from '@/object-record/record-table/virtualization/components/RecordTableRowVirtualizedSkeleton'; import { dataLoadingStatusByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2'; type RecordTableRowVirtualizedRouterLevel2Props = { realIndex: number; @@ -12,7 +12,7 @@ type RecordTableRowVirtualizedRouterLevel2Props = { export const RecordTableRowVirtualizedRouterLevel2 = ({ realIndex, }: RecordTableRowVirtualizedRouterLevel2Props) => { - const dataLoadingStatus = useRecoilComponentFamilyValue( + const dataLoadingStatus = useRecoilComponentFamilySelectorValueV2( dataLoadingStatusByRealIndexComponentFamilySelector, realIndex, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx index 97ce5112c9..54e6fe1c24 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx @@ -1,7 +1,7 @@ import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; @@ -18,7 +18,7 @@ const StyledVirtualizationContainer = styled.div<{ `; export const RecordTableVirtualizedBodyPlaceholder = () => { - const totalNumberOfRecordsToVirtualize = useRecoilComponentValue( + const totalNumberOfRecordsToVirtualize = useRecoilComponentValueV2( totalNumberOfRecordsToVirtualizeComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedDebugHelper.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedDebugHelper.tsx index c634029771..f898b8ed00 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedDebugHelper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedDebugHelper.tsx @@ -4,11 +4,11 @@ import { } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect'; import { TABLE_VIRTUALIZATION_DEBUG_ACTIVATED } from '@/object-record/record-table/virtualization/constants/TableVirtualizationDebugActivated'; import { lowDetailsActivatedComponentState } from '@/object-record/record-table/virtualization/states/lowDetailsActivatedComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { createPortal } from 'react-dom'; export const RecordTableVirtualizedDebugHelper = () => { - const lowDetailsActivated = useRecoilComponentValue( + const lowDetailsActivated = useRecoilComponentValueV2( lowDetailsActivatedComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedFieldMetadataUpdateEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedFieldMetadataUpdateEffect.tsx index f5903089d2..d1f2b9d86d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedFieldMetadataUpdateEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedFieldMetadataUpdateEffect.tsx @@ -3,8 +3,8 @@ import { visibleRecordFieldsComponentSelector } from '@/object-record/record-fie import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useResetVirtualizationBecauseDataChanged } from '@/object-record/record-table/virtualization/hooks/useResetVirtualizationBecauseDataChanged'; import { lastProcessedFieldMetadataUpdateIdComponentState } from '@/object-record/record-table/virtualization/states/lastProcessedFieldMetadataUpdateIdComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useEffect } from 'react'; @@ -14,7 +14,7 @@ export const RecordTableVirtualizedFieldMetadataUpdateEffect = () => { const { resetVirtualizationBecauseDataChanged } = useResetVirtualizationBecauseDataChanged(objectNameSingular); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); @@ -25,7 +25,9 @@ export const RecordTableVirtualizedFieldMetadataUpdateEffect = () => { const [ lastProcessedFieldMetadataUpdateId, setLastProcessedFieldMetadataUpdateId, - ] = useRecoilComponentState(lastProcessedFieldMetadataUpdateIdComponentState); + ] = useRecoilComponentStateV2( + lastProcessedFieldMetadataUpdateIdComponentState, + ); useEffect(() => { if (!lastFieldMetadataItemUpdate) { @@ -42,7 +44,7 @@ export const RecordTableVirtualizedFieldMetadataUpdateEffect = () => { lastFieldMetadataItemUpdate.fieldMetadataItemId, ); - if (isFieldInCurrentView) { + if (isFieldInCurrentView === true) { setLastProcessedFieldMetadataUpdateId(lastFieldMetadataItemUpdate.id); resetVirtualizationBecauseDataChanged(); } diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx index 34dcdd4d06..bc8a52ca40 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedInitialDataLoadEffect.tsx @@ -1,5 +1,3 @@ -import { useRecoilValue } from 'recoil'; - import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; @@ -10,8 +8,9 @@ import { lastContextStoreVirtualizedViewIdComponentState } from '@/object-record import { lastContextStoreVirtualizedVisibleRecordFieldsComponentState } from '@/object-record/record-table/virtualization/states/lastContextStoreVirtualizedVisibleRecordFieldsComponentState'; import { lastRecordTableQueryIdentifierComponentState } from '@/object-record/record-table/virtualization/states/lastRecordTableQueryIdentifierComponentState'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import isEmpty from 'lodash.isempty'; import { useEffect } from 'react'; @@ -23,17 +22,18 @@ export const RecordTableVirtualizedInitialDataLoadEffect = () => { const { queryIdentifier } = useRecordIndexTableFetchMore(objectNameSingular); const [lastRecordTableQueryIdentifier, setLastRecordTableQueryIdentifier] = - useRecoilComponentState(lastRecordTableQueryIdentifierComponentState); + useRecoilComponentStateV2(lastRecordTableQueryIdentifierComponentState); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); - const [isInitializingVirtualTableDataLoading] = useRecoilComponentState( + const [isInitializingVirtualTableDataLoading] = useRecoilComponentStateV2( isInitializingVirtualTableDataLoadingComponentState, ); - const isFetchingMoreRecords = useRecoilValue( - isFetchingMoreRecordsFamilyState(recordTableId), + const isFetchingMoreRecords = useFamilyRecoilValueV2( + isFetchingMoreRecordsFamilyState, + recordTableId, ); const { triggerInitialRecordTableDataLoad } = @@ -42,12 +42,14 @@ export const RecordTableVirtualizedInitialDataLoadEffect = () => { const [ lastContextStoreVirtualizedViewId, setLastContextStoreVirtualizedViewId, - ] = useRecoilComponentState(lastContextStoreVirtualizedViewIdComponentState); + ] = useRecoilComponentStateV2( + lastContextStoreVirtualizedViewIdComponentState, + ); const [ lastContextStoreVisibleRecordFields, setLastContextStoreVisibleRecordFields, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( lastContextStoreVirtualizedVisibleRecordFieldsComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx index bfe2cec277..abe9054ec5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx @@ -1,3 +1,6 @@ +import { useCallback, useEffect } from 'react'; +import { useStore } from 'jotai'; + import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; import { NUMBER_OF_VIRTUALIZED_ROWS } from '@/object-record/record-table/virtualization/constants/NumberOfVirtualizedRows'; import { useProcessTreadmillScrollTop } from '@/object-record/record-table/virtualization/hooks/useProcessTreadmillScrollTop'; @@ -7,14 +10,9 @@ import { lowDetailsActivatedComponentState } from '@/object-record/record-table/ import { scrollAtRealIndexComponentState } from '@/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useCallback, useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useDebouncedCallback } from 'use-debounce'; -// TODO: export those constants -// TODO: break down this effect into multiple smaller effect components export const SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_ACTIVATE_LOW_DETAILS = 120; export const SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_DEACTIVATE_LOW_DETAILS = 30; @@ -27,20 +25,20 @@ const LAST_SCROLL_DEBOUNCE_TIME = 300; export const RecordTableVirtualizedRowTreadmillEffect = () => { const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement(); - const scrollAtRealIndexCallbackState = useRecoilComponentCallbackState( + const scrollAtRealIndexCallbackState = useRecoilComponentStateCallbackStateV2( scrollAtRealIndexComponentState, ); - const lowDetailsActivatedCallbackState = useRecoilComponentCallbackState( - lowDetailsActivatedComponentState, - ); + const lowDetailsActivatedCallbackState = + useRecoilComponentStateCallbackStateV2(lowDetailsActivatedComponentState); - const lastScrollMeasurementsCallbackState = useRecoilComponentCallbackState( - lastScrollMeasurementsComponentState, - ); + const lastScrollMeasurementsCallbackState = + useRecoilComponentStateCallbackStateV2( + lastScrollMeasurementsComponentState, + ); const totalNumberOfRecordsToVirtualizeCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( totalNumberOfRecordsToVirtualizeComponentState, ); @@ -48,6 +46,8 @@ export const RecordTableVirtualizedRowTreadmillEffect = () => { const { processTreadmillScrollTop } = useProcessTreadmillScrollTop(); + const store = useStore(); + const handleScrollDebounced = useDebouncedCallback( processTreadmillScrollTop, TIME_BETWEEN_TWO_SCROLL_HANDLING, @@ -58,20 +58,15 @@ export const RecordTableVirtualizedRowTreadmillEffect = () => { }, ); - const deactivateLowDetails = useRecoilCallback( - ({ snapshot, set }) => - () => { - const currentLowDetailsActivated = getSnapshotValue( - snapshot, - lowDetailsActivatedCallbackState, - ); + const deactivateLowDetails = useCallback(() => { + const currentLowDetailsActivated = store.get( + lowDetailsActivatedCallbackState, + ); - if (currentLowDetailsActivated !== false) { - set(lowDetailsActivatedCallbackState, false); - } - }, - [lowDetailsActivatedCallbackState], - ); + if (currentLowDetailsActivated !== false) { + store.set(lowDetailsActivatedCallbackState, false); + } + }, [lowDetailsActivatedCallbackState, store]); const deactivateLowDetailsDebounced = useDebouncedCallback( deactivateLowDetails, @@ -81,62 +76,53 @@ export const RecordTableVirtualizedRowTreadmillEffect = () => { }, ); - const activateLowDetails = useRecoilCallback( - ({ snapshot, set }) => - () => { - deactivateLowDetailsDebounced.cancel(); + const activateLowDetails = useCallback(() => { + deactivateLowDetailsDebounced.cancel(); - const currentLowDetailsActivated = getSnapshotValue( - snapshot, - lowDetailsActivatedCallbackState, - ); - - const scrollAtRealIndex = getSnapshotValue( - snapshot, - scrollAtRealIndexCallbackState, - ); - - const totalNumberOfRecordsToVirtualize = - getSnapshotValue( - snapshot, - totalNumberOfRecordsToVirtualizeCallbackState, - ) ?? NUMBER_OF_VIRTUALIZED_ROWS; - - if ( - scrollAtRealIndex < 100 || - scrollAtRealIndex > totalNumberOfRecordsToVirtualize - 100 - ) { - return; - } - - if (currentLowDetailsActivated !== true) { - set(lowDetailsActivatedCallbackState, true); - } - }, - [ + const currentLowDetailsActivated = store.get( lowDetailsActivatedCallbackState, - deactivateLowDetailsDebounced, - scrollAtRealIndexCallbackState, - totalNumberOfRecordsToVirtualizeCallbackState, - ], - ); + ); - const handleAfterLastScroll = useRecoilCallback( - ({ set }) => - (scrollEvent: Event) => { - deactivateLowDetails(); + const scrollAtRealIndex = store.get(scrollAtRealIndexCallbackState); - processTreadmillScrollTop((scrollEvent.target as any).scrollTop); + const totalNumberOfRecordsToVirtualize = + store.get(totalNumberOfRecordsToVirtualizeCallbackState) ?? + NUMBER_OF_VIRTUALIZED_ROWS; - triggerFetchPages(); + if ( + scrollAtRealIndex < 100 || + scrollAtRealIndex > totalNumberOfRecordsToVirtualize - 100 + ) { + return; + } - set(lastScrollMeasurementsCallbackState, []); - }, + if (currentLowDetailsActivated !== true) { + store.set(lowDetailsActivatedCallbackState, true); + } + }, [ + lowDetailsActivatedCallbackState, + deactivateLowDetailsDebounced, + scrollAtRealIndexCallbackState, + totalNumberOfRecordsToVirtualizeCallbackState, + store, + ]); + + const handleAfterLastScroll = useCallback( + (scrollEvent: Event) => { + deactivateLowDetails(); + + processTreadmillScrollTop((scrollEvent.target as any).scrollTop); + + triggerFetchPages(); + + store.set(lastScrollMeasurementsCallbackState, []); + }, [ processTreadmillScrollTop, triggerFetchPages, deactivateLowDetails, lastScrollMeasurementsCallbackState, + store, ], ); @@ -145,89 +131,85 @@ export const RecordTableVirtualizedRowTreadmillEffect = () => { LAST_SCROLL_DEBOUNCE_TIME, ); - const handleScrollData = useRecoilCallback( - ({ snapshot, set }) => - (scrollEvent: Event) => { - const distanceFromTop = (scrollEvent.target as any).scrollTop; + const handleScrollData = useCallback( + (scrollEvent: Event) => { + const distanceFromTop = (scrollEvent.target as any).scrollTop; - const lastScrollMeasurements = getSnapshotValue( - snapshot, - lastScrollMeasurementsCallbackState, - ).concat(); + const lastScrollMeasurements = store + .get(lastScrollMeasurementsCallbackState) + .concat(); - lastScrollMeasurements.push({ - scrollToTop: distanceFromTop, - timestamp: scrollEvent.timeStamp, - }); + lastScrollMeasurements.push({ + scrollToTop: distanceFromTop, + timestamp: scrollEvent.timeStamp, + }); - set(lastScrollMeasurementsCallbackState, lastScrollMeasurements); + store.set(lastScrollMeasurementsCallbackState, lastScrollMeasurements); - if (lastScrollMeasurements.length > 1) { - const scrollMeasurementsForAverage = lastScrollMeasurements.slice( - -NUMBER_OF_EVENTS_TO_COMPUTE_AVERAGE, + if (lastScrollMeasurements.length > 1) { + const scrollMeasurementsForAverage = lastScrollMeasurements.slice( + -NUMBER_OF_EVENTS_TO_COMPUTE_AVERAGE, + ); + + const scrollSpeedInPixelsPerSecondSum = + scrollMeasurementsForAverage.reduce( + (sum, scrollMeasurement, currentIndex, allMeasurements) => { + if (currentIndex === 0) { + return sum; + } + + const previousMeasurement = allMeasurements[currentIndex - 1]; + + const secondsDifferenceWithPreviousMeasurement = + (scrollMeasurement.timestamp - previousMeasurement.timestamp) / + 1_000; + + const scrollDifferenceWithPreviousMeasurement = Math.abs( + scrollMeasurement.scrollToTop - previousMeasurement.scrollToTop, + ); + + const scrollSpeedInPixelsPerSecond = + scrollDifferenceWithPreviousMeasurement / + secondsDifferenceWithPreviousMeasurement; + + sum += scrollSpeedInPixelsPerSecond; + + return sum; + }, + 0, ); - const scrollSpeedInPixelsPerSecondSum = - scrollMeasurementsForAverage.reduce( - (sum, scrollMeasurement, currentIndex, allMeasurements) => { - if (currentIndex === 0) { - return sum; - } + const averageScrollSpeedInPixelsPerSecond = + scrollSpeedInPixelsPerSecondSum / scrollMeasurementsForAverage.length; - const previousMeasurement = allMeasurements[currentIndex - 1]; + const averageScrollSpeedInRowsPerSecond = + averageScrollSpeedInPixelsPerSecond / (RECORD_TABLE_ROW_HEIGHT + 1); - const secondsDifferenceWithPreviousMeasurement = - (scrollMeasurement.timestamp - - previousMeasurement.timestamp) / - 1_000; + if ( + averageScrollSpeedInRowsPerSecond > + SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_ACTIVATE_LOW_DETAILS + ) { + activateLowDetails(); + handleAfterLastScrollDebounced.cancel(); + } else if ( + averageScrollSpeedInRowsPerSecond < + SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_DEACTIVATE_LOW_DETAILS + ) { + deactivateLowDetailsDebounced(); - const scrollDifferenceWithPreviousMeasurement = Math.abs( - scrollMeasurement.scrollToTop - - previousMeasurement.scrollToTop, - ); - - const scrollSpeedInPixelsPerSecond = - scrollDifferenceWithPreviousMeasurement / - secondsDifferenceWithPreviousMeasurement; - - sum += scrollSpeedInPixelsPerSecond; - - return sum; - }, - 0, - ); - - const averageScrollSpeedInPixelsPerSecond = - scrollSpeedInPixelsPerSecondSum / - scrollMeasurementsForAverage.length; - - const averageScrollSpeedInRowsPerSecond = - averageScrollSpeedInPixelsPerSecond / (RECORD_TABLE_ROW_HEIGHT + 1); - - if ( - averageScrollSpeedInRowsPerSecond > - SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_ACTIVATE_LOW_DETAILS - ) { - activateLowDetails(); - handleAfterLastScrollDebounced.cancel(); - } else if ( - averageScrollSpeedInRowsPerSecond < - SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_DEACTIVATE_LOW_DETAILS - ) { - deactivateLowDetailsDebounced(); - - triggerFetchPages(); - } - } else { triggerFetchPages(); } - }, + } else { + triggerFetchPages(); + } + }, [ lastScrollMeasurementsCallbackState, triggerFetchPages, activateLowDetails, deactivateLowDetailsDebounced, handleAfterLastScrollDebounced, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedSSESubscribeEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedSSESubscribeEffect.tsx index 1f4d85a4dc..1bf848b416 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedSSESubscribeEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedSSESubscribeEffect.tsx @@ -7,22 +7,22 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { computeRecordGqlOperationFilter } from 'twenty-shared/utils'; export const RecordTableVirtualizedSSESubscribeEffect = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); const { filterValueDependencies } = useFilterValueDependencies(); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useGetShouldResetTableVirtualizationForUpdateInputs.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useGetShouldResetTableVirtualizationForUpdateInputs.ts index c0df1bc795..35bd9b341f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useGetShouldResetTableVirtualizationForUpdateInputs.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useGetShouldResetTableVirtualizationForUpdateInputs.ts @@ -3,7 +3,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { type ObjectRecordOperationUpdateInput } from '@/object-record/types/ObjectRecordOperationUpdateInput'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { mapById } from 'twenty-shared/utils'; @@ -14,11 +14,11 @@ export const useGetShouldResetTableVirtualizationForUpdateInputs = () => { objectMetadataItem, }); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows.ts index 5cd27b00bb..26b4e41f40 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows.ts @@ -1,95 +1,97 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; -import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { NO_RECORD_GROUP_FAMILY_KEY } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; -import { dataLoadingStatusByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector'; -import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; +import { dataLoadingStatusByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState'; +import { recordIdByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useLoadRecordsToVirtualRows = () => { - const recordIdByRealIndexCallbackSelector = - useRecoilComponentFamilyCallbackState( - recordIdByRealIndexComponentFamilySelector, - ); - - const dataLoadingStatusByRealIndexCallbackSelector = - useRecoilComponentFamilyCallbackState( - dataLoadingStatusByRealIndexComponentFamilySelector, - ); - - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( - recordIndexAllRecordIdsComponentSelector, + const recordIdByRealIndexAtom = useRecoilComponentStateCallbackStateV2( + recordIdByRealIndexComponentState, ); - const hasUserSelectedAllRowsCallbackState = useRecoilComponentCallbackState( + const dataLoadingStatusByRealIndexAtom = + useRecoilComponentStateCallbackStateV2( + dataLoadingStatusByRealIndexComponentState, + ); + + const recordIndexRecordIdsByGroupFamilyState = + useRecoilComponentFamilyStateCallbackStateV2( + recordIndexRecordIdsByGroupComponentFamilyState, + ); + + const hasUserSelectedAllRowsAtom = useRecoilComponentStateCallbackStateV2( hasUserSelectedAllRowsComponentState, ); - const isRowSelectedCallbackState = useRecoilComponentCallbackState( + const isRowSelectedFamilyState = useRecoilComponentFamilyStateCallbackStateV2( isRowSelectedComponentFamilyState, ); - const loadRecordsToVirtualRows = useRecoilCallback( - ({ set, snapshot }) => - ({ - records, - startingRealIndex, - }: { - records: ObjectRecord[]; - startingRealIndex: number; - }) => { - const hasUserSelectedAllRows = getSnapshotValue( - snapshot, - hasUserSelectedAllRowsCallbackState, - ); + const store = useStore(); - for (const [recordIndex, record] of records.entries()) { - const realIndex = startingRealIndex + recordIndex; + const loadRecordsToVirtualRows = useCallback( + ({ + records, + startingRealIndex, + }: { + records: ObjectRecord[]; + startingRealIndex: number; + }) => { + const hasUserSelectedAllRows = store.get(hasUserSelectedAllRowsAtom); - const currentRecordIdAtRealIndex = getSnapshotValue( - snapshot, - recordIdByRealIndexCallbackSelector(realIndex), - ); + const currentRecordIdMap = store.get(recordIdByRealIndexAtom); + const newRecordIdMap = new Map(currentRecordIdMap); + const currentStatusMap = store.get(dataLoadingStatusByRealIndexAtom); + const newStatusMap = new Map(currentStatusMap); - if (record.id !== currentRecordIdAtRealIndex) { - set(recordIdByRealIndexCallbackSelector(realIndex), record.id); - } + for (const [recordIndex, record] of records.entries()) { + const realIndex = startingRealIndex + recordIndex; - set( - dataLoadingStatusByRealIndexCallbackSelector(realIndex), - 'loaded', - ); + if (record.id !== currentRecordIdMap.get(realIndex)) { + newRecordIdMap.set(realIndex, record.id); } - const currentAllRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); + newStatusMap.set(realIndex, 'loaded'); + } - const recordIds = records.map((record) => record.id); + store.set(recordIdByRealIndexAtom, newRecordIdMap); + store.set(dataLoadingStatusByRealIndexAtom, newStatusMap); - const newAllRecordIds = currentAllRecordIds.concat(); + const currentAllRecordIds = store.get( + recordIndexRecordIdsByGroupFamilyState(NO_RECORD_GROUP_FAMILY_KEY), + ); - for (let i = 0; i < records.length; i++) { - newAllRecordIds[i + startingRealIndex] = recordIds[i]; + const recordIds = records.map((record) => record.id); - if (hasUserSelectedAllRows) { - set(isRowSelectedCallbackState(recordIds[i]), true); - } + const newAllRecordIds = currentAllRecordIds.concat(); + + for (let i = 0; i < records.length; i++) { + newAllRecordIds[i + startingRealIndex] = recordIds[i]; + + if (hasUserSelectedAllRows) { + store.set(isRowSelectedFamilyState(recordIds[i]), true); } + } - set(recordIndexAllRecordIdsSelector, newAllRecordIds); - }, + store.set( + recordIndexRecordIdsByGroupFamilyState(NO_RECORD_GROUP_FAMILY_KEY), + newAllRecordIds, + ); + }, [ - recordIdByRealIndexCallbackSelector, - dataLoadingStatusByRealIndexCallbackSelector, - recordIndexAllRecordIdsSelector, - isRowSelectedCallbackState, - hasUserSelectedAllRowsCallbackState, + recordIdByRealIndexAtom, + dataLoadingStatusByRealIndexAtom, + recordIndexRecordIdsByGroupFamilyState, + isRowSelectedFamilyState, + hasUserSelectedAllRowsAtom, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useProcessTreadmillScrollTop.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useProcessTreadmillScrollTop.ts index 643833d871..27ffaf61bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useProcessTreadmillScrollTop.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useProcessTreadmillScrollTop.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; import { NUMBER_OF_VIRTUALIZED_ROWS } from '@/object-record/record-table/virtualization/constants/NumberOfVirtualizedRows'; import { lastRealIndexSetComponentState } from '@/object-record/record-table/virtualization/states/lastRealIndexSetComponentState'; @@ -5,141 +8,137 @@ import { lastScrollPositionComponentState } from '@/object-record/record-table/v import { realIndexByVirtualIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState'; import { scrollAtRealIndexComponentState } from '@/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; export const useProcessTreadmillScrollTop = () => { const { getScrollWrapperElement } = useScrollWrapperHTMLElement(); - const lastScrollPositionCallbackState = useRecoilComponentCallbackState( - lastScrollPositionComponentState, - ); + const lastScrollPositionCallbackState = + useRecoilComponentStateCallbackStateV2(lastScrollPositionComponentState); - const lastRealIndexSetCallbackState = useRecoilComponentCallbackState( + const lastRealIndexSetCallbackState = useRecoilComponentStateCallbackStateV2( lastRealIndexSetComponentState, ); - const scrollAtRealIndexCallbackState = useRecoilComponentCallbackState( + const scrollAtRealIndexCallbackState = useRecoilComponentStateCallbackStateV2( scrollAtRealIndexComponentState, ); const virtualizedRowRealIndexByVirtualIndexCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentFamilyStateCallbackStateV2( realIndexByVirtualIndexComponentFamilyState, ); - const processTreadmillScrollTop = useRecoilCallback( - ({ snapshot, set }) => - (scrollTop: number) => { - const distanceFromTop = scrollTop; + const store = useStore(); - const { scrollWrapperElement } = getScrollWrapperElement(); + const processTreadmillScrollTop = useCallback( + (scrollTop: number) => { + const distanceFromTop = scrollTop; - const tableScrollWrapperHeight = - scrollWrapperElement?.clientHeight ?? 0; + const { scrollWrapperElement } = getScrollWrapperElement(); - const lastScrollPosition = getSnapshotValue( - snapshot, - lastScrollPositionCallbackState, - ); + const tableScrollWrapperHeight = scrollWrapperElement?.clientHeight ?? 0; - set(lastScrollPositionCallbackState, distanceFromTop); + const lastScrollPosition = store.get(lastScrollPositionCallbackState); - const scrollDirection = - distanceFromTop > lastScrollPosition ? 'downward' : 'upward'; + store.set(lastScrollPositionCallbackState, distanceFromTop); - const numberOfRowsDisplayedInTable = Math.min( - Math.floor(tableScrollWrapperHeight / (RECORD_TABLE_ROW_HEIGHT + 1)), - 30, - ); + const scrollDirection = + distanceFromTop > lastScrollPosition ? 'downward' : 'upward'; - const halfNumberOfRowsVisible = Math.floor( - numberOfRowsDisplayedInTable / 2, - ); + const numberOfRowsDisplayedInTable = Math.min( + Math.floor(tableScrollWrapperHeight / (RECORD_TABLE_ROW_HEIGHT + 1)), + 30, + ); - const realIndexAtTheMiddleOfTheTable = - Math.floor(distanceFromTop / (RECORD_TABLE_ROW_HEIGHT + 1)) + - halfNumberOfRowsVisible; + const halfNumberOfRowsVisible = Math.floor( + numberOfRowsDisplayedInTable / 2, + ); - const lastCorrectlySetRealIndex = - getSnapshotValue(snapshot, lastRealIndexSetCallbackState) ?? - numberOfRowsDisplayedInTable; + const realIndexAtTheMiddleOfTheTable = + Math.floor(distanceFromTop / (RECORD_TABLE_ROW_HEIGHT + 1)) + + halfNumberOfRowsVisible; - set(scrollAtRealIndexCallbackState, realIndexAtTheMiddleOfTheTable); + const lastCorrectlySetRealIndex = + store.get(lastRealIndexSetCallbackState) ?? + numberOfRowsDisplayedInTable; - if (scrollDirection === 'downward') { - const newTargetRealIndexToReachAtTheBottomOfTheOverscan = - realIndexAtTheMiddleOfTheTable + - Math.floor(NUMBER_OF_VIRTUALIZED_ROWS / 2); + store.set(scrollAtRealIndexCallbackState, realIndexAtTheMiddleOfTheTable); - const numberOfRealIndexToSet = - newTargetRealIndexToReachAtTheBottomOfTheOverscan - - lastCorrectlySetRealIndex; + if (scrollDirection === 'downward') { + const newTargetRealIndexToReachAtTheBottomOfTheOverscan = + realIndexAtTheMiddleOfTheTable + + Math.floor(NUMBER_OF_VIRTUALIZED_ROWS / 2); - if (numberOfRealIndexToSet <= 0) { - return; - } + const numberOfRealIndexToSet = + newTargetRealIndexToReachAtTheBottomOfTheOverscan - + lastCorrectlySetRealIndex; - for (let i = 0; i < numberOfRealIndexToSet + 1; i++) { - const realIndexThatWillBeSet = lastCorrectlySetRealIndex + i; + if (numberOfRealIndexToSet <= 0) { + return; + } - const correspondingVirtualIndex = - realIndexThatWillBeSet % NUMBER_OF_VIRTUALIZED_ROWS; + for (let i = 0; i < numberOfRealIndexToSet + 1; i++) { + const realIndexThatWillBeSet = lastCorrectlySetRealIndex + i; - set( - virtualizedRowRealIndexByVirtualIndexCallbackState({ - virtualIndex: correspondingVirtualIndex, - }), - realIndexThatWillBeSet, - ); - } + const correspondingVirtualIndex = + realIndexThatWillBeSet % NUMBER_OF_VIRTUALIZED_ROWS; - set( - lastRealIndexSetCallbackState, - lastCorrectlySetRealIndex + numberOfRealIndexToSet, - ); - } else { - const newTargetRealIndexToReachAtTheTopOfTheOverscan = Math.max( - 0, - realIndexAtTheMiddleOfTheTable - - Math.floor(NUMBER_OF_VIRTUALIZED_ROWS / 2), - ); - - const numberOfRealIndexToSet = - lastCorrectlySetRealIndex - - newTargetRealIndexToReachAtTheTopOfTheOverscan; - - if (numberOfRealIndexToSet <= 0) { - return; - } - - for (let i = 0; i <= numberOfRealIndexToSet; i++) { - const realIndexThatWillBeSet = lastCorrectlySetRealIndex - i; - - const correspondingVirtualIndex = - realIndexThatWillBeSet % NUMBER_OF_VIRTUALIZED_ROWS; - - set( - virtualizedRowRealIndexByVirtualIndexCallbackState({ - virtualIndex: correspondingVirtualIndex, - }), - realIndexThatWillBeSet, - ); - } - - set( - lastRealIndexSetCallbackState, - lastCorrectlySetRealIndex - numberOfRealIndexToSet, + store.set( + virtualizedRowRealIndexByVirtualIndexCallbackState({ + virtualIndex: correspondingVirtualIndex, + }), + realIndexThatWillBeSet, ); } - }, + + store.set( + lastRealIndexSetCallbackState, + lastCorrectlySetRealIndex + numberOfRealIndexToSet, + ); + } else { + const newTargetRealIndexToReachAtTheTopOfTheOverscan = Math.max( + 0, + realIndexAtTheMiddleOfTheTable - + Math.floor(NUMBER_OF_VIRTUALIZED_ROWS / 2), + ); + + const numberOfRealIndexToSet = + lastCorrectlySetRealIndex - + newTargetRealIndexToReachAtTheTopOfTheOverscan; + + if (numberOfRealIndexToSet <= 0) { + return; + } + + for (let i = 0; i <= numberOfRealIndexToSet; i++) { + const realIndexThatWillBeSet = lastCorrectlySetRealIndex - i; + + const correspondingVirtualIndex = + realIndexThatWillBeSet % NUMBER_OF_VIRTUALIZED_ROWS; + + store.set( + virtualizedRowRealIndexByVirtualIndexCallbackState({ + virtualIndex: correspondingVirtualIndex, + }), + realIndexThatWillBeSet, + ); + } + + store.set( + lastRealIndexSetCallbackState, + lastCorrectlySetRealIndex - numberOfRealIndexToSet, + ); + } + }, [ lastRealIndexSetCallbackState, virtualizedRowRealIndexByVirtualIndexCallbackState, lastScrollPositionCallbackState, scrollAtRealIndexCallbackState, getScrollWrapperElement, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useReapplyRowSelection.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useReapplyRowSelection.ts index cbd077c2f0..95be7531a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useReapplyRowSelection.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useReapplyRowSelection.ts @@ -1,11 +1,11 @@ import { useSelectAllRows } from '@/object-record/record-table/hooks/internal/useSelectAllRows'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useReapplyRowSelection = () => { const { selectAllRows } = useSelectAllRows(); - const hasUserSelectedAllRows = useRecoilComponentValue( + const hasUserSelectedAllRows = useRecoilComponentValueV2( hasUserSelectedAllRowsComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetTableFocuses.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetTableFocuses.ts index d5b2ff26a0..51afbca949 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetTableFocuses.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetTableFocuses.ts @@ -1,13 +1,13 @@ import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/useFocusedRecordTableRow'; import { useUnfocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useUnfocusRecordTableCell'; import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export const useResetTableFocuses = (recordTableId: string) => { const { unfocusRecordTableCell } = useUnfocusRecordTableCell(recordTableId); const { unfocusRecordTableRow } = useFocusedRecordTableRow(recordTableId); - const setRecordTableHoverPosition = useSetRecoilComponentState( + const setRecordTableHoverPosition = useSetRecoilComponentStateV2( recordTableHoverPositionComponentState, recordTableId, ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizationBecauseDataChanged.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizationBecauseDataChanged.ts index cd82e8012c..e70da44bad 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizationBecauseDataChanged.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizationBecauseDataChanged.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields'; @@ -11,10 +14,7 @@ import { recordIdByRealIndexComponentState } from '@/object-record/record-table/ import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; import { getVirtualizationOverscanWindow } from '@/object-record/record-table/virtualization/utils/getVirtualizationOverscanWindow'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; import { sleep } from '~/utils/sleep'; @@ -29,7 +29,6 @@ export const useResetVirtualizationBecauseDataChanged = ( const params = useFindManyRecordIndexTableParams(objectNameSingular); - // TODO: we could optimize this by using an aggregate or using only id: true in recordGqlFields const recordGqlFields = useRecordsFieldVisibleGqlFields({ objectMetadataItem, }); @@ -42,113 +41,100 @@ export const useResetVirtualizationBecauseDataChanged = ( }); const totalNumberOfRecordsToVirtualizeCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( totalNumberOfRecordsToVirtualizeComponentState, ); - const dataPagesLoadedCallbackState = useRecoilComponentCallbackState( + const dataPagesLoadedCallbackState = useRecoilComponentStateCallbackStateV2( dataPagesLoadedComponentState, ); const { triggerFetchPagesWithoutDebounce } = useTriggerFetchPages(); - const lastScrollPositionCallbackState = useRecoilComponentCallbackState( - lastScrollPositionComponentState, - ); + const lastScrollPositionCallbackState = + useRecoilComponentStateCallbackStateV2(lastScrollPositionComponentState); - const recordIdByRealIndexCallbackState = useRecoilComponentCallbackState( - recordIdByRealIndexComponentState, - ); + const recordIdByRealIndexCallbackState = + useRecoilComponentStateCallbackStateV2(recordIdByRealIndexComponentState); const dataLoadingStatusByRealIndexCallbackState = - useRecoilComponentCallbackState(dataLoadingStatusByRealIndexComponentState); + useRecoilComponentStateCallbackStateV2( + dataLoadingStatusByRealIndexComponentState, + ); - const resetVirtualization = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const { totalCount } = await findManyRecordsLazy(); + const store = useStore(); - const tableScrollWrapperHeight = - scrollWrapperHTMLElement?.clientHeight ?? 0; + const resetVirtualization = useCallback(async () => { + const { totalCount } = await findManyRecordsLazy(); - const lastScrollPosition = getSnapshotValue( - snapshot, - lastScrollPositionCallbackState, - ); + const tableScrollWrapperHeight = + scrollWrapperHTMLElement?.clientHeight ?? 0; - const totalNumberOfRecordsToVirtualize = - getSnapshotValue( - snapshot, - totalNumberOfRecordsToVirtualizeCallbackState, - ) ?? 0; + const lastScrollPosition = store.get(lastScrollPositionCallbackState); - const { - firstRealIndexInOverscanWindow, - lastRealIndexInOverscanWindow, - } = getVirtualizationOverscanWindow( - lastScrollPosition, - tableScrollWrapperHeight, - totalNumberOfRecordsToVirtualize, - ); + const totalNumberOfRecordsToVirtualize = + store.get(totalNumberOfRecordsToVirtualizeCallbackState) ?? 0; - const recordIdByRealIndex = getSnapshotValue( - snapshot, - recordIdByRealIndexCallbackState, - ); + const { firstRealIndexInOverscanWindow, lastRealIndexInOverscanWindow } = + getVirtualizationOverscanWindow( + lastScrollPosition, + tableScrollWrapperHeight, + totalNumberOfRecordsToVirtualize, + ); - const dataLoadingStatusByRealIndex = getSnapshotValue( - snapshot, - dataLoadingStatusByRealIndexCallbackState, - ); + const recordIdByRealIndex = store.get(recordIdByRealIndexCallbackState); - const lengthOfOverscanWindow = - lastRealIndexInOverscanWindow - firstRealIndexInOverscanWindow + 1; - - const newRecordIdByRealIndex = new Map(); - const newDataLoadingStatusByRealIndex = new Map< - number, - 'loaded' | 'not-loaded' - >(); - - for (let i = 0; i < lengthOfOverscanWindow; i++) { - const realIndex = firstRealIndexInOverscanWindow + i; - - const existingRecordId = recordIdByRealIndex.get(realIndex); - - if (isDefined(existingRecordId)) { - newRecordIdByRealIndex.set(realIndex, existingRecordId); - } - - const existingDataLoadingStatus = - dataLoadingStatusByRealIndex.get(realIndex); - - if (isDefined(existingDataLoadingStatus)) { - newDataLoadingStatusByRealIndex.set( - realIndex, - existingDataLoadingStatus, - ); - } - } - - set(recordIdByRealIndexCallbackState, newRecordIdByRealIndex); - set( - dataLoadingStatusByRealIndexCallbackState, - newDataLoadingStatusByRealIndex, - ); - - set(dataPagesLoadedCallbackState, []); - set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount); - }, - [ - findManyRecordsLazy, - scrollWrapperHTMLElement?.clientHeight, - lastScrollPositionCallbackState, - totalNumberOfRecordsToVirtualizeCallbackState, - dataPagesLoadedCallbackState, + const dataLoadingStatusByRealIndex = store.get( dataLoadingStatusByRealIndexCallbackState, - recordIdByRealIndexCallbackState, - ], - ); + ); + + const lengthOfOverscanWindow = + lastRealIndexInOverscanWindow - firstRealIndexInOverscanWindow + 1; + + const newRecordIdByRealIndex = new Map(); + const newDataLoadingStatusByRealIndex = new Map< + number, + 'loaded' | 'not-loaded' + >(); + + for (let i = 0; i < lengthOfOverscanWindow; i++) { + const realIndex = firstRealIndexInOverscanWindow + i; + + const existingRecordId = recordIdByRealIndex.get(realIndex); + + if (isDefined(existingRecordId)) { + newRecordIdByRealIndex.set(realIndex, existingRecordId); + } + + const existingDataLoadingStatus = + dataLoadingStatusByRealIndex.get(realIndex); + + if (isDefined(existingDataLoadingStatus)) { + newDataLoadingStatusByRealIndex.set( + realIndex, + existingDataLoadingStatus, + ); + } + } + + store.set(recordIdByRealIndexCallbackState, newRecordIdByRealIndex); + store.set( + dataLoadingStatusByRealIndexCallbackState, + newDataLoadingStatusByRealIndex, + ); + + store.set(dataPagesLoadedCallbackState, []); + store.set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount); + }, [ + findManyRecordsLazy, + scrollWrapperHTMLElement?.clientHeight, + lastScrollPositionCallbackState, + totalNumberOfRecordsToVirtualizeCallbackState, + dataPagesLoadedCallbackState, + dataLoadingStatusByRealIndexCallbackState, + recordIdByRealIndexCallbackState, + store, + ]); const resetVirtualizationBecauseDataChanged = useCallback(async () => { await resetVirtualization(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizedRowTreadmill.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizedRowTreadmill.ts index 4dfea232c9..5465236ed4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizedRowTreadmill.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useResetVirtualizedRowTreadmill.ts @@ -1,34 +1,35 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { NUMBER_OF_VIRTUALIZED_ROWS } from '@/object-record/record-table/virtualization/constants/NumberOfVirtualizedRows'; import { realIndexByVirtualIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2'; import { getContiguousIncrementalValues } from 'twenty-shared/utils'; export const useResetVirtualizedRowTreadmill = () => { - const realIndexByVirtualIndexCallbackState = useRecoilComponentCallbackState( - realIndexByVirtualIndexComponentFamilyState, - ); + const realIndexByVirtualIndexCallbackState = + useRecoilComponentFamilyStateCallbackStateV2( + realIndexByVirtualIndexComponentFamilyState, + ); - const resetVirtualizedRowTreadmill = useRecoilCallback( - ({ set }) => - () => { - const virtualIndices = getContiguousIncrementalValues( - NUMBER_OF_VIRTUALIZED_ROWS, - ); + const store = useStore(); - for (const virtualIndex of virtualIndices) { - const realIndex = virtualIndex; + const resetVirtualizedRowTreadmill = useCallback(() => { + const virtualIndices = getContiguousIncrementalValues( + NUMBER_OF_VIRTUALIZED_ROWS, + ); - set( - realIndexByVirtualIndexCallbackState({ - virtualIndex: virtualIndex, - }), - realIndex, - ); - } - }, - [realIndexByVirtualIndexCallbackState], - ); + for (const virtualIndex of virtualIndices) { + const realIndex = virtualIndex; + + store.set( + realIndexByVirtualIndexCallbackState({ + virtualIndex: virtualIndex, + }), + realIndex, + ); + } + }, [realIndexByVirtualIndexCallbackState, store]); return { resetVirtualizedRowTreadmill }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerFetchPages.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerFetchPages.ts index a553ab10df..5bfb6d0fc8 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerFetchPages.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerFetchPages.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useLazyFindManyRecordsWithOffset } from '@/object-record/hooks/useLazyFindManyRecordsWithOffset'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; @@ -10,16 +13,10 @@ import { lowDetailsActivatedComponentState } from '@/object-record/record-table/ import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; import { getVirtualizationOverscanWindow } from '@/object-record/record-table/virtualization/utils/getVirtualizationOverscanWindow'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { getContiguousIncrementalValues, isDefined } from 'twenty-shared/utils'; import { useDebouncedCallback } from 'use-debounce'; -// TODO: Those parameters allow the UI to not freeze while it can take time to fetch data. -// We should work on two additional optimization rounds : -// - A row take too much time to render -// - Requests are too eagerly loading relationships. const TIME_BETWEEN_UI_BATCH_UPDATE = 25; const PAGING_FOR_UI_UPDATE = 10; const TIME_BETWEEN_TWO_REQUETS = 25; @@ -33,15 +30,14 @@ export const useTriggerFetchPages = () => { const { loadRecordsToVirtualRows } = useLoadRecordsToVirtualRows(); const totalNumberOfRecordsToVirtualizeCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( totalNumberOfRecordsToVirtualizeComponentState, ); - const lastScrollPositionCallbackState = useRecoilComponentCallbackState( - lastScrollPositionComponentState, - ); + const lastScrollPositionCallbackState = + useRecoilComponentStateCallbackStateV2(lastScrollPositionComponentState); - const dataPagesLoadedCallbackState = useRecoilComponentCallbackState( + const dataPagesLoadedCallbackState = useRecoilComponentStateCallbackStateV2( dataPagesLoadedComponentState, ); @@ -49,152 +45,138 @@ export const useTriggerFetchPages = () => { objectNameSingular, }); - const lowDetailsActivatedCallbackState = useRecoilComponentCallbackState( - lowDetailsActivatedComponentState, - ); + const lowDetailsActivatedCallbackState = + useRecoilComponentStateCallbackStateV2(lowDetailsActivatedComponentState); - const triggerFetchPagesWithoutDebounce = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const lowDetailsActivated = getSnapshotValue( - snapshot, - lowDetailsActivatedCallbackState, + const store = useStore(); + + const triggerFetchPagesWithoutDebounce = useCallback(async () => { + const lowDetailsActivated = store.get(lowDetailsActivatedCallbackState); + + if (lowDetailsActivated) { + return; + } + + const tableScrollWrapperHeight = + scrollWrapperHTMLElement?.clientHeight ?? 0; + + const lastScrollPosition = store.get(lastScrollPositionCallbackState); + + const totalNumberOfRecordsToVirtualize = + store.get(totalNumberOfRecordsToVirtualizeCallbackState) ?? 0; + + const { overscanPageAtBottom, overscanPageAtTop } = + getVirtualizationOverscanWindow( + lastScrollPosition, + tableScrollWrapperHeight, + totalNumberOfRecordsToVirtualize, + ); + + const pagesAlreadyLoaded = store.get(dataPagesLoadedCallbackState); + + const numberOfPages = overscanPageAtBottom - overscanPageAtTop; + + const pagesToFetchInitial = getContiguousIncrementalValues( + numberOfPages, + overscanPageAtTop, + ); + + const pagesToFetch = pagesToFetchInitial.filter( + (pageNumber) => !pagesAlreadyLoaded.includes(pageNumber), + ); + + if (pagesToFetch.length === 0) { + return; + } + + let pagesAreContiguous = true; + + for (const [index, pageNumber] of pagesToFetch.entries()) { + const isLastElementOfArray = index === pagesToFetch.length - 1; + + if (isLastElementOfArray) { + continue; + } + + const nextPageNumberIsNotContiguous = + pagesToFetch.at(index + 1) !== pageNumber + 1; + + if (nextPageNumberIsNotContiguous) { + pagesAreContiguous = false; + break; + } + } + + if (pagesAreContiguous) { + const startingRealIndexToFetch = + (pagesToFetch.at(0) ?? 0) * + TABLE_VIRTUALIZATION_NUMBER_OF_RECORDS_PER_PAGE; + + const endingRealIndexToFetch = + (pagesToFetch.at(-1) ?? 0) * + TABLE_VIRTUALIZATION_NUMBER_OF_RECORDS_PER_PAGE + + TABLE_VIRTUALIZATION_NUMBER_OF_RECORDS_PER_PAGE; + + const numberOfRecordsToFetch = + endingRealIndexToFetch - startingRealIndexToFetch; + + if (numberOfRecordsToFetch > 0) { + const fetchResult = await findManyRecordsLazyWithOffset( + numberOfRecordsToFetch, + startingRealIndexToFetch, ); - if (lowDetailsActivated) { - return; - } + const records = fetchResult.records; - const tableScrollWrapperHeight = - scrollWrapperHTMLElement?.clientHeight ?? 0; + if (isDefined(records)) { + const pagingForUIUpdate = PAGING_FOR_UI_UPDATE; - const lastScrollPosition = getSnapshotValue( - snapshot, - lastScrollPositionCallbackState, - ); + const pages = Math.ceil(records.length / pagingForUIUpdate); - const totalNumberOfRecordsToVirtualize = - getSnapshotValue( - snapshot, - totalNumberOfRecordsToVirtualizeCallbackState, - ) ?? 0; - - const { overscanPageAtBottom, overscanPageAtTop } = - getVirtualizationOverscanWindow( - lastScrollPosition, - tableScrollWrapperHeight, - totalNumberOfRecordsToVirtualize, - ); - - const pagesAlreadyLoaded = getSnapshotValue( - snapshot, - dataPagesLoadedCallbackState, - ); - - const numberOfPages = overscanPageAtBottom - overscanPageAtTop; - - const pagesToFetchInitial = getContiguousIncrementalValues( - numberOfPages, - overscanPageAtTop, - ); - - const pagesToFetch = pagesToFetchInitial.filter( - (pageNumber) => !pagesAlreadyLoaded.includes(pageNumber), - ); - - if (pagesToFetch.length === 0) { - return; - } - - let pagesAreContiguous = true; - - for (const [index, pageNumber] of pagesToFetch.entries()) { - const isLastElementOfArray = index === pagesToFetch.length - 1; - - if (isLastElementOfArray) { - continue; - } - - const nextPageNumberIsNotContiguous = - pagesToFetch.at(index + 1) !== pageNumber + 1; - - if (nextPageNumberIsNotContiguous) { - pagesAreContiguous = false; - break; - } - } - - if (pagesAreContiguous) { - const startingRealIndexToFetch = - (pagesToFetch.at(0) ?? 0) * - TABLE_VIRTUALIZATION_NUMBER_OF_RECORDS_PER_PAGE; - - const endingRealIndexToFetch = - (pagesToFetch.at(-1) ?? 0) * - TABLE_VIRTUALIZATION_NUMBER_OF_RECORDS_PER_PAGE + - TABLE_VIRTUALIZATION_NUMBER_OF_RECORDS_PER_PAGE; - - const numberOfRecordsToFetch = - endingRealIndexToFetch - startingRealIndexToFetch; - - if (numberOfRecordsToFetch > 0) { - const fetchResult = await findManyRecordsLazyWithOffset( - numberOfRecordsToFetch, - startingRealIndexToFetch, + for (let page = 0; page < pages; page++) { + await new Promise((res) => + setTimeout(() => res(), TIME_BETWEEN_UI_BATCH_UPDATE), ); - const records = fetchResult.records; + const startingRealIndexInThisUIPage = + startingRealIndexToFetch + page * pagingForUIUpdate; - if (isDefined(records)) { - const pagingForUIUpdate = PAGING_FOR_UI_UPDATE; + const startingSliceIndexInThisPage = page * pagingForUIUpdate; + const endingSliceIndexInThisPage = + startingSliceIndexInThisPage + pagingForUIUpdate; - const pages = Math.ceil(records.length / pagingForUIUpdate); - - for (let page = 0; page < pages; page++) { - await new Promise((res) => - setTimeout(() => res(), TIME_BETWEEN_UI_BATCH_UPDATE), - ); - - const startingRealIndexInThisUIPage = - startingRealIndexToFetch + page * pagingForUIUpdate; - - const startingSliceIndexInThisPage = page * pagingForUIUpdate; - const endingSliceIndexInThisPage = - startingSliceIndexInThisPage + pagingForUIUpdate; - - const recordsSlice = records.slice( - startingSliceIndexInThisPage, - endingSliceIndexInThisPage, - ); - - loadRecordsToVirtualRows({ - records: recordsSlice, - startingRealIndex: startingRealIndexInThisUIPage, - }); - - upsertRecordsInStore({ partialRecords: recordsSlice }); - } - } - - set(dataPagesLoadedCallbackState, (currentLoadedPages) => - currentLoadedPages.concat(pagesToFetch).toSorted(), + const recordsSlice = records.slice( + startingSliceIndexInThisPage, + endingSliceIndexInThisPage, ); + + loadRecordsToVirtualRows({ + records: recordsSlice, + startingRealIndex: startingRealIndexInThisUIPage, + }); + + upsertRecordsInStore({ partialRecords: recordsSlice }); } - } else { - // TODO fetch page by page (will be optmized later) } - }, - [ - dataPagesLoadedCallbackState, - findManyRecordsLazyWithOffset, - totalNumberOfRecordsToVirtualizeCallbackState, - loadRecordsToVirtualRows, - upsertRecordsInStore, - lastScrollPositionCallbackState, - scrollWrapperHTMLElement, - lowDetailsActivatedCallbackState, - ], - ); + + store.set(dataPagesLoadedCallbackState, (currentLoadedPages) => + currentLoadedPages.concat(pagesToFetch).toSorted(), + ); + } + } else { + // TODO fetch page by page (will be optmized later) + } + }, [ + dataPagesLoadedCallbackState, + findManyRecordsLazyWithOffset, + totalNumberOfRecordsToVirtualizeCallbackState, + loadRecordsToVirtualRows, + upsertRecordsInStore, + lastScrollPositionCallbackState, + scrollWrapperHTMLElement, + lowDetailsActivatedCallbackState, + store, + ]); const triggerFetchPages = useDebouncedCallback( triggerFetchPagesWithoutDebounce, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerInitialRecordTableDataLoad.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerInitialRecordTableDataLoad.ts index 69dd20cc78..d323566c95 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerInitialRecordTableDataLoad.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerInitialRecordTableDataLoad.ts @@ -1,3 +1,6 @@ +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; @@ -14,22 +17,20 @@ import { useReapplyRowSelection } from '@/object-record/record-table/virtualizat import { useResetTableFocuses } from '@/object-record/record-table/virtualization/hooks/useResetTableFocuses'; import { useResetVirtualizedRowTreadmill } from '@/object-record/record-table/virtualization/hooks/useResetVirtualizedRowTreadmill'; -import { dataLoadingStatusByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector'; import { dataPagesLoadedComponentState } from '@/object-record/record-table/virtualization/states/dataPagesLoadedComponentState'; import { isInitializingVirtualTableDataLoadingComponentState } from '@/object-record/record-table/virtualization/states/isInitializingVirtualTableDataLoadingComponentState'; import { lastRealIndexSetComponentState } from '@/object-record/record-table/virtualization/states/lastRealIndexSetComponentState'; import { lastScrollPositionComponentState } from '@/object-record/record-table/virtualization/states/lastScrollPositionComponentState'; -import { recordIdByRealIndexComponentFamilySelector } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector'; import { scrollAtRealIndexComponentState } from '@/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies'; import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentFamilyCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { dataLoadingStatusByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState'; +import { recordIdByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; +import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useTriggerInitialRecordTableDataLoad = () => { @@ -41,48 +42,51 @@ export const useTriggerInitialRecordTableDataLoad = () => { useRecordIndexTableFetchMore(objectNameSingular); const isInitializingVirtualTableDataLoadingCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( isInitializingVirtualTableDataLoadingComponentState, ); - const dataPagesLoadedCallbackState = useRecoilComponentCallbackState( + const dataPagesLoadedCallbackState = useRecoilComponentStateCallbackStateV2( dataPagesLoadedComponentState, ); - const isRecordTableInitialLoadingCallbackState = - useRecoilComponentCallbackState(isRecordTableInitialLoadingComponentState); + const isRecordTableInitialLoadingAtom = + useRecoilComponentStateCallbackStateV2( + isRecordTableInitialLoadingComponentState, + recordTableId, + ); - const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackState( + const recordIndexAllRecordIdsAtom = useRecoilComponentSelectorCallbackStateV2( recordIndexAllRecordIdsComponentSelector, + recordTableId, ); - const recordIdByRealIndexCallbackSelector = - useRecoilComponentFamilyCallbackState( - recordIdByRealIndexComponentFamilySelector, + const store = useStore(); + + const recordIdByRealIndexCallbackState = + useRecoilComponentStateCallbackStateV2(recordIdByRealIndexComponentState); + + const dataLoadingStatusByRealIndexCallbackState = + useRecoilComponentStateCallbackStateV2( + dataLoadingStatusByRealIndexComponentState, ); - const dataLoadingStatusByRealIndexCallbackSelector = - useRecoilComponentFamilyCallbackState( - dataLoadingStatusByRealIndexComponentFamilySelector, - ); - - const setIsRecordTableScrolledHorizontally = useSetRecoilComponentState( + const setIsRecordTableScrolledHorizontally = useSetRecoilComponentStateV2( isRecordTableScrolledHorizontallyComponentState, ); - const setIsRecordTableScrolledVertically = useSetRecoilComponentState( + const setIsRecordTableScrolledVertically = useSetRecoilComponentStateV2( isRecordTableScrolledVerticallyComponentState, ); - const lastScrollPositionCallbackState = useRecoilComponentCallbackState( - lastScrollPositionComponentState, - ); + const lastScrollPositionCallbackState = + useRecoilComponentStateCallbackStateV2(lastScrollPositionComponentState); - const lastRealIndexSetCallbackState = useRecoilComponentCallbackState( + const lastRealIndexSetCallbackState = useRecoilComponentStateCallbackStateV2( lastRealIndexSetComponentState, ); - const scrollAtRealIndexCallbackState = useRecoilComponentCallbackState( + const scrollAtRealIndexCallbackState = useRecoilComponentStateCallbackStateV2( scrollAtRealIndexComponentState, ); @@ -98,108 +102,114 @@ export const useTriggerInitialRecordTableDataLoad = () => { const { reapplyRowSelection } = useReapplyRowSelection(); const totalNumberOfRecordsToVirtualizeCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( totalNumberOfRecordsToVirtualizeComponentState, ); - const triggerInitialRecordTableDataLoad = useRecoilCallback( - ({ snapshot, set }) => - async ({ - shouldScrollToStart = true, - }: { shouldScrollToStart?: boolean } = {}) => { - const isInitializingVirtualTableDataLoading = getSnapshotValue( - snapshot, - isInitializingVirtualTableDataLoadingCallbackState, + const triggerInitialRecordTableDataLoad = useCallback( + async ({ + shouldScrollToStart = true, + }: { shouldScrollToStart?: boolean } = {}) => { + const isInitializingVirtualTableDataLoading = store.get( + isInitializingVirtualTableDataLoadingCallbackState, + ); + + if (isInitializingVirtualTableDataLoading) { + return; + } + + store.set(isInitializingVirtualTableDataLoadingCallbackState, true); + + resetTableFocuses(); + + resetVirtualizedRowTreadmill(); + + updateRecordTableCSSVariable( + RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME, + 'hidden', + ); + + updateRecordTableCSSVariable( + RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME, + 'hidden', + ); + + const currentRecordIds = store.get(recordIndexAllRecordIdsAtom); + + let records: ObjectRecord[] | null = null; + let totalCount = 0; + + if (showAuthModal) { + records = SIGN_IN_BACKGROUND_MOCK_COMPANIES; + totalCount = SIGN_IN_BACKGROUND_MOCK_COMPANIES.length; + } else { + const newRecordIdByRealIndex = new Map( + store.get(recordIdByRealIndexCallbackState), + ); + const newDataLoadingStatusByRealIndex = new Map( + store.get(dataLoadingStatusByRealIndexCallbackState), ); - if (isInitializingVirtualTableDataLoading) { - return; + for (const [realIndex] of currentRecordIds.entries()) { + newDataLoadingStatusByRealIndex.set(realIndex, 'not-loaded'); + newRecordIdByRealIndex.delete(realIndex); } - set(isInitializingVirtualTableDataLoadingCallbackState, true); - - resetTableFocuses(); - - resetVirtualizedRowTreadmill(); - - updateRecordTableCSSVariable( - RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME, - 'hidden', + store.set(recordIdByRealIndexCallbackState, newRecordIdByRealIndex); + store.set( + dataLoadingStatusByRealIndexCallbackState, + newDataLoadingStatusByRealIndex, ); - updateRecordTableCSSVariable( - RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME, - 'hidden', - ); + const { records: findManyRecords, totalCount: findManyTotalCount } = + await findManyRecordsLazy(); - const currentRecordIds = getSnapshotValue( - snapshot, - recordIndexAllRecordIdsSelector, - ); + records = findManyRecords; + totalCount = findManyTotalCount; + } - let records: ObjectRecord[] | null = null; - let totalCount = 0; + store.set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount); - if (showAuthModal) { - records = SIGN_IN_BACKGROUND_MOCK_COMPANIES; - totalCount = SIGN_IN_BACKGROUND_MOCK_COMPANIES.length; - } else { - for (const [realIndex] of currentRecordIds.entries()) { - set( - dataLoadingStatusByRealIndexCallbackSelector(realIndex), - 'not-loaded', - ); - set(recordIdByRealIndexCallbackSelector(realIndex), undefined); - } + if (isDefined(records)) { + upsertRecordsInStore({ partialRecords: records }); - const { records: findManyRecords, totalCount: findManyTotalCount } = - await findManyRecordsLazy(); + loadRecordsToVirtualRows({ + records, + startingRealIndex: 0, + }); - records = findManyRecords; - totalCount = findManyTotalCount; - } + reapplyRowSelection(); + } - set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount); + store.set(dataPagesLoadedCallbackState, []); - if (isDefined(records)) { - upsertRecordsInStore({ partialRecords: records }); + store.set(isInitializingVirtualTableDataLoadingCallbackState, false); + store.set(isRecordTableInitialLoadingAtom, false); - loadRecordsToVirtualRows({ - records, - startingRealIndex: 0, - }); + store.set(lastScrollPositionCallbackState, 0); + store.set(lastRealIndexSetCallbackState, null); + store.set(scrollAtRealIndexCallbackState, 0); - reapplyRowSelection(); - } + setIsRecordTableScrolledHorizontally(false); + setIsRecordTableScrolledVertically(false); + resetTableFocuses(); - set(dataPagesLoadedCallbackState, []); - - set(isInitializingVirtualTableDataLoadingCallbackState, false); - set(isRecordTableInitialLoadingCallbackState, false); - - set(lastScrollPositionCallbackState, 0); - set(lastRealIndexSetCallbackState, null); - set(scrollAtRealIndexCallbackState, 0); - - setIsRecordTableScrolledHorizontally(false); - setIsRecordTableScrolledVertically(false); - resetTableFocuses(); - - if (shouldScrollToStart) { - scrollTableToPosition({ - horizontalScrollInPx: 0, - verticalScrollInPx: 0, - }); - } - }, + if (shouldScrollToStart) { + scrollTableToPosition({ + horizontalScrollInPx: 0, + verticalScrollInPx: 0, + }); + } + }, [ isInitializingVirtualTableDataLoadingCallbackState, resetTableFocuses, resetVirtualizedRowTreadmill, - recordIndexAllRecordIdsSelector, + recordIndexAllRecordIdsAtom, + store, showAuthModal, dataPagesLoadedCallbackState, - isRecordTableInitialLoadingCallbackState, + isRecordTableInitialLoadingAtom, lastScrollPositionCallbackState, lastRealIndexSetCallbackState, scrollAtRealIndexCallbackState, @@ -207,8 +217,8 @@ export const useTriggerInitialRecordTableDataLoad = () => { setIsRecordTableScrolledVertically, scrollTableToPosition, findManyRecordsLazy, - dataLoadingStatusByRealIndexCallbackSelector, - recordIdByRealIndexCallbackSelector, + dataLoadingStatusByRealIndexCallbackState, + recordIdByRealIndexCallbackState, totalNumberOfRecordsToVirtualizeCallbackState, upsertRecordsInStore, loadRecordsToVirtualRows, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector.ts index a230db5338..4b9ac665a9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilySelector.ts @@ -1,12 +1,11 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { dataLoadingStatusByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; -import { type DefaultValue } from 'recoil'; +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; import { type Nullable } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const dataLoadingStatusByRealIndexComponentFamilySelector = - createComponentFamilySelector< + createComponentFamilySelectorV2< 'loaded' | 'not-loaded' | undefined, Nullable >({ @@ -18,9 +17,8 @@ export const dataLoadingStatusByRealIndexComponentFamilySelector = const realIndex = familyKey; const dataLoadingStatusByRealIndex = get( - dataLoadingStatusByRealIndexComponentState.atomFamily({ - instanceId, - }), + dataLoadingStatusByRealIndexComponentState, + { instanceId }, ); if (!isDefined(realIndex)) { @@ -31,37 +29,4 @@ export const dataLoadingStatusByRealIndexComponentFamilySelector = return dataLoadingStatus; }, - set: - ({ familyKey, instanceId }) => - ( - { get, set }, - newValue: 'loaded' | 'not-loaded' | DefaultValue | undefined, - ) => { - if (!isDefined(familyKey)) { - return; - } - - const actualDataLoadingStatusByRealIndex = get( - dataLoadingStatusByRealIndexComponentState.atomFamily({ - instanceId, - }), - ); - - const newDataLoadingStatusByRealIndex = new Map( - actualDataLoadingStatusByRealIndex, - ); - - if (newValue === 'loaded') { - newDataLoadingStatusByRealIndex.set(familyKey, 'loaded'); - } else { - newDataLoadingStatusByRealIndex.set(familyKey, 'not-loaded'); - } - - set( - dataLoadingStatusByRealIndexComponentState.atomFamily({ - instanceId, - }), - newDataLoadingStatusByRealIndex, - ); - }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState.ts index 680117d409..cbb41a9b0a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentState.ts @@ -1,10 +1,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const dataLoadingStatusByRealIndexComponentState = createComponentState< - Map ->({ - key: 'dataLoadingStatusByRealIndexComponentState', - componentInstanceContext: RecordTableComponentInstanceContext, - defaultValue: new Map(), -}); +export const dataLoadingStatusByRealIndexComponentState = + createComponentStateV2>({ + key: 'dataLoadingStatusByRealIndexComponentState', + componentInstanceContext: RecordTableComponentInstanceContext, + defaultValue: new Map(), + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataPagesLoadedComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataPagesLoadedComponentState.ts index 1c763bd1da..ac3ab0be22 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataPagesLoadedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/dataPagesLoadedComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const dataPagesLoadedComponentState = createComponentState({ +export const dataPagesLoadedComponentState = createComponentStateV2({ key: 'dataPagesLoadedComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: [], diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/isInitializingVirtualTableDataLoadingComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/isInitializingVirtualTableDataLoadingComponentState.ts index 80bfb09957..8c2987d870 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/isInitializingVirtualTableDataLoadingComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/isInitializingVirtualTableDataLoadingComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isInitializingVirtualTableDataLoadingComponentState = - createComponentState({ + createComponentStateV2({ key: 'isInitializingVirtualTableDataLoadingComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: false, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedViewIdComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedViewIdComponentState.ts index 5fd4ed4981..b07968c730 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedViewIdComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedViewIdComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const lastContextStoreVirtualizedViewIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'lastContextStoreVirtualizedViewIdComponentState', componentInstanceContext: ContextStoreComponentInstanceContext, defaultValue: null, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedVisibleRecordFieldsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedVisibleRecordFieldsComponentState.ts index 12951af4a3..06446fa023 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedVisibleRecordFieldsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastContextStoreVirtualizedVisibleRecordFieldsComponentState.ts @@ -1,9 +1,9 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const lastContextStoreVirtualizedVisibleRecordFieldsComponentState = - createComponentState({ + createComponentStateV2({ key: 'lastContextStoreVirtualizedVisibleRecordFieldsComponentState', componentInstanceContext: ContextStoreComponentInstanceContext, defaultValue: null, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastProcessedFieldMetadataUpdateIdComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastProcessedFieldMetadataUpdateIdComponentState.ts index 21fd890a75..21a67abe4f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastProcessedFieldMetadataUpdateIdComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastProcessedFieldMetadataUpdateIdComponentState.ts @@ -1,8 +1,8 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const lastProcessedFieldMetadataUpdateIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'lastProcessedFieldMetadataUpdateIdComponentState', componentInstanceContext: ContextStoreComponentInstanceContext, defaultValue: null, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRealIndexSetComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRealIndexSetComponentState.ts index faa2e21c53..fb1d6e6c0a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRealIndexSetComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRealIndexSetComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const lastRealIndexSetComponentState = createComponentState< +export const lastRealIndexSetComponentState = createComponentStateV2< number | null >({ key: 'lastRealIndexSetComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRecordTableQueryIdentifierComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRecordTableQueryIdentifierComponentState.ts index 9ade277ba4..5a0ac360db 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRecordTableQueryIdentifierComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastRecordTableQueryIdentifierComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const lastRecordTableQueryIdentifierComponentState = - createComponentState({ + createComponentStateV2({ key: 'lastRecordTableQueryIdentifierComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: '', diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollMeasurementsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollMeasurementsComponentState.ts index 8b1c80c761..78c17a6ebb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollMeasurementsComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollMeasurementsComponentState.ts @@ -1,12 +1,12 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export type ScrollMeasurement = { scrollToTop: number; timestamp: number; }; -export const lastScrollMeasurementsComponentState = createComponentState< +export const lastScrollMeasurementsComponentState = createComponentStateV2< ScrollMeasurement[] >({ key: 'lastScrollMeasurementsComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollPositionComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollPositionComponentState.ts index 490e0bcaf0..3fd988e067 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollPositionComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lastScrollPositionComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const lastScrollPositionComponentState = createComponentState({ +export const lastScrollPositionComponentState = createComponentStateV2({ key: 'lastScrollPositionComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: 0, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lowDetailsActivatedComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lowDetailsActivatedComponentState.ts index 9ca899983c..09a3ae3e73 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lowDetailsActivatedComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/lowDetailsActivatedComponentState.ts @@ -1,8 +1,9 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const lowDetailsActivatedComponentState = createComponentState({ - key: 'lowDetailsActivatedComponentState', - componentInstanceContext: RecordTableComponentInstanceContext, - defaultValue: false, -}); +export const lowDetailsActivatedComponentState = + createComponentStateV2({ + key: 'lowDetailsActivatedComponentState', + componentInstanceContext: RecordTableComponentInstanceContext, + defaultValue: false, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState.ts index f24c4e22ee..3149a0a0f2 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/realIndexByVirtualIndexComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const realIndexByVirtualIndexComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'realIndexByVirtualIndexComponentFamilyState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: null, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector.ts index f48c5b3fe4..9414c6b2b4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilySelector.ts @@ -1,13 +1,11 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { recordIdByRealIndexComponentState } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState'; -import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; -import { isNonEmptyString } from '@sniptt/guards'; -import { type DefaultValue } from 'recoil'; +import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2'; import { type Nullable } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const recordIdByRealIndexComponentFamilySelector = - createComponentFamilySelector, Nullable>({ + createComponentFamilySelectorV2, Nullable>({ key: 'recordIdByRealIndexComponentFamilySelector', componentInstanceContext: RecordTableComponentInstanceContext, get: @@ -15,11 +13,9 @@ export const recordIdByRealIndexComponentFamilySelector = ({ get }) => { const realIndex = familyKey; - const recordIdByRealIndex = get( - recordIdByRealIndexComponentState.atomFamily({ - instanceId, - }), - ); + const recordIdByRealIndex = get(recordIdByRealIndexComponentState, { + instanceId, + }); if (!isDefined(realIndex)) { return null; @@ -29,30 +25,4 @@ export const recordIdByRealIndexComponentFamilySelector = return recordId; }, - set: - ({ familyKey, instanceId }) => - ({ get, set }, newValue: Nullable | DefaultValue) => { - if (!isDefined(familyKey)) { - return; - } - - const actualRecordIdByRealIndex = get( - recordIdByRealIndexComponentState.atomFamily({ - instanceId, - }), - ); - - const newRecordIdByRealIndex = new Map(actualRecordIdByRealIndex); - - if (isNonEmptyString(newValue)) { - newRecordIdByRealIndex.set(familyKey, newValue); - } else { - newRecordIdByRealIndex.delete(familyKey); - } - - set( - recordIdByRealIndexComponentState.atomFamily({ instanceId }), - newRecordIdByRealIndex, - ); - }, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState.ts index ad0de49189..eb31f1525a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/recordIdByRealIndexComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const recordIdByRealIndexComponentState = createComponentState< +export const recordIdByRealIndexComponentState = createComponentStateV2< Map >({ key: 'recordIdByRealIndexComponentState', diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState.ts index a5adedbf88..835f797ac4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState.ts @@ -1,7 +1,7 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const scrollAtRealIndexComponentState = createComponentState({ +export const scrollAtRealIndexComponentState = createComponentStateV2({ key: 'scrollAtRealIndexComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: 0, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/tableHasAnyFilterOrSortComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/tableHasAnyFilterOrSortComponentSelector.ts index 674b6118f1..963ac6f22a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/tableHasAnyFilterOrSortComponentSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/tableHasAnyFilterOrSortComponentSelector.ts @@ -1,22 +1,22 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; export const tableHasAnyFilterOrSortComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'tableHasAnyFilterOrSortComponentSelector', componentInstanceContext: RecordTableComponentInstanceContext, get: ({ instanceId }) => ({ get }) => { - const currentRecordFilters = get( - currentRecordFiltersComponentState.atomFamily({ instanceId }), - ); + const currentRecordFilters = get(currentRecordFiltersComponentState, { + instanceId, + }); - const currentRecordSorts = get( - currentRecordSortsComponentState.atomFamily({ instanceId }), - ); + const currentRecordSorts = get(currentRecordSortsComponentState, { + instanceId, + }); const tableHasAnyFilterOrSort = currentRecordFilters.length > 0 || currentRecordSorts.length > 0; diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState.ts index caacc259fe..63ac311018 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState.ts @@ -1,8 +1,8 @@ import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const totalNumberOfRecordsToVirtualizeComponentState = - createComponentState({ + createComponentStateV2({ key: 'totalNumberOfRecordsToVirtualizeComponentState', componentInstanceContext: RecordTableComponentInstanceContext, defaultValue: null, diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCell.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCell.tsx index cc58bf105c..9c2cb8d9d8 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCell.tsx @@ -22,7 +22,6 @@ import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useR import { RecordTitleCellComponentInstanceContext } from '@/object-record/record-title-cell/states/contexts/RecordTitleCellComponentInstanceContext'; import { type RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; -import { useRecoilCallback } from 'recoil'; type RecordTitleCellProps = { loading?: boolean; @@ -68,15 +67,14 @@ export const RecordTitleCell = ({ closeCell(); }; - const handleClickOutside: FieldInputClickOutsideEvent = useRecoilCallback( - () => - ({ newValue, skipPersist }) => { - if (skipPersist !== true) { - persistFieldFromFieldInputContext(newValue); - } + const handleClickOutside: FieldInputClickOutsideEvent = useCallback( + ({ newValue, skipPersist }) => { + if (skipPersist !== true) { + persistFieldFromFieldInputContext(newValue); + } - closeCell(); - }, + closeCell(); + }, [closeCell, persistFieldFromFieldInputContext], ); diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellContainer.tsx index 05d438c86f..2210d23479 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellContainer.tsx @@ -1,6 +1,6 @@ import { RecordTitleCellContext } from '@/object-record/record-title-cell/components/RecordTitleCellContext'; import { isTitleCellInEditModeComponentState } from '@/object-record/record-title-cell/states/isTitleCellInEditModeComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -9,7 +9,7 @@ export const RecordTitleCellContainer = () => { RecordTitleCellContext, ); - const isTitleCellInEditMode = useRecoilComponentValue( + const isTitleCellInEditMode = useRecoilComponentValueV2( isTitleCellInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx index 2647b463ee..5ddbe5b0ae 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx @@ -1,5 +1,6 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useRecordTitleCell } from '@/object-record/record-title-cell/hooks/useRecordTitleCell'; import { type RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; @@ -7,7 +8,6 @@ import { withTheme, type Theme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; const StyledDiv = styled.div` @@ -39,7 +39,7 @@ export const RecordTitleCellSingleTextDisplayMode = ({ }) => { const { recordId, fieldDefinition } = useContext(FieldContext); - const recordValue = useRecoilValue(recordStoreFamilyState(recordId)); + const recordValue = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const isEmpty = recordValue?.[fieldDefinition.metadata.fieldName]?.trim() === ''; diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellUuidFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellUuidFieldDisplay.tsx index a294fcde59..e9ac4aa845 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellUuidFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellUuidFieldDisplay.tsx @@ -1,9 +1,9 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { type RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType'; import styled from '@emotion/styled'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; const StyledDiv = styled.div` @@ -27,7 +27,7 @@ export const RecordTitleCellUuidFieldDisplay = ({ }) => { const { recordId, fieldDefinition } = useContext(FieldContext); - const recordValue = useRecoilValue(recordStoreFamilyState(recordId)); + const recordValue = useFamilyRecoilValueV2(recordStoreFamilyState, recordId); const uuidValue = recordValue?.[fieldDefinition.metadata.fieldName] ?? ''; diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useOpenNewRecordTitleCell.ts b/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useOpenNewRecordTitleCell.ts index 98c3a92a95..5e1f518e95 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useOpenNewRecordTitleCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useOpenNewRecordTitleCell.ts @@ -3,40 +3,41 @@ import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/ import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useOpenNewRecordTitleCell = () => { const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); + const store = useStore(); - const openNewRecordTitleCell = useRecoilCallback( - ({ set }) => - ({ recordId, fieldName }: { recordId: string; fieldName: string }) => { - const instanceId = getRecordFieldInputInstanceId({ - recordId, - fieldName, - prefix: RecordTitleCellContainerType.PageHeader, - }); + const openNewRecordTitleCell = useCallback( + ({ recordId, fieldName }: { recordId: string; fieldName: string }) => { + const instanceId = getRecordFieldInputInstanceId({ + recordId, + fieldName, + prefix: RecordTitleCellContainerType.PageHeader, + }); - pushFocusItemToFocusStack({ - focusId: instanceId, - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, - instanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - enableGlobalHotkeysWithModifiers: false, - }, - }); + pushFocusItemToFocusStack({ + focusId: instanceId, + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + enableGlobalHotkeysWithModifiers: false, + }, + }); - set( - isTitleCellInEditModeComponentState.atomFamily({ - instanceId, - }), - true, - ); - }, - [pushFocusItemToFocusStack], + store.set( + isTitleCellInEditModeComponentState.atomFamily({ + instanceId, + }), + true, + ); + }, + [pushFocusItemToFocusStack, store], ); return { openNewRecordTitleCell }; diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx index 8e69a8a20b..7d119c3154 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx @@ -8,7 +8,8 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; type OpenTitleCellFunctionParams = { @@ -32,92 +33,94 @@ export const useRecordTitleCell = () => { const { getFieldMetadataItemByIdOrThrow } = useGetFieldMetadataItemByIdOrThrow(); - const closeRecordTitleCell = useRecoilCallback( - ({ set }) => - (instanceIdFromProps?: string) => { - const computedInstanceId = instanceIdFromProps ?? instanceId; + const store = useStore(); - if (!isDefined(computedInstanceId)) { - throw new Error( - 'Instance ID is not defined in closeRecordTitleCell this should not happen.', - ); - } - set( - isTitleCellInEditModeComponentState.atomFamily({ - instanceId: computedInstanceId, - }), - false, + const closeRecordTitleCell = useCallback( + (instanceIdFromProps?: string) => { + const computedInstanceId = instanceIdFromProps ?? instanceId; + + if (!isDefined(computedInstanceId)) { + throw new Error( + 'Instance ID is not defined in closeRecordTitleCell this should not happen.', ); + } + store.set( + isTitleCellInEditModeComponentState.atomFamily({ + instanceId: computedInstanceId, + }), + false, + ); - removeFocusItemFromFocusStackById({ - focusId: computedInstanceId, - }); + removeFocusItemFromFocusStackById({ + focusId: computedInstanceId, + }); - goBackToPreviousDropdownFocusId(); - }, + goBackToPreviousDropdownFocusId(); + }, [ goBackToPreviousDropdownFocusId, instanceId, removeFocusItemFromFocusStackById, + store, ], ); const initFieldInputDraftValue = useInitDraftValue(); - const openRecordTitleCell = useRecoilCallback( - ({ set }) => - ({ - recordId, - fieldMetadataItemId, - instanceId: instanceIdFromProps, - }: OpenTitleCellFunctionParams) => { - const computedInstanceId = instanceIdFromProps ?? instanceId; + const openRecordTitleCell = useCallback( + ({ + recordId, + fieldMetadataItemId, + instanceId: instanceIdFromProps, + }: OpenTitleCellFunctionParams) => { + const computedInstanceId = instanceIdFromProps ?? instanceId; - if (!isDefined(computedInstanceId)) { - throw new Error( - 'Instance ID is not defined in openRecordTitleCell this should not happen.', - ); - } - - pushFocusItemToFocusStack({ - focusId: computedInstanceId, - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, - instanceId: computedInstanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - enableGlobalHotkeysWithModifiers: false, - }, - }); - - set( - isTitleCellInEditModeComponentState.atomFamily({ - instanceId: computedInstanceId, - }), - true, + if (!isDefined(computedInstanceId)) { + throw new Error( + 'Instance ID is not defined in openRecordTitleCell this should not happen.', ); + } - const { fieldMetadataItem, objectMetadataItem } = - getFieldMetadataItemByIdOrThrow(fieldMetadataItemId); + pushFocusItemToFocusStack({ + focusId: computedInstanceId, + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId: computedInstanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + enableGlobalHotkeysWithModifiers: false, + }, + }); - const fieldDefinition = formatFieldMetadataItemAsColumnDefinition({ - field: fieldMetadataItem, - objectMetadataItem, - position: 0, - }); + store.set( + isTitleCellInEditModeComponentState.atomFamily({ + instanceId: computedInstanceId, + }), + true, + ); - initFieldInputDraftValue({ - recordId, - fieldDefinition, - fieldComponentInstanceId: computedInstanceId, - }); - }, + const { fieldMetadataItem, objectMetadataItem } = + getFieldMetadataItemByIdOrThrow(fieldMetadataItemId); + + const fieldDefinition = formatFieldMetadataItemAsColumnDefinition({ + field: fieldMetadataItem, + objectMetadataItem, + position: 0, + }); + + initFieldInputDraftValue({ + recordId, + fieldDefinition, + fieldComponentInstanceId: computedInstanceId, + }); + }, [ instanceId, pushFocusItemToFocusStack, initFieldInputDraftValue, getFieldMetadataItemByIdOrThrow, + store, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/states/isTitleCellInEditModeComponentState.ts b/packages/twenty-front/src/modules/object-record/record-title-cell/states/isTitleCellInEditModeComponentState.ts index 67422b1e94..0732c92c92 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/states/isTitleCellInEditModeComponentState.ts +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/states/isTitleCellInEditModeComponentState.ts @@ -1,8 +1,8 @@ import { RecordTitleCellComponentInstanceContext } from '@/object-record/record-title-cell/states/contexts/RecordTitleCellComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isTitleCellInEditModeComponentState = - createComponentState({ + createComponentStateV2({ key: 'isTitleCellInEditModeComponentState', defaultValue: false, componentInstanceContext: RecordTitleCellComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/__tests__/useUpdateMultipleRecordsActions.test.ts b/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/__tests__/useUpdateMultipleRecordsActions.test.ts index dee7819d6b..083d8f7ce0 100644 --- a/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/__tests__/useUpdateMultipleRecordsActions.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/__tests__/useUpdateMultipleRecordsActions.test.ts @@ -1,7 +1,7 @@ import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { useIncrementalUpdateManyRecords } from '@/object-record/hooks/useIncrementalUpdateManyRecords'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { renderHook } from '@testing-library/react'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; @@ -11,7 +11,7 @@ jest.mock('@/context-store/utils/computeContextStoreFilters'); jest.mock('@/object-record/hooks/useIncrementalUpdateManyRecords'); jest.mock('@/object-record/record-filter/hooks/useFilterValueDependencies'); jest.mock('@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'); -jest.mock('@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'); +jest.mock('@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'); const mockComputeContextStoreFilters = jest.mocked(computeContextStoreFilters); const mockUseIncrementalUpdateManyRecords = jest.mocked( @@ -21,7 +21,7 @@ const mockUseFilterValueDependencies = jest.mocked(useFilterValueDependencies); const mockUseContextStoreObjectMetadataItemOrThrow = jest.mocked( useContextStoreObjectMetadataItemOrThrow, ); -const mockUseRecoilComponentValue = jest.mocked(useRecoilComponentValue); +const mockUseRecoilComponentValueV2 = jest.mocked(useRecoilComponentValueV2); describe('useUpdateMultipleRecordsActions', () => { const mockIncrementalUpdateManyRecords = jest.fn(); @@ -45,7 +45,7 @@ describe('useUpdateMultipleRecordsActions', () => { filterValueDependencies: {}, } as any); - mockUseRecoilComponentValue.mockReturnValue({}); + mockUseRecoilComponentValueV2.mockReturnValue({}); mockComputeContextStoreFilters.mockReturnValue('mock-filter' as any); }); diff --git a/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/useUpdateMultipleRecordsActions.ts b/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/useUpdateMultipleRecordsActions.ts index cd4e99e70d..e8845ca589 100644 --- a/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/useUpdateMultipleRecordsActions.ts +++ b/packages/twenty-front/src/modules/object-record/record-update-multiple/hooks/useUpdateMultipleRecordsActions.ts @@ -6,7 +6,7 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { useIncrementalUpdateManyRecords } from '@/object-record/hooks/useIncrementalUpdateManyRecords'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; type UseUpdateMultipleRecordsActionsProps = { objectNameSingular: string; @@ -21,22 +21,22 @@ export const useUpdateMultipleRecordsActions = ({ contextStoreInstanceId, ); - const contextStoreTargetedRecordsRule = useRecoilComponentValue( + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, contextStoreInstanceId, ); - const contextStoreFilters = useRecoilComponentValue( + const contextStoreFilters = useRecoilComponentValueV2( contextStoreFiltersComponentState, contextStoreInstanceId, ); - const contextStoreFilterGroups = useRecoilComponentValue( + const contextStoreFilterGroups = useRecoilComponentValueV2( contextStoreFilterGroupsComponentState, contextStoreInstanceId, ); - const contextStoreAnyFieldFilterValue = useRecoilComponentValue( + const contextStoreAnyFieldFilterValue = useRecoilComponentValueV2( contextStoreAnyFieldFilterValueComponentState, contextStoreInstanceId, ); diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreadsheetImportDialog.test.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreadsheetImportDialog.test.ts index 29076df8a8..669f55523d 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreadsheetImportDialog.test.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/__tests__/useOpenObjectRecordsSpreadsheetImportDialog.test.ts @@ -1,11 +1,11 @@ import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { useRecoilValue } from 'recoil'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; import { useOpenObjectRecordsSpreadsheetImportDialog } from '@/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreadsheetImportDialog'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import gql from 'graphql-tag'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; @@ -79,34 +79,29 @@ describe('useOpenObjectRecordsSpreadsheetImportDialog', () => { it('should open dialog and configure onSubmit function correctly', async () => { const { result } = renderHook( () => { - const spreadsheetImportDialog = useRecoilValue( - spreadsheetImportDialogState, - ); const { openObjectRecordsSpreadsheetImportDialog } = useOpenObjectRecordsSpreadsheetImportDialog( CoreObjectNameSingular.Company, ); return { openObjectRecordsSpreadsheetImportDialog, - spreadsheetImportDialog, }; }, { wrapper: Wrapper }, ); - const { - spreadsheetImportDialog, - openObjectRecordsSpreadsheetImportDialog, - } = result.current; + const spreadsheetImportDialog = jotaiStore.get( + spreadsheetImportDialogState.atom, + ); expect(spreadsheetImportDialog.isOpen).toBe(false); expect(spreadsheetImportDialog.options).toBeNull(); await act(async () => { - openObjectRecordsSpreadsheetImportDialog(); + result.current.openObjectRecordsSpreadsheetImportDialog(); }); - const { spreadsheetImportDialog: dialogAfterOpen } = result.current; + const dialogAfterOpen = jotaiStore.get(spreadsheetImportDialogState.atom); expect(dialogAfterOpen.isOpen).toBe(true); expect(dialogAfterOpen.options).toHaveProperty('onSubmit'); @@ -120,16 +115,12 @@ describe('useOpenObjectRecordsSpreadsheetImportDialog', () => { it('should call batchCreateManyRecords when onSubmit is executed', async () => { const { result } = renderHook( () => { - const spreadsheetImportDialog = useRecoilValue( - spreadsheetImportDialogState, - ); const { openObjectRecordsSpreadsheetImportDialog } = useOpenObjectRecordsSpreadsheetImportDialog( CoreObjectNameSingular.Company, ); return { openObjectRecordsSpreadsheetImportDialog, - spreadsheetImportDialog, }; }, { wrapper: Wrapper }, @@ -139,7 +130,9 @@ describe('useOpenObjectRecordsSpreadsheetImportDialog', () => { result.current.openObjectRecordsSpreadsheetImportDialog(); }); - const { spreadsheetImportDialog } = result.current; + const spreadsheetImportDialog = jotaiStore.get( + spreadsheetImportDialogState.atom, + ); const submitData = { validStructuredRows: [ diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreadsheetImportDialog.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreadsheetImportDialog.ts index 7b6a9a279d..3594fcdbb4 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreadsheetImportDialog.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/hooks/useOpenObjectRecordsSpreadsheetImportDialog.ts @@ -11,7 +11,7 @@ import { useOpenSpreadsheetImportDialog } from '@/spreadsheet-import/hooks/useOp import { spreadsheetImportCreatedRecordsProgressState } from '@/spreadsheet-import/states/spreadsheetImportCreatedRecordsProgressState'; import { type SpreadsheetImportDialogOptions } from '@/spreadsheet-import/types'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; export const useOpenObjectRecordsSpreadsheetImportDialog = ( objectNameSingular: string, @@ -26,7 +26,7 @@ export const useOpenObjectRecordsSpreadsheetImportDialog = ( objectNameSingular, }); - const setCreatedRecordsProgress = useSetRecoilState( + const setCreatedRecordsProgress = useSetRecoilStateV2( spreadsheetImportCreatedRecordsProgressState, ); diff --git a/packages/twenty-front/src/modules/object-record/states/cursorFamilyState.ts b/packages/twenty-front/src/modules/object-record/states/cursorFamilyState.ts index 44fb5742cb..c347976175 100644 --- a/packages/twenty-front/src/modules/object-record/states/cursorFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/states/cursorFamilyState.ts @@ -1,6 +1,9 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const cursorFamilyState = createFamilyState({ +export const cursorFamilyState = createFamilyStateV2< + string, + string | undefined +>({ key: 'cursorFamilyState', defaultValue: '', }); diff --git a/packages/twenty-front/src/modules/object-record/states/hasNextPageFamilyState.ts b/packages/twenty-front/src/modules/object-record/states/hasNextPageFamilyState.ts index 2a5f9e8947..54d5192be5 100644 --- a/packages/twenty-front/src/modules/object-record/states/hasNextPageFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/states/hasNextPageFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const hasNextPageFamilyState = createFamilyState< +export const hasNextPageFamilyState = createFamilyStateV2< boolean, string | undefined >({ diff --git a/packages/twenty-front/src/modules/object-record/states/isFetchingMoreRecordsFamilyState.ts b/packages/twenty-front/src/modules/object-record/states/isFetchingMoreRecordsFamilyState.ts index e254f92318..ccec150e07 100644 --- a/packages/twenty-front/src/modules/object-record/states/isFetchingMoreRecordsFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/states/isFetchingMoreRecordsFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const isFetchingMoreRecordsFamilyState = createFamilyState< +export const isFetchingMoreRecordsFamilyState = createFamilyStateV2< boolean, string | undefined >({ diff --git a/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts b/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts index 8804ff588b..90143c4825 100644 --- a/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/states/isRecordBoardColumnLoadingFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const isRecordIndexBoardColumnLoadingFamilyState = createFamilyState< +export const isRecordIndexBoardColumnLoadingFamilyState = createFamilyStateV2< boolean, string | undefined >({ diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx index 9369d78af0..7676eb3dd9 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx @@ -7,14 +7,14 @@ import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageL import { usePageLayoutTabWithVisibleWidgetsOrThrow } from '@/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow'; import { useReorderPageLayoutWidgets } from '@/page-layout/hooks/useReorderPageLayoutWidgets'; import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { PageLayoutTabLayoutMode, PageLayoutType, } from '~/generated-metadata/graphql'; export const PageLayoutContent = () => { - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx index 033f7c29c9..d669fcc5ae 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx @@ -24,8 +24,8 @@ import { filterPendingPlaceholderFromLayouts } from '@/page-layout/utils/filterP import { prepareGridLayoutItemsWithPlaceholders } from '@/page-layout/utils/prepareGridLayoutItemsWithPlaceholders'; import { WidgetPlaceholder } from '@/page-layout/widgets/components/WidgetPlaceholder'; import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { useMemo, useRef } from 'react'; @@ -100,15 +100,15 @@ type PageLayoutGridLayoutProps = { }; export const PageLayoutGridLayout = ({ tabId }: PageLayoutGridLayoutProps) => { - const setPageLayoutCurrentBreakpoint = useSetRecoilComponentState( + const setPageLayoutCurrentBreakpoint = useSetRecoilComponentStateV2( pageLayoutCurrentBreakpointComponentState, ); - const setDraggingWidgetId = useSetRecoilComponentState( + const setDraggingWidgetId = useSetRecoilComponentStateV2( pageLayoutDraggingWidgetIdComponentState, ); - const setResizingWidgetId = useSetRecoilComponentState( + const setResizingWidgetId = useSetRecoilComponentStateV2( pageLayoutResizingWidgetIdComponentState, ); @@ -126,18 +126,18 @@ export const PageLayoutGridLayout = ({ tabId }: PageLayoutGridLayoutProps) => { const gridContainerRef = useRef(null); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); - const pageLayoutCurrentLayouts = useRecoilComponentValue( + const pageLayoutCurrentLayouts = useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, ); - const pageLayoutDraggedArea = useRecoilComponentValue( + const pageLayoutDraggedArea = useRecoilComponentValueV2( pageLayoutDraggedAreaComponentState, ); - const draggingWidgetId = useRecoilComponentValue( + const draggingWidgetId = useRecoilComponentValueV2( pageLayoutDraggingWidgetIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx index 8b07e73310..480c15d0a4 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx @@ -8,7 +8,6 @@ import { calculateGridCellPosition } from '@/page-layout/utils/calculateGridCell import { calculateTotalGridRows } from '@/page-layout/utils/calculateTotalGridRows'; import { generateCellId } from '@/page-layout/utils/generateCellId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { useMemo } from 'react'; @@ -49,15 +48,15 @@ const StyledGridCell = styled.div<{ isSelected?: boolean }>` `; export const PageLayoutGridOverlay = () => { - const pageLayoutCurrentBreakpoint = useRecoilComponentValue( + const pageLayoutCurrentBreakpoint = useRecoilComponentValueV2( pageLayoutCurrentBreakpointComponentState, ); - const pageLayoutSelectedCells = useRecoilComponentValue( + const pageLayoutSelectedCells = useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, ); - const pageLayoutCurrentLayouts = useRecoilComponentValue( + const pageLayoutCurrentLayouts = useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx index 928e8e0092..ae868c2210 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx @@ -6,11 +6,10 @@ import { pageLayoutIsInitializedComponentState } from '@/page-layout/states/page import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; import { type PageLayout } from '@/page-layout/types/PageLayout'; import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useStore } from 'jotai'; +import { useCallback, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -23,7 +22,7 @@ export const PageLayoutInitializationQueryEffect = ({ pageLayoutId, onInitialized, }: PageLayoutInitializationQueryEffectProps) => { - const [isInitialized, setIsInitialized] = useRecoilComponentState( + const [isInitialized, setIsInitialized] = useRecoilComponentStateV2( pageLayoutIsInitializedComponentState, ); @@ -32,41 +31,43 @@ export const PageLayoutInitializationQueryEffect = ({ const pageLayout = usePageLayoutWithRelationWidgets(basePageLayout); const pageLayoutPersistedComponentCallbackState = - useRecoilComponentCallbackState(pageLayoutPersistedComponentState); + useRecoilComponentStateCallbackStateV2(pageLayoutPersistedComponentState); - const pageLayoutDraftComponentCallbackState = useRecoilComponentCallbackState( - pageLayoutDraftComponentState, - ); + const pageLayoutDraftComponentCallbackState = + useRecoilComponentStateCallbackStateV2(pageLayoutDraftComponentState); const pageLayoutCurrentLayoutsComponentCallbackState = - useRecoilComponentCallbackState(pageLayoutCurrentLayoutsComponentState); + useRecoilComponentStateCallbackStateV2( + pageLayoutCurrentLayoutsComponentState, + ); - const initializePageLayout = useRecoilCallback( - ({ set, snapshot }) => - (layout: PageLayout) => { - const currentPersisted = getSnapshotValue( - snapshot, - pageLayoutPersistedComponentCallbackState, - ); + const store = useStore(); - if (!isDeeplyEqual(layout, currentPersisted)) { - set(pageLayoutPersistedComponentCallbackState, layout); - set(pageLayoutDraftComponentCallbackState, { - id: layout.id, - name: layout.name, - type: layout.type, - objectMetadataId: layout.objectMetadataId, - tabs: layout.tabs, - }); + const initializePageLayout = useCallback( + (layout: PageLayout) => { + const currentPersisted = store.get( + pageLayoutPersistedComponentCallbackState, + ); - const tabLayouts = convertPageLayoutToTabLayouts(layout); - set(pageLayoutCurrentLayoutsComponentCallbackState, tabLayouts); - } - }, + if (!isDeeplyEqual(layout, currentPersisted)) { + store.set(pageLayoutPersistedComponentCallbackState, layout); + store.set(pageLayoutDraftComponentCallbackState, { + id: layout.id, + name: layout.name, + type: layout.type, + objectMetadataId: layout.objectMetadataId, + tabs: layout.tabs, + }); + + const tabLayouts = convertPageLayoutToTabLayouts(layout); + store.set(pageLayoutCurrentLayoutsComponentCallbackState, tabLayouts); + } + }, [ pageLayoutCurrentLayoutsComponentCallbackState, pageLayoutDraftComponentCallbackState, pageLayoutPersistedComponentCallbackState, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx index e2a020949d..aac9ea256d 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx @@ -8,11 +8,10 @@ import { type PageLayout } from '@/page-layout/types/PageLayout'; import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts'; import { injectRelationWidgetsIntoLayout } from '@/page-layout/utils/injectRelationWidgetsIntoLayout'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useStore } from 'jotai'; +import { useCallback, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { PageLayoutType } from '~/generated-metadata/graphql'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -26,7 +25,7 @@ export const PageLayoutRelationWidgetsSyncEffect = ({ }: PageLayoutRelationWidgetsSyncEffectProps) => { const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext(); - const isInitialized = useRecoilComponentValue( + const isInitialized = useRecoilComponentValueV2( pageLayoutIsInitializedComponentState, ); @@ -37,41 +36,43 @@ export const PageLayoutRelationWidgetsSyncEffect = ({ }); const pageLayoutPersistedComponentCallbackState = - useRecoilComponentCallbackState(pageLayoutPersistedComponentState); + useRecoilComponentStateCallbackStateV2(pageLayoutPersistedComponentState); - const pageLayoutDraftComponentCallbackState = useRecoilComponentCallbackState( - pageLayoutDraftComponentState, - ); + const pageLayoutDraftComponentCallbackState = + useRecoilComponentStateCallbackStateV2(pageLayoutDraftComponentState); const pageLayoutCurrentLayoutsComponentCallbackState = - useRecoilComponentCallbackState(pageLayoutCurrentLayoutsComponentState); + useRecoilComponentStateCallbackStateV2( + pageLayoutCurrentLayoutsComponentState, + ); - const syncPageLayoutWithRelationWidgets = useRecoilCallback( - ({ set, snapshot }) => - (layout: PageLayout) => { - const currentPersisted = getSnapshotValue( - snapshot, - pageLayoutPersistedComponentCallbackState, - ); + const store = useStore(); - if (!isDeeplyEqual(layout, currentPersisted)) { - set(pageLayoutPersistedComponentCallbackState, layout); - set(pageLayoutDraftComponentCallbackState, { - id: layout.id, - name: layout.name, - type: layout.type, - objectMetadataId: layout.objectMetadataId, - tabs: layout.tabs, - }); + const syncPageLayoutWithRelationWidgets = useCallback( + (layout: PageLayout) => { + const currentPersisted = store.get( + pageLayoutPersistedComponentCallbackState, + ); - const tabLayouts = convertPageLayoutToTabLayouts(layout); - set(pageLayoutCurrentLayoutsComponentCallbackState, tabLayouts); - } - }, + if (!isDeeplyEqual(layout, currentPersisted)) { + store.set(pageLayoutPersistedComponentCallbackState, layout); + store.set(pageLayoutDraftComponentCallbackState, { + id: layout.id, + name: layout.name, + type: layout.type, + objectMetadataId: layout.objectMetadataId, + tabs: layout.tabs, + }); + + const tabLayouts = convertPageLayoutToTabLayouts(layout); + store.set(pageLayoutCurrentLayoutsComponentCallbackState, tabLayouts); + } + }, [ pageLayoutCurrentLayoutsComponentCallbackState, pageLayoutDraftComponentCallbackState, pageLayoutPersistedComponentCallbackState, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx index 81145e8359..fdd337efb6 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx @@ -18,8 +18,7 @@ import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -56,7 +55,7 @@ export const PageLayoutRendererContent = () => { const { isInRightDrawer, layoutType, targetRecordIdentifier } = useLayoutRenderingContext(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); @@ -64,7 +63,7 @@ export const PageLayoutRendererContent = () => { const { createPageLayoutTab } = useCreatePageLayoutTab(currentPageLayout?.id); const { reorderTabs } = useReorderPageLayoutTabs(currentPageLayout?.id ?? ''); - const setTabSettingsOpenTabId = useSetRecoilComponentState( + const setTabSettingsOpenTabId = useSetRecoilComponentStateV2( pageLayoutTabSettingsOpenTabIdComponentState, ); const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu(); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx index 7848fc7147..0e91af5c9f 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx @@ -24,7 +24,7 @@ import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/con import { type TabListProps } from '@/ui/layout/tab-list/types/TabListProps'; import { NodeDimension } from '@/ui/utilities/dimensions/components/NodeDimension'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu'; @@ -43,7 +43,7 @@ import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnable import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab-list/components/TabListFromUrlOptionalEffect'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { type PageLayoutType } from '~/generated-metadata/graphql'; @@ -134,12 +134,16 @@ export const PageLayoutTabList = ({ hasAddButton: isDefined(onAddTab), }); + const pageLayoutId = useAvailableComponentInstanceIdOrThrow( + PageLayoutComponentInstanceContext, + ); + const dropdownId = `tab-overflow-${componentInstanceId}`; const { closeDropdown } = useCloseDropdown(); const { openDropdown } = useOpenDropdown(); const { toggleClickOutside } = useClickOutsideListener(dropdownId); - const setIsTabDragging = useSetRecoilComponentState( + const setIsTabDragging = useSetRecoilComponentStateV2( isPageLayoutTabDraggingComponentState, componentInstanceId, ); @@ -174,9 +178,11 @@ export const PageLayoutTabList = ({ closeDropdown(dropdownId); }, [closeDropdown, dropdownId]); - const setPageLayoutTabListCurrentDragDroppableId = useSetRecoilComponentState( - pageLayoutTabListCurrentDragDroppableIdComponentState, - ); + const setPageLayoutTabListCurrentDragDroppableId = + useSetRecoilComponentStateV2( + pageLayoutTabListCurrentDragDroppableIdComponentState, + pageLayoutId, + ); const handleDragUpdate: OnDragUpdateResponder = (update) => { setPageLayoutTabListCurrentDragDroppableId(update.destination?.droppableId); @@ -214,17 +220,15 @@ export const PageLayoutTabList = ({ [onReorder, setIsTabDragging, toggleClickOutside, openDropdown, dropdownId], ); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, + pageLayoutId, ); - const pageLayoutId = useAvailableComponentInstanceIdOrThrow( - PageLayoutComponentInstanceContext, - ); - const tabSettingsOpenTabId = useRecoilComponentValue( + const tabSettingsOpenTabId = useRecoilComponentValueV2( pageLayoutTabSettingsOpenTabIdComponentState, pageLayoutId, ); - const setTabSettingsOpenTabId = useSetRecoilComponentState( + const setTabSettingsOpenTabId = useSetRecoilComponentStateV2( pageLayoutTabSettingsOpenTabIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx index 315cd456e3..fe18594b3f 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx @@ -25,8 +25,8 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { type PageLayoutType } from '~/generated-metadata/graphql'; @@ -73,7 +73,7 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({ PageLayoutComponentInstanceContext, ); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, pageLayoutId, ); @@ -81,17 +81,17 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({ const shouldShowEditButton = isPageLayoutInEditMode && shouldEnableTabEditingFeatures(pageLayoutType); - const isTabDragging = useRecoilComponentValue( + const isTabDragging = useRecoilComponentValueV2( isPageLayoutTabDraggingComponentState, instanceId, ); - const setIsTabDragging = useSetRecoilComponentState( + const setIsTabDragging = useSetRecoilComponentStateV2( isPageLayoutTabDraggingComponentState, instanceId, ); - const setTabSettingsOpenTabId = useSetRecoilComponentState( + const setTabSettingsOpenTabId = useSetRecoilComponentStateV2( pageLayoutTabSettingsOpenTabIdComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx index 89a49723fb..179b58a551 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx @@ -2,7 +2,7 @@ import { Draggable } from '@hello-pangea/dnd'; import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { StyledTabContainer, TabContent } from 'twenty-ui/input'; @@ -27,7 +27,7 @@ export const PageLayoutTabListReorderableTab = ({ disabled, onSelect, }: PageLayoutTabListReorderableTabProps) => { - const tabSettingsOpenTabId = useRecoilComponentValue( + const tabSettingsOpenTabId = useRecoilComponentValueV2( pageLayoutTabSettingsOpenTabIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx index bbe2803134..f0514f4af0 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx @@ -3,7 +3,7 @@ import { pageLayoutTabListCurrentDragDroppableIdComponentState } from '@/page-la import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { TabAvatar } from '@/ui/layout/tab-list/components/TabAvatar'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { type DraggableProvided } from '@hello-pangea/dnd'; @@ -30,7 +30,7 @@ export const PageLayoutTabRenderClone = ({ }) => { const theme = useTheme(); - const pageLayoutTabListCurrentDragDroppableId = useRecoilComponentValue( + const pageLayoutTabListCurrentDragDroppableId = useRecoilComponentValueV2( pageLayoutTabListCurrentDragDroppableIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx index f7a32ab378..c0ad1128d3 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx @@ -5,7 +5,7 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer'; import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { DragDropContext, @@ -61,7 +61,7 @@ export const PageLayoutVerticalListEditor = ({ isInRightDrawer, }); - const setDraggingWidgetId = useSetRecoilComponentState( + const setDraggingWidgetId = useSetRecoilComponentStateV2( pageLayoutDraggingWidgetIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx index 899f78ea8c..e84b33ad88 100644 --- a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx @@ -2,7 +2,6 @@ import styled from '@emotion/styled'; import { type DropResult, type ResponderProvided } from '@hello-pangea/dnd'; import type { Meta, StoryObj } from '@storybook/react-vite'; import { useMemo, useState } from 'react'; -import { RecoilRoot } from 'recoil'; import { ComponentWithRouterDecorator } from 'twenty-ui/testing'; import { PageLayoutTabList } from '@/page-layout/components/PageLayoutTabList'; @@ -183,13 +182,11 @@ const meta: Meta = { decorators: [ ComponentWithRouterDecorator, (Story) => ( - - - - - + + + ), ], }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/PageLayoutTestWrapper.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/PageLayoutTestWrapper.tsx index 6015d1d3b0..c17fc28650 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/PageLayoutTestWrapper.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/PageLayoutTestWrapper.tsx @@ -7,19 +7,16 @@ import { Provider as JotaiProvider, } from 'jotai'; import { type ReactNode, useState } from 'react'; -import { RecoilRoot, type MutableSnapshot } from 'recoil'; export const PAGE_LAYOUT_TEST_INSTANCE_ID = '20202020-f244-4ae0-906b-78958aa07642'; export const PageLayoutTestWrapper = ({ children, - initializeState, instanceId: instanceIdFromProps, store: storeFromProps, }: { children: ReactNode; - initializeState?: (snapshot: MutableSnapshot) => void; instanceId?: string; store?: ReturnType; }) => { @@ -35,7 +32,7 @@ export const PageLayoutTestWrapper = ({ instanceId: getTabListInstanceIdFromPageLayoutId(instanceId), }} > - {children} + {children} diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useChangePageLayoutDragSelection.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useChangePageLayoutDragSelection.test.tsx index e237a96d38..42378ce040 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useChangePageLayoutDragSelection.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useChangePageLayoutDragSelection.test.tsx @@ -1,5 +1,6 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { act, renderHook } from '@testing-library/react'; +import { createStore } from 'jotai'; import { type ReactNode } from 'react'; import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState'; import { @@ -10,28 +11,27 @@ import { useChangePageLayoutDragSelection } from '@/page-layout/hooks/useChangeP describe('useChangePageLayoutDragSelection', () => { it('should add cell to selection when selected is true', () => { + const store = createStore(); + store.set( + pageLayoutSelectedCellsComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + new Set(['cell-1']), + ); + const { result } = renderHook( () => ({ changeDragSelection: useChangePageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - { - set( - pageLayoutSelectedCellsComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - new Set(['cell-1']), - ); - }} - > + {children} ), @@ -54,28 +54,27 @@ describe('useChangePageLayoutDragSelection', () => { }); it('should remove cell from selection when selected is false', () => { + const store = createStore(); + store.set( + pageLayoutSelectedCellsComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + new Set(['cell-1', 'cell-2']), + ); + const { result } = renderHook( () => ({ changeDragSelection: useChangePageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - { - set( - pageLayoutSelectedCellsComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - new Set(['cell-1', 'cell-2']), - ); - }} - > + {children} ), @@ -103,7 +102,7 @@ describe('useChangePageLayoutDragSelection', () => { changeDragSelection: useChangePageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -133,28 +132,27 @@ describe('useChangePageLayoutDragSelection', () => { }); it('should handle removing non-existent cell', () => { + const store = createStore(); + store.set( + pageLayoutSelectedCellsComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + new Set(['cell-1']), + ); + const { result } = renderHook( () => ({ changeDragSelection: useChangePageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - { - set( - pageLayoutSelectedCellsComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - new Set(['cell-1']), - ); - }} - > + {children} ), diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx index 0bd8dfbd4c..3197b21a02 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutGraphWidget.test.tsx @@ -3,8 +3,8 @@ import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pag import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { type GraphWidgetFieldSelection } from '@/page-layout/types/GraphWidgetFieldSelection'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { act, renderHook } from '@testing-library/react'; import { useSetAtom } from 'jotai'; import { isDefined } from 'twenty-shared/utils'; @@ -35,16 +35,16 @@ describe('useCreatePageLayoutGraphWidget', () => { instanceId: `${PAGE_LAYOUT_TEST_INSTANCE_ID}-tab-list`, }), ); - const setPageLayoutDraft = useSetRecoilComponentState( + const setPageLayoutDraft = useSetRecoilComponentStateV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); - const pageLayoutDraft = useRecoilComponentValue( + const pageLayoutDraft = useRecoilComponentValueV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); const allWidgets = pageLayoutDraft.tabs.flatMap((tab) => tab.widgets); - const pageLayoutCurrentLayouts = useRecoilComponentValue( + const pageLayoutCurrentLayouts = useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); @@ -109,7 +109,7 @@ describe('useCreatePageLayoutGraphWidget', () => { it('should handle different graph types', () => { const { result } = renderHook( () => { - const setPageLayoutDraft = useSetRecoilComponentState( + const setPageLayoutDraft = useSetRecoilComponentStateV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); @@ -118,12 +118,12 @@ describe('useCreatePageLayoutGraphWidget', () => { instanceId: `${PAGE_LAYOUT_TEST_INSTANCE_ID}-tab-list`, }), ); - const pageLayoutDraft = useRecoilComponentValue( + const pageLayoutDraft = useRecoilComponentValueV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); const allWidgets = pageLayoutDraft.tabs.flatMap((tab) => tab.widgets); - const pageLayoutCurrentLayouts = useRecoilComponentValue( + const pageLayoutCurrentLayouts = useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx index 8dd37dc6ed..89fee35707 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreatePageLayoutTab.test.tsx @@ -2,9 +2,8 @@ import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutT import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { act, renderHook } from '@testing-library/react'; import { useSetAtom } from 'jotai'; import { PageLayoutType } from '~/generated-metadata/graphql'; @@ -29,11 +28,11 @@ describe('useCreatePageLayoutTab', () => { const { result } = renderHook( () => ({ createTab: useCreatePageLayoutTab(PAGE_LAYOUT_TEST_INSTANCE_ID), - pageLayoutDraft: useRecoilComponentValue( + pageLayoutDraft: useRecoilComponentValueV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), - pageLayoutCurrentLayouts: useRecoilComponentValue( + pageLayoutCurrentLayouts: useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -71,7 +70,7 @@ describe('useCreatePageLayoutTab', () => { const { result } = renderHook( () => ({ createTab: useCreatePageLayoutTab(PAGE_LAYOUT_TEST_INSTANCE_ID), - pageLayoutDraft: useRecoilComponentValue( + pageLayoutDraft: useRecoilComponentValueV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -99,7 +98,7 @@ describe('useCreatePageLayoutTab', () => { const { result } = renderHook( () => ({ createTab: useCreatePageLayoutTab(PAGE_LAYOUT_TEST_INSTANCE_ID), - pageLayoutDraft: useRecoilComponentValue( + pageLayoutDraft: useRecoilComponentValueV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -135,7 +134,7 @@ describe('useCreatePageLayoutTab', () => { const { result } = renderHook( () => ({ createTab: useCreatePageLayoutTab(PAGE_LAYOUT_TEST_INSTANCE_ID), - pageLayoutCurrentLayouts: useRecoilComponentValue( + pageLayoutCurrentLayouts: useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -204,11 +203,11 @@ describe('useCreatePageLayoutTab', () => { const { result } = renderHook( () => { - const setPageLayoutDraft = useSetRecoilComponentState( + const setPageLayoutDraft = useSetRecoilComponentStateV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); - const pageLayoutDraft = useRecoilComponentValue( + const pageLayoutDraft = useRecoilComponentValueV2( pageLayoutDraftComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreateWidgetFromClick.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreateWidgetFromClick.test.tsx index 27a7f2cfb5..1f86654861 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreateWidgetFromClick.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useCreateWidgetFromClick.test.tsx @@ -2,7 +2,7 @@ import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layo import { useCreateWidgetFromClick } from '@/page-layout/hooks/useCreateWidgetFromClick'; import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { act, renderHook } from '@testing-library/react'; import { type ReactNode } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; @@ -29,11 +29,11 @@ describe('useCreateWidgetFromClick', () => { const { result } = renderHook( () => ({ createWidget: useCreateWidgetFromClick(), - draggedArea: useRecoilComponentValue( + draggedArea: useRecoilComponentValueV2( pageLayoutDraggedAreaComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), - editingWidgetId: useRecoilComponentValue( + editingWidgetId: useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useEndPageLayoutDragSelection.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useEndPageLayoutDragSelection.test.tsx index 3a8cc94c0b..8470dc6495 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useEndPageLayoutDragSelection.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useEndPageLayoutDragSelection.test.tsx @@ -3,8 +3,9 @@ import { useEndPageLayoutDragSelection } from '@/page-layout/hooks/useEndPageLay import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState'; import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState'; import { calculateGridBoundsFromSelectedCells } from '@/page-layout/utils/calculateGridBoundsFromSelectedCells'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { act, renderHook } from '@testing-library/react'; +import { createStore } from 'jotai'; import { type ReactNode } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -18,26 +19,29 @@ jest.mock( ); jest.mock('../../utils/calculateGridBoundsFromSelectedCells'); -const createInitializeState = - (initialSelectedCells?: Set, initialDraggedArea?: any) => - ({ set }: { set: any }) => { - if (isDefined(initialSelectedCells)) { - set( - pageLayoutSelectedCellsComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - initialSelectedCells, - ); - } - if (initialDraggedArea !== undefined) { - set( - pageLayoutDraggedAreaComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - initialDraggedArea, - ); - } - }; +const createTestStore = ( + initialSelectedCells?: Set, + initialDraggedArea?: any, +) => { + const store = createStore(); + if (isDefined(initialSelectedCells)) { + store.set( + pageLayoutSelectedCellsComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + initialSelectedCells, + ); + } + if (initialDraggedArea !== undefined) { + store.set( + pageLayoutDraggedAreaComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + initialDraggedArea, + ); + } + return store; +}; describe('useEndPageLayoutDragSelection', () => { const mockNavigatePageLayoutCommandMenu = jest.fn(); @@ -55,28 +59,25 @@ describe('useEndPageLayoutDragSelection', () => { mockBounds, ); + const store = createTestStore(new Set(['0-0', '0-1', '1-0', '1-1']), null); + const { result } = renderHook( () => ({ endDragSelection: useEndPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), - draggedArea: useRecoilComponentValue( + draggedArea: useRecoilComponentValueV2( pageLayoutDraggedAreaComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), @@ -109,25 +110,25 @@ describe('useEndPageLayoutDragSelection', () => { it('should not navigate when no cells are selected', () => { (calculateGridBoundsFromSelectedCells as jest.Mock).mockReturnValue(null); + const store = createTestStore(new Set(), null); + const { result } = renderHook( () => ({ endDragSelection: useEndPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), - draggedArea: useRecoilComponentValue( + draggedArea: useRecoilComponentValueV2( pageLayoutDraggedAreaComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), @@ -147,28 +148,25 @@ describe('useEndPageLayoutDragSelection', () => { it('should not navigate when bounds calculation returns null', () => { (calculateGridBoundsFromSelectedCells as jest.Mock).mockReturnValue(null); + const store = createTestStore(new Set(['invalid-cell']), null); + const { result } = renderHook( () => ({ endDragSelection: useEndPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), - draggedArea: useRecoilComponentValue( + draggedArea: useRecoilComponentValueV2( pageLayoutDraggedAreaComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), @@ -206,21 +204,21 @@ describe('useEndPageLayoutDragSelection', () => { mockBounds, ); + const store = createTestStore(new Set(['0-0'])); + const { result } = renderHook( () => ({ endDragSelection: useEndPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), @@ -240,21 +238,21 @@ describe('useEndPageLayoutDragSelection', () => { mockBounds, ); + const store = createTestStore(new Set(['0-0'])); + const { result } = renderHook( () => ({ endDragSelection: useEndPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutHandleLayoutChange.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutHandleLayoutChange.test.tsx index 011bc78750..41e022f2b3 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutHandleLayoutChange.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutHandleLayoutChange.test.tsx @@ -1,5 +1,5 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { act, renderHook } from '@testing-library/react'; import { useSetAtom } from 'jotai'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; @@ -14,7 +14,7 @@ describe('usePageLayoutHandleLayoutChange', () => { const { result } = renderHook( () => ({ handler: usePageLayoutHandleLayoutChange(PAGE_LAYOUT_TEST_INSTANCE_ID), - layouts: useRecoilComponentValue( + layouts: useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -57,7 +57,7 @@ describe('usePageLayoutHandleLayoutChange', () => { const { result } = renderHook( () => ({ handler: usePageLayoutHandleLayoutChange(PAGE_LAYOUT_TEST_INSTANCE_ID), - layouts: useRecoilComponentValue( + layouts: useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), @@ -92,7 +92,7 @@ describe('usePageLayoutHandleLayoutChange', () => { const { result } = renderHook( () => ({ handler: usePageLayoutHandleLayoutChange(PAGE_LAYOUT_TEST_INSTANCE_ID), - layouts: useRecoilComponentValue( + layouts: useRecoilComponentValueV2( pageLayoutCurrentLayoutsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useStartPageLayoutDragSelection.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useStartPageLayoutDragSelection.test.tsx index 358bcb3aad..e95ad75e53 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useStartPageLayoutDragSelection.test.tsx +++ b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/useStartPageLayoutDragSelection.test.tsx @@ -1,5 +1,6 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { act, renderHook } from '@testing-library/react'; +import { createStore } from 'jotai'; import { type ReactNode } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState'; @@ -9,38 +10,36 @@ import { PageLayoutTestWrapper, } from './PageLayoutTestWrapper'; -const createInitializeState = - (initialSelectedCells?: Set) => - ({ set }: { set: any }) => { - if (isDefined(initialSelectedCells)) { - set( - pageLayoutSelectedCellsComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - initialSelectedCells, - ); - } - }; +const createTestStore = (initialSelectedCells?: Set) => { + const store = createStore(); + if (isDefined(initialSelectedCells)) { + store.set( + pageLayoutSelectedCellsComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + initialSelectedCells, + ); + } + return store; +}; describe('useStartPageLayoutDragSelection', () => { it('should clear selected cells when starting drag selection', () => { + const store = createTestStore(new Set(['cell-1', 'cell-2'])); + const { result } = renderHook( () => ({ startDragSelection: useStartPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), @@ -72,21 +71,21 @@ describe('useStartPageLayoutDragSelection', () => { }); it('should handle multiple calls correctly', () => { + const store = createTestStore(new Set(['cell-1'])); + const { result } = renderHook( () => ({ startDragSelection: useStartPageLayoutDragSelection( PAGE_LAYOUT_TEST_INSTANCE_ID, ), - selectedCells: useRecoilComponentValue( + selectedCells: useRecoilComponentValueV2( pageLayoutSelectedCellsComponentState, PAGE_LAYOUT_TEST_INSTANCE_ID, ), }), { wrapper: ({ children }: { children: ReactNode }) => ( - + {children} ), diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useBasePageLayout.ts b/packages/twenty-front/src/modules/page-layout/hooks/useBasePageLayout.ts index c6a83329d1..0d3d2c45ce 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useBasePageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useBasePageLayout.ts @@ -20,8 +20,8 @@ import { DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID } from '@/page-layout/constants import { recordPageLayoutFromIdFamilySelector } from '@/page-layout/states/selectors/recordPageLayoutFromIdFamilySelector'; import { type PageLayout } from '@/page-layout/types/PageLayout'; import { transformPageLayout } from '@/page-layout/utils/transformPageLayout'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useQuery } from '@apollo/client'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; const getDefaultLayoutById = (layoutId: string): PageLayout => { @@ -64,8 +64,9 @@ export const useBasePageLayout = ( ): PageLayout | undefined => { const isDefaultLayout = isDefaultLayoutId(pageLayoutId); - const cachedRecordPageLayout = useRecoilValue( - recordPageLayoutFromIdFamilySelector({ pageLayoutId }), + const cachedRecordPageLayout = useFamilySelectorValueV2( + recordPageLayoutFromIdFamilySelector, + { pageLayoutId }, ); const shouldSkipQuery = isDefaultLayout || isDefined(cachedRecordPageLayout); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useChangePageLayoutDragSelection.ts b/packages/twenty-front/src/modules/page-layout/hooks/useChangePageLayoutDragSelection.ts index 85dbf2270a..0ae9b0a72d 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useChangePageLayoutDragSelection.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useChangePageLayoutDragSelection.ts @@ -1,7 +1,8 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState'; export const useChangePageLayoutDragSelection = ( @@ -12,25 +13,26 @@ export const useChangePageLayoutDragSelection = ( pageLayoutIdFromProps, ); - const pageLayoutSelectedCellsState = useRecoilComponentCallbackState( + const pageLayoutSelectedCellsState = useRecoilComponentStateCallbackStateV2( pageLayoutSelectedCellsComponentState, pageLayoutId, ); - const changePageLayoutDragSelection = useRecoilCallback( - ({ set }) => - (cellId: string, selected: boolean) => { - set(pageLayoutSelectedCellsState, (prev) => { - const newSet = new Set(prev); - if (selected) { - newSet.add(cellId); - } else { - newSet.delete(cellId); - } - return newSet; - }); - }, - [pageLayoutSelectedCellsState], + const store = useStore(); + + const changePageLayoutDragSelection = useCallback( + (cellId: string, selected: boolean) => { + store.set(pageLayoutSelectedCellsState, (prev) => { + const newSet = new Set(prev); + if (selected) { + newSet.add(cellId); + } else { + newSet.delete(cellId); + } + return newSet; + }); + }, + [pageLayoutSelectedCellsState, store], ); return { changePageLayoutDragSelection }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutFrontComponentWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutFrontComponentWidget.ts index 989c0b986d..eb54473879 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutFrontComponentWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutFrontComponentWidget.ts @@ -11,9 +11,10 @@ import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTab import { getUpdatedTabLayouts } from '@/page-layout/utils/getUpdatedTabLayouts'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 as uuidv4 } from 'uuid'; import { WidgetType } from '~/generated-metadata/graphql'; @@ -31,93 +32,91 @@ export const useCreatePageLayoutFrontComponentWidget = ( getTabListInstanceIdFromPageLayoutId(pageLayoutId), ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, pageLayoutId, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const createPageLayoutFrontComponentWidget = useRecoilCallback( - ({ snapshot, set }) => - (title: string, frontComponentId: string): PageLayoutWidget => { - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const store = useStore(); - const pageLayoutDraggedArea = snapshot - .getLoadable(pageLayoutDraggedAreaState) - .getValue(); + const createPageLayoutFrontComponentWidget = useCallback( + (title: string, frontComponentId: string): PageLayoutWidget => { + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); - if (!isDefined(activeTabId)) { - throw new Error( - 'A tab must be selected to create a new front component widget', - ); - } + const pageLayoutDraggedArea = store.get(pageLayoutDraggedAreaState); - const widgetId = uuidv4(); - const frontComponentSize = WIDGET_SIZES[WidgetType.FRONT_COMPONENT]!; - const defaultSize = frontComponentSize.default; - const minimumSize = frontComponentSize.minimum; - const position = getDefaultWidgetPosition( - pageLayoutDraggedArea, - defaultSize, - minimumSize, + if (!isDefined(activeTabId)) { + throw new Error( + 'A tab must be selected to create a new front component widget', ); + } - const newWidget = createDefaultFrontComponentWidget( - widgetId, - activeTabId, - title, - frontComponentId, - { - row: position.y, - column: position.x, - rowSpan: position.h, - columnSpan: position.w, - }, - ); + const widgetId = uuidv4(); + const frontComponentSize = WIDGET_SIZES[WidgetType.FRONT_COMPONENT]!; + const defaultSize = frontComponentSize.default; + const minimumSize = frontComponentSize.minimum; + const position = getDefaultWidgetPosition( + pageLayoutDraggedArea, + defaultSize, + minimumSize, + ); - const newLayout = { - i: widgetId, - x: position.x, - y: position.y, - w: position.w, - h: position.h, - minW: minimumSize.w, - minH: minimumSize.h, - }; + const newWidget = createDefaultFrontComponentWidget( + widgetId, + activeTabId, + title, + frontComponentId, + { + row: position.y, + column: position.x, + rowSpan: position.h, + columnSpan: position.w, + }, + ); - const updatedLayouts = getUpdatedTabLayouts( - allTabLayouts, - activeTabId, - newLayout, - ); + const newLayout = { + i: widgetId, + x: position.x, + y: position.y, + w: position.w, + h: position.h, + minW: minimumSize.w, + minH: minimumSize.h, + }; - set(pageLayoutCurrentLayoutsState, updatedLayouts); + const updatedLayouts = getUpdatedTabLayouts( + allTabLayouts, + activeTabId, + newLayout, + ); - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), - })); + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - set(pageLayoutDraggedAreaState, null); + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), + })); - return newWidget; - }, + store.set(pageLayoutDraggedAreaState, null); + + return newWidget; + }, [ activeTabId, pageLayoutCurrentLayoutsState, pageLayoutDraftState, pageLayoutDraggedAreaState, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutGraphWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutGraphWidget.ts index a50ec45aa4..da0f5cce1d 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutGraphWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutGraphWidget.ts @@ -15,9 +15,9 @@ import { getWidgetSize } from '@/page-layout/utils/getWidgetSize'; import { getWidgetTitle } from '@/page-layout/utils/getWidgetTitle'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 as uuidv4 } from 'uuid'; import { @@ -39,133 +39,124 @@ export const useCreatePageLayoutGraphWidget = ( const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, pageLayoutId, ); - const createPageLayoutGraphWidget = useRecoilCallback( - ({ snapshot, set }) => - ({ - fieldSelection, - }: { - fieldSelection?: GraphWidgetFieldSelection; - }): PageLayoutWidget => { - const activeTabId = store.get( - activeTabIdComponentState.atomFamily({ - instanceId: tabListInstanceId, - }), - ); + const createPageLayoutGraphWidget = useCallback( + ({ + fieldSelection, + }: { + fieldSelection?: GraphWidgetFieldSelection; + }): PageLayoutWidget => { + const activeTabId = store.get( + activeTabIdComponentState.atomFamily({ + instanceId: tabListInstanceId, + }), + ); - if (!isDefined(activeTabId)) { - throw new Error( - 'A tab must be selected to create a new graph widget', - ); + if (!isDefined(activeTabId)) { + throw new Error('A tab must be selected to create a new graph widget'); + } + + const pageLayoutDraft = store.get(pageLayoutDraftState); + + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); + + const pageLayoutDraggedArea = store.get(pageLayoutDraggedAreaState); + + const allWidgets = pageLayoutDraft.tabs.flatMap((tab) => tab.widgets); + const existingWidgetCount = allWidgets.filter((widget) => { + if (widget.type !== WidgetType.GRAPH) { + return false; } - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); + if ( + !isWidgetConfigurationOfType( + widget.configuration, + 'BarChartConfiguration', + ) + ) { + return false; + } + return widget.configuration.layout === BarChartLayout.VERTICAL; + }).length; - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const title = getWidgetTitle( + { + configurationType: WidgetConfigurationType.BAR_CHART, + layout: BarChartLayout.VERTICAL, + }, + existingWidgetCount, + ); + const widgetId = uuidv4(); - const pageLayoutDraggedArea = snapshot - .getLoadable(pageLayoutDraggedAreaState) - .getValue(); + const defaultSize = getWidgetSize( + WidgetConfigurationType.BAR_CHART, + 'default', + ); + const minimumSize = getWidgetSize( + WidgetConfigurationType.BAR_CHART, + 'minimum', + ); + const position = getDefaultWidgetPosition( + pageLayoutDraggedArea, + defaultSize, + minimumSize, + ); - const allWidgets = pageLayoutDraft.tabs.flatMap((tab) => tab.widgets); - const existingWidgetCount = allWidgets.filter((widget) => { - if (widget.type !== WidgetType.GRAPH) { - return false; - } + const newWidget = createDefaultGraphWidget({ + id: widgetId, + pageLayoutTabId: activeTabId, + title, + gridPosition: { + row: position.y, + column: position.x, + rowSpan: position.h, + columnSpan: position.w, + }, + fieldSelection, + timezone: timeZone, + firstDayOfTheWeek: calendarStartDay, + }); - if ( - !isWidgetConfigurationOfType( - widget.configuration, - 'BarChartConfiguration', - ) - ) { - return false; - } - return widget.configuration.layout === BarChartLayout.VERTICAL; - }).length; + const newLayout = { + i: widgetId, + x: position.x, + y: position.y, + w: position.w, + h: position.h, + minW: minimumSize.w, + minH: minimumSize.h, + }; - const title = getWidgetTitle( - { - configurationType: WidgetConfigurationType.BAR_CHART, - layout: BarChartLayout.VERTICAL, - }, - existingWidgetCount, - ); - const widgetId = uuidv4(); + const updatedLayouts = getUpdatedTabLayouts( + allTabLayouts, + activeTabId, + newLayout, + ); + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - const defaultSize = getWidgetSize( - WidgetConfigurationType.BAR_CHART, - 'default', - ); - const minimumSize = getWidgetSize( - WidgetConfigurationType.BAR_CHART, - 'minimum', - ); - const position = getDefaultWidgetPosition( - pageLayoutDraggedArea, - defaultSize, - minimumSize, - ); + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), + })); - const newWidget = createDefaultGraphWidget({ - id: widgetId, - pageLayoutTabId: activeTabId, - title, - gridPosition: { - row: position.y, - column: position.x, - rowSpan: position.h, - columnSpan: position.w, - }, - fieldSelection, - timezone: timeZone, - firstDayOfTheWeek: calendarStartDay, - }); + store.set(pageLayoutDraggedAreaState, null); - const newLayout = { - i: widgetId, - x: position.x, - y: position.y, - w: position.w, - h: position.h, - minW: minimumSize.w, - minH: minimumSize.h, - }; - - const updatedLayouts = getUpdatedTabLayouts( - allTabLayouts, - activeTabId, - newLayout, - ); - set(pageLayoutCurrentLayoutsState, updatedLayouts); - - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), - })); - - set(pageLayoutDraggedAreaState, null); - - return newWidget; - }, + return newWidget; + }, [ tabListInstanceId, pageLayoutCurrentLayoutsState, diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutIframeWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutIframeWidget.ts index c76c10c18e..c57ae88da5 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutIframeWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutIframeWidget.ts @@ -11,9 +11,10 @@ import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTab import { getUpdatedTabLayouts } from '@/page-layout/utils/getUpdatedTabLayouts'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 as uuidv4 } from 'uuid'; import { WidgetType } from '~/generated-metadata/graphql'; @@ -31,93 +32,89 @@ export const useCreatePageLayoutIframeWidget = ( getTabListInstanceIdFromPageLayoutId(pageLayoutId), ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, pageLayoutId, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const createPageLayoutIframeWidget = useRecoilCallback( - ({ snapshot, set }) => - (title: string, url: string | null): PageLayoutWidget => { - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const store = useStore(); - const pageLayoutDraggedArea = snapshot - .getLoadable(pageLayoutDraggedAreaState) - .getValue(); + const createPageLayoutIframeWidget = useCallback( + (title: string, url: string | null): PageLayoutWidget => { + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); - if (!isDefined(activeTabId)) { - throw new Error( - 'A tab must be selected to create a new iframe widget', - ); - } + const pageLayoutDraggedArea = store.get(pageLayoutDraggedAreaState); - const widgetId = uuidv4(); - const iframeSize = WIDGET_SIZES[WidgetType.IFRAME]!; - const defaultIframeSize = iframeSize.default; - const minimumSize = iframeSize.minimum; - const position = getDefaultWidgetPosition( - pageLayoutDraggedArea, - defaultIframeSize, - minimumSize, - ); + if (!isDefined(activeTabId)) { + throw new Error('A tab must be selected to create a new iframe widget'); + } - const newWidget = createDefaultIframeWidget( - widgetId, - activeTabId, - title, - url, - { - row: position.y, - column: position.x, - rowSpan: position.h, - columnSpan: position.w, - }, - ); + const widgetId = uuidv4(); + const iframeSize = WIDGET_SIZES[WidgetType.IFRAME]!; + const defaultIframeSize = iframeSize.default; + const minimumSize = iframeSize.minimum; + const position = getDefaultWidgetPosition( + pageLayoutDraggedArea, + defaultIframeSize, + minimumSize, + ); - const newLayout = { - i: widgetId, - x: position.x, - y: position.y, - w: position.w, - h: position.h, - minW: minimumSize.w, - minH: minimumSize.h, - }; + const newWidget = createDefaultIframeWidget( + widgetId, + activeTabId, + title, + url, + { + row: position.y, + column: position.x, + rowSpan: position.h, + columnSpan: position.w, + }, + ); - const updatedLayouts = getUpdatedTabLayouts( - allTabLayouts, - activeTabId, - newLayout, - ); + const newLayout = { + i: widgetId, + x: position.x, + y: position.y, + w: position.w, + h: position.h, + minW: minimumSize.w, + minH: minimumSize.h, + }; - set(pageLayoutCurrentLayoutsState, updatedLayouts); + const updatedLayouts = getUpdatedTabLayouts( + allTabLayouts, + activeTabId, + newLayout, + ); - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), - })); + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - set(pageLayoutDraggedAreaState, null); + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), + })); - return newWidget; - }, + store.set(pageLayoutDraggedAreaState, null); + + return newWidget; + }, [ activeTabId, pageLayoutCurrentLayoutsState, pageLayoutDraftState, pageLayoutDraggedAreaState, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutStandaloneRichTextWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutStandaloneRichTextWidget.ts index 1ef3cd26e7..2c414be6c7 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutStandaloneRichTextWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutStandaloneRichTextWidget.ts @@ -10,9 +10,9 @@ import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTab import { getUpdatedTabLayouts } from '@/page-layout/utils/getUpdatedTabLayouts'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 as uuidv4 } from 'uuid'; import { @@ -32,94 +32,89 @@ export const useCreatePageLayoutStandaloneRichTextWidget = ( const store = useStore(); const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, pageLayoutId, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const createPageLayoutStandaloneRichTextWidget = useRecoilCallback( - ({ snapshot, set }) => - (body: RichTextV2Body): PageLayoutWidget => { - const activeTabId = store.get( - activeTabIdComponentState.atomFamily({ - instanceId: tabListInstanceId, - }), + const createPageLayoutStandaloneRichTextWidget = useCallback( + (body: RichTextV2Body): PageLayoutWidget => { + const activeTabId = store.get( + activeTabIdComponentState.atomFamily({ + instanceId: tabListInstanceId, + }), + ); + + if (!isDefined(activeTabId)) { + throw new Error( + 'A tab must be selected to create a new rich text widget', ); + } - if (!isDefined(activeTabId)) { - throw new Error( - 'A tab must be selected to create a new rich text widget', - ); - } + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const pageLayoutDraggedArea = store.get(pageLayoutDraggedAreaState); - const pageLayoutDraggedArea = snapshot - .getLoadable(pageLayoutDraggedAreaState) - .getValue(); + const widgetId = uuidv4(); + const richTextSize = WIDGET_SIZES[WidgetType.STANDALONE_RICH_TEXT]!; + const defaultRichTextSize = richTextSize.default; + const minimumSize = richTextSize.minimum; + const position = getDefaultWidgetPosition( + pageLayoutDraggedArea, + defaultRichTextSize, + minimumSize, + ); - const widgetId = uuidv4(); - const richTextSize = WIDGET_SIZES[WidgetType.STANDALONE_RICH_TEXT]!; - const defaultRichTextSize = richTextSize.default; - const minimumSize = richTextSize.minimum; - const position = getDefaultWidgetPosition( - pageLayoutDraggedArea, - defaultRichTextSize, - minimumSize, - ); + const newWidget = createDefaultStandaloneRichTextWidget( + widgetId, + activeTabId, - const newWidget = createDefaultStandaloneRichTextWidget( - widgetId, - activeTabId, + body, + { + row: position.y, + column: position.x, + rowSpan: position.h, + columnSpan: position.w, + }, + ); - body, - { - row: position.y, - column: position.x, - rowSpan: position.h, - columnSpan: position.w, - }, - ); + const newLayout = { + i: widgetId, + x: position.x, + y: position.y, + w: position.w, + h: position.h, + minW: minimumSize.w, + minH: minimumSize.h, + }; - const newLayout = { - i: widgetId, - x: position.x, - y: position.y, - w: position.w, - h: position.h, - minW: minimumSize.w, - minH: minimumSize.h, - }; + const updatedLayouts = getUpdatedTabLayouts( + allTabLayouts, + activeTabId, + newLayout, + ); - const updatedLayouts = getUpdatedTabLayouts( - allTabLayouts, - activeTabId, - newLayout, - ); + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - set(pageLayoutCurrentLayoutsState, updatedLayouts); + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), + })); - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget), - })); + store.set(pageLayoutDraggedAreaState, null); - set(pageLayoutDraggedAreaState, null); - - return newWidget; - }, + return newWidget; + }, [ tabListInstanceId, pageLayoutCurrentLayoutsState, diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts index 5adcab7aed..1c555ab62b 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreatePageLayoutTab.ts @@ -6,9 +6,10 @@ import { getEmptyTabLayout } from '@/page-layout/utils/getEmptyTabLayout'; import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { v4 as uuidv4 } from 'uuid'; export const useCreatePageLayoutTab = (pageLayoutIdFromProps?: string) => { @@ -17,12 +18,12 @@ export const useCreatePageLayoutTab = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); @@ -33,51 +34,51 @@ export const useCreatePageLayoutTab = (pageLayoutIdFromProps?: string) => { tabListInstanceId, ); - const createPageLayoutTab = useRecoilCallback( - ({ snapshot, set }) => - (title?: string): string => { - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); + const store = useStore(); - const newTabId = uuidv4(); - const tabsLength = pageLayoutDraft.tabs.length; - const maxPosition = - tabsLength > 0 - ? Math.max(...pageLayoutDraft.tabs.map((t) => t.position)) - : -1; - const newTab: PageLayoutTab = { - id: newTabId, - applicationId: '', - title: title || `Tab ${tabsLength + 1}`, - position: maxPosition + 1, - pageLayoutId: pageLayoutId, - widgets: [], - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - deletedAt: null, - }; + const createPageLayoutTab = useCallback( + (title?: string): string => { + const pageLayoutDraft = store.get(pageLayoutDraftState); - const updatedTabs = [...(pageLayoutDraft.tabs || []), newTab]; + const newTabId = uuidv4(); + const tabsLength = pageLayoutDraft.tabs.length; + const maxPosition = + tabsLength > 0 + ? Math.max(...pageLayoutDraft.tabs.map((t) => t.position)) + : -1; + const newTab: PageLayoutTab = { + id: newTabId, + applicationId: '', + title: title || `Tab ${tabsLength + 1}`, + position: maxPosition + 1, + pageLayoutId: pageLayoutId, + widgets: [], + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + deletedAt: null, + }; - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: updatedTabs, - })); + const updatedTabs = [...(pageLayoutDraft.tabs || []), newTab]; - set(pageLayoutCurrentLayoutsState, (prev) => - getEmptyTabLayout(prev, newTabId), - ); + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: updatedTabs, + })); - setActiveTabId(newTabId); + store.set(pageLayoutCurrentLayoutsState, (prev) => + getEmptyTabLayout(prev, newTabId), + ); - return newTabId; - }, + setActiveTabId(newTabId); + + return newTabId; + }, [ pageLayoutCurrentLayoutsState, pageLayoutDraftState, pageLayoutId, setActiveTabId, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCreateWidgetFromClick.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCreateWidgetFromClick.ts index d8135f5643..6b19cb75a4 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCreateWidgetFromClick.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCreateWidgetFromClick.ts @@ -2,39 +2,42 @@ import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layo import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLayoutDraggedAreaComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { parseCellIdToCoordinates } from '@/page-layout/utils/parseCellIdToCoordinates'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; export const useCreateWidgetFromClick = () => { - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, ); - const pageLayoutEditingWidgetIdState = useRecoilComponentCallbackState( + const pageLayoutEditingWidgetIdState = useRecoilComponentStateCallbackStateV2( pageLayoutEditingWidgetIdComponentState, ); const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu(); - const createWidgetFromClick = useRecoilCallback( - ({ set }) => - (cellId: string) => { - const { col, row } = parseCellIdToCoordinates(cellId); - const bounds = { x: col, y: row, w: 1, h: 1 }; + const store = useStore(); - set(pageLayoutDraggedAreaState, bounds); - set(pageLayoutEditingWidgetIdState, null); + const createWidgetFromClick = useCallback( + (cellId: string) => { + const { col, row } = parseCellIdToCoordinates(cellId); + const bounds = { x: col, y: row, w: 1, h: 1 }; - navigatePageLayoutCommandMenu({ - commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect, - resetNavigationStack: true, - }); - }, + store.set(pageLayoutDraggedAreaState, bounds); + store.set(pageLayoutEditingWidgetIdState, null); + + navigatePageLayoutCommandMenu({ + commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect, + resetNavigationStack: true, + }); + }, [ navigatePageLayoutCommandMenu, pageLayoutDraggedAreaState, pageLayoutEditingWidgetIdState, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayout.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayout.ts index 81d4bae833..3fcc34d29f 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayout.ts @@ -1,18 +1,18 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; export const useCurrentPageLayout = () => { - const pageLayoutPersisted = useRecoilComponentValue( + const pageLayoutPersisted = useRecoilComponentValueV2( pageLayoutPersistedComponentState, ); - const pageLayoutDraft = useRecoilComponentValue( + const pageLayoutDraft = useRecoilComponentValueV2( pageLayoutDraftComponentState, ); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutTab.ts index 8f6f65727a..f960c4b42b 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutTab.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutTab.ts @@ -6,9 +6,9 @@ import { removeTabLayouts } from '@/page-layout/utils/removeTabLayouts'; import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; export const useDeletePageLayoutTab = (pageLayoutIdFromProps?: string) => { const pageLayoutId = useAvailableComponentInstanceIdOrThrow( @@ -16,12 +16,12 @@ export const useDeletePageLayoutTab = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); @@ -33,36 +33,33 @@ export const useDeletePageLayoutTab = (pageLayoutIdFromProps?: string) => { instanceId: tabListInstanceId, }); - const deleteTab = useRecoilCallback( - ({ set, snapshot }) => - (tabId: string) => { - const draft = snapshot.getLoadable(pageLayoutDraftState).getValue(); - if (draft.tabs.length <= 1) { - return; - } + const deleteTab = useCallback( + (tabId: string) => { + const draft = store.get(pageLayoutDraftState); + if (draft.tabs.length <= 1) { + return; + } - const sorted = sortTabsByPosition(draft.tabs); - const index = sorted.findIndex((t) => t.id === tabId); + const sorted = sortTabsByPosition(draft.tabs); + const index = sorted.findIndex((t) => t.id === tabId); - const activeTabId = store.get(activeTabIdAtom); + const activeTabId = store.get(activeTabIdAtom); - const allLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); - const updatedLayouts = removeTabLayouts(allLayouts, tabId); - set(pageLayoutCurrentLayoutsState, updatedLayouts); + const allLayouts = store.get(pageLayoutCurrentLayoutsState); + const updatedLayouts = removeTabLayouts(allLayouts, tabId); + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: prev.tabs.filter((t) => t.id !== tabId), - })); + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: prev.tabs.filter((t) => t.id !== tabId), + })); - if (activeTabId === tabId) { - const neighbor = index > 0 ? sorted[index - 1] : sorted[index + 1]; - const nextActiveId = neighbor?.id ?? null; - store.set(activeTabIdAtom, nextActiveId); - } - }, + if (activeTabId === tabId) { + const neighbor = index > 0 ? sorted[index - 1] : sorted[index + 1]; + const nextActiveId = neighbor?.id ?? null; + store.set(activeTabIdAtom, nextActiveId); + } + }, [ pageLayoutCurrentLayoutsState, pageLayoutDraftState, diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutWidget.ts index fe5f625ff6..c2670fa1c4 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useDeletePageLayoutWidget.ts @@ -1,8 +1,9 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; @@ -15,50 +16,52 @@ export const useDeletePageLayoutWidget = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); const { closeCommandMenu } = useCommandMenu(); - const deletePageLayoutWidget = useRecoilCallback( - ({ snapshot, set }) => - (widgetId: string) => { - closeCommandMenu(); + const store = useStore(); - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const deletePageLayoutWidget = useCallback( + (widgetId: string) => { + closeCommandMenu(); - const tabWithWidget = pageLayoutDraft.tabs.find((tab) => - tab.widgets.some((w) => w.id === widgetId), + const pageLayoutDraft = store.get(pageLayoutDraftState); + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); + + const tabWithWidget = pageLayoutDraft.tabs.find((tab) => + tab.widgets.some((w) => w.id === widgetId), + ); + const tabId = tabWithWidget?.id; + + if (isDefined(tabId)) { + const updatedLayouts = removeWidgetLayoutFromTab( + allTabLayouts, + tabId, + widgetId, ); - const tabId = tabWithWidget?.id; + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - if (isDefined(tabId)) { - const updatedLayouts = removeWidgetLayoutFromTab( - allTabLayouts, - tabId, - widgetId, - ); - set(pageLayoutCurrentLayoutsState, updatedLayouts); - - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: removeWidgetFromTab(prev.tabs, tabId, widgetId), - })); - } - }, - [closeCommandMenu, pageLayoutCurrentLayoutsState, pageLayoutDraftState], + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: removeWidgetFromTab(prev.tabs, tabId, widgetId), + })); + } + }, + [ + closeCommandMenu, + pageLayoutCurrentLayoutsState, + pageLayoutDraftState, + store, + ], ); return { deletePageLayoutWidget }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutTab.ts index 5574b52ee5..372030ac3c 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutTab.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutTab.ts @@ -12,10 +12,10 @@ import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition'; import { calculateNewPosition } from '@/ui/layout/draggable-list/utils/calculateNewPosition'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { appendCopySuffix, isDefined } from 'twenty-shared/utils'; import { v4 as uuidv4 } from 'uuid'; @@ -25,23 +25,25 @@ export const useDuplicatePageLayoutTab = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftAtom = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsAtom = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); + const store = useStore(); + const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId); const setActiveTabId = useSetRecoilComponentStateV2( activeTabIdComponentState, tabListInstanceId, ); - const setTabSettingsOpenTabId = useSetRecoilComponentState( + const setTabSettingsOpenTabId = useSetRecoilComponentStateV2( pageLayoutTabSettingsOpenTabIdComponentState, pageLayoutId, ); @@ -50,103 +52,100 @@ export const useDuplicatePageLayoutTab = (pageLayoutIdFromProps?: string) => { const { closeCommandMenu } = useCommandMenu(); - const duplicateTab = useRecoilCallback( - ({ snapshot, set }) => - (tabId: string): string => { - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); + const duplicateTab = useCallback( + (tabId: string): string => { + const pageLayoutDraft = store.get(pageLayoutDraftAtom); - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const allTabLayouts = store.get(pageLayoutCurrentLayoutsAtom); - const sourceTab = pageLayoutDraft.tabs.find((t) => t.id === tabId); + const sourceTab = pageLayoutDraft.tabs.find((t) => t.id === tabId); - if (!isDefined(sourceTab)) { - throw new Error(`Tab with id ${tabId} not found`); - } + if (!isDefined(sourceTab)) { + throw new Error(`Tab with id ${tabId} not found`); + } - const newTabId = uuidv4(); - const widgetOldIdNewIdMap = new Map(); + const newTabId = uuidv4(); + const widgetOldIdNewIdMap = new Map(); - const clonedWidgets = sourceTab.widgets.map((widget) => { - const newWidgetId = uuidv4(); - widgetOldIdNewIdMap.set(widget.id, newWidgetId); + const clonedWidgets = sourceTab.widgets.map((widget) => { + const newWidgetId = uuidv4(); + widgetOldIdNewIdMap.set(widget.id, newWidgetId); - return { - ...widget, - id: newWidgetId, - pageLayoutTabId: newTabId, - ...generateDuplicatedTimestamps(), - }; - }); - - const sortedTabs = sortTabsByPosition(pageLayoutDraft.tabs); - const sourceIndex = sortedTabs.findIndex((t) => t.id === tabId); - - const newTabPosition = calculateNewPosition({ - items: sortedTabs, - destinationIndex: sourceIndex + 1, - sourceIndex, - }); - - const newTab: PageLayoutTab = { - ...sourceTab, - id: newTabId, - title: appendCopySuffix(sourceTab.title), - position: newTabPosition, - widgets: clonedWidgets, + return { + ...widget, + id: newWidgetId, + pageLayoutTabId: newTabId, ...generateDuplicatedTimestamps(), }; + }); - const sourceLayouts = allTabLayouts[tabId] ?? { - desktop: [], - mobile: [], - }; + const sortedTabs = sortTabsByPosition(pageLayoutDraft.tabs); + const sourceIndex = sortedTabs.findIndex((t) => t.id === tabId); - const newLayouts = { - desktop: sourceLayouts.desktop.map((layout) => ({ - ...layout, - i: widgetOldIdNewIdMap.get(layout.i) || layout.i, - })), - mobile: sourceLayouts.mobile.map((layout) => ({ - ...layout, - i: widgetOldIdNewIdMap.get(layout.i) || layout.i, - })), - }; + const newTabPosition = calculateNewPosition({ + items: sortedTabs, + destinationIndex: sourceIndex + 1, + sourceIndex, + }); - set(pageLayoutCurrentLayoutsState, { - ...allTabLayouts, - [newTabId]: newLayouts, - }); + const newTab: PageLayoutTab = { + ...sourceTab, + id: newTabId, + title: appendCopySuffix(sourceTab.title), + position: newTabPosition, + widgets: clonedWidgets, + ...generateDuplicatedTimestamps(), + }; - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: [...prev.tabs, newTab], - })); + const sourceLayouts = allTabLayouts[tabId] ?? { + desktop: [], + mobile: [], + }; - closeCommandMenu(); + const newLayouts = { + desktop: sourceLayouts.desktop.map((layout) => ({ + ...layout, + i: widgetOldIdNewIdMap.get(layout.i) || layout.i, + })), + mobile: sourceLayouts.mobile.map((layout) => ({ + ...layout, + i: widgetOldIdNewIdMap.get(layout.i) || layout.i, + })), + }; - setActiveTabId(newTabId); + store.set(pageLayoutCurrentLayoutsAtom, { + ...allTabLayouts, + [newTabId]: newLayouts, + }); - setTabSettingsOpenTabId(newTabId); + const prev = store.get(pageLayoutDraftAtom); + store.set(pageLayoutDraftAtom, { + ...prev, + tabs: [...prev.tabs, newTab], + }); - navigatePageLayoutCommandMenu({ - commandMenuPage: CommandMenuPages.PageLayoutTabSettings, - pageTitle: newTab.title, - focusTitleInput: true, - }); + closeCommandMenu(); - return newTabId; - }, + setActiveTabId(newTabId); + + setTabSettingsOpenTabId(newTabId); + + navigatePageLayoutCommandMenu({ + commandMenuPage: CommandMenuPages.PageLayoutTabSettings, + pageTitle: newTab.title, + focusTitleInput: true, + }); + + return newTabId; + }, [ closeCommandMenu, navigatePageLayoutCommandMenu, - pageLayoutCurrentLayoutsState, - pageLayoutDraftState, + pageLayoutCurrentLayoutsAtom, + pageLayoutDraftAtom, setActiveTabId, setTabSettingsOpenTabId, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutWidget.ts index 59c1269654..7d63cff9b8 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useDuplicatePageLayoutWidget.ts @@ -9,9 +9,10 @@ import { getScrollWrapperInstanceIdFromPageLayoutId } from '@/page-layout/utils/ import { getUpdatedTabLayouts } from '@/page-layout/utils/getUpdatedTabLayouts'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { appendCopySuffix, isDefined } from 'twenty-shared/utils'; import { v4 as uuidv4 } from 'uuid'; @@ -23,17 +24,17 @@ export const useDuplicatePageLayoutWidget = ( pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const setEditingWidgetId = useSetRecoilComponentState( + const setEditingWidgetId = useSetRecoilComponentStateV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); @@ -42,107 +43,105 @@ export const useDuplicatePageLayoutWidget = ( getScrollWrapperInstanceIdFromPageLayoutId(pageLayoutId), ); - const duplicateWidget = useRecoilCallback( - ({ snapshot, set }) => - (widgetId: string): string => { - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); + const store = useStore(); - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const duplicateWidget = useCallback( + (widgetId: string): string => { + const pageLayoutDraft = store.get(pageLayoutDraftState); - const sourceWidget = pageLayoutDraft.tabs - .flatMap((tab) => tab.widgets) - .find((widget) => widget.id === widgetId); + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); - if (!isDefined(sourceWidget)) { - throw new Error(`Widget with id ${widgetId} not found`); - } + const sourceWidget = pageLayoutDraft.tabs + .flatMap((tab) => tab.widgets) + .find((widget) => widget.id === widgetId); - const sourceTab = pageLayoutDraft.tabs.find( - (tab) => tab.id === sourceWidget.pageLayoutTabId, + if (!isDefined(sourceWidget)) { + throw new Error(`Widget with id ${widgetId} not found`); + } + + const sourceTab = pageLayoutDraft.tabs.find( + (tab) => tab.id === sourceWidget.pageLayoutTabId, + ); + + if (!isDefined(sourceTab)) { + throw new Error( + `Tab with id ${sourceWidget.pageLayoutTabId} not found`, ); + } - if (!isDefined(sourceTab)) { - throw new Error( - `Tab with id ${sourceWidget.pageLayoutTabId} not found`, + const newWidgetId = uuidv4(); + + const clonedWidget: PageLayoutWidget = { + ...sourceWidget, + id: newWidgetId, + title: appendCopySuffix(sourceWidget.title), + ...generateDuplicatedTimestamps(), + }; + + const currentTabLayouts = allTabLayouts[sourceTab.id] || { + desktop: [], + mobile: [], + }; + + const sourceLayout = currentTabLayouts.desktop.find( + (layout) => layout.i === widgetId, + ); + + if (!isDefined(sourceLayout)) { + throw new Error(`Layout for widget ${widgetId} not found`); + } + + const maxY = currentTabLayouts.desktop.reduce( + (max, layout) => Math.max(max, layout.y + layout.h), + 0, + ); + + const newLayout = { + ...sourceLayout, + i: newWidgetId, + y: maxY, + }; + + const updatedLayouts = getUpdatedTabLayouts( + allTabLayouts, + sourceTab.id, + newLayout, + ); + + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); + + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: addWidgetToTab(prev.tabs, sourceTab.id, clonedWidget), + })); + + setEditingWidgetId(newWidgetId); + + const { scrollWrapperElement } = getScrollWrapperElement(); + + if (isDefined(scrollWrapperElement)) { + requestAnimationFrame(() => { + const widgetElement = scrollWrapperElement.querySelector( + `[data-widget-id="${newWidgetId}"]`, ); - } - const newWidgetId = uuidv4(); + if (isDefined(widgetElement)) { + widgetElement.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }); + } + }); + } - const clonedWidget: PageLayoutWidget = { - ...sourceWidget, - id: newWidgetId, - title: appendCopySuffix(sourceWidget.title), - ...generateDuplicatedTimestamps(), - }; - - const currentTabLayouts = allTabLayouts[sourceTab.id] || { - desktop: [], - mobile: [], - }; - - const sourceLayout = currentTabLayouts.desktop.find( - (layout) => layout.i === widgetId, - ); - - if (!isDefined(sourceLayout)) { - throw new Error(`Layout for widget ${widgetId} not found`); - } - - const maxY = currentTabLayouts.desktop.reduce( - (max, layout) => Math.max(max, layout.y + layout.h), - 0, - ); - - const newLayout = { - ...sourceLayout, - i: newWidgetId, - y: maxY, - }; - - const updatedLayouts = getUpdatedTabLayouts( - allTabLayouts, - sourceTab.id, - newLayout, - ); - - set(pageLayoutCurrentLayoutsState, updatedLayouts); - - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: addWidgetToTab(prev.tabs, sourceTab.id, clonedWidget), - })); - - setEditingWidgetId(newWidgetId); - - const { scrollWrapperElement } = getScrollWrapperElement(); - - if (isDefined(scrollWrapperElement)) { - requestAnimationFrame(() => { - const widgetElement = scrollWrapperElement.querySelector( - `[data-widget-id="${newWidgetId}"]`, - ); - - if (isDefined(widgetElement)) { - widgetElement.scrollIntoView({ - behavior: 'smooth', - block: 'nearest', - }); - } - }); - } - - return newWidgetId; - }, + return newWidgetId; + }, [ pageLayoutCurrentLayoutsState, pageLayoutDraftState, setEditingWidgetId, getScrollWrapperElement, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts index 70a2a4041f..040a5f5310 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts @@ -1,15 +1,15 @@ import { useCallback } from 'react'; -import { useSetRecoilState } from 'recoil'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { CommandMenuPages } from 'twenty-shared/types'; import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { t } from '@lingui/core/macro'; import { WidgetType } from '~/generated-metadata/graphql'; @@ -19,14 +19,14 @@ export const useEditPageLayoutWidget = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const setPageLayoutEditingWidgetId = useSetRecoilComponentState( + const setPageLayoutEditingWidgetId = useSetRecoilComponentStateV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu(); const { closeCommandMenu } = useCommandMenu(); - const setCommandMenuPage = useSetRecoilState(commandMenuPageState); + const setCommandMenuPage = useSetRecoilStateV2(commandMenuPageState); const handleEditWidget = useCallback( ({ diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useEndPageLayoutDragSelection.ts b/packages/twenty-front/src/modules/page-layout/hooks/useEndPageLayoutDragSelection.ts index 2a202206e6..b9f92c0642 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useEndPageLayoutDragSelection.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useEndPageLayoutDragSelection.ts @@ -5,8 +5,9 @@ import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pa import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState'; import { calculateGridBoundsFromSelectedCells } from '@/page-layout/utils/calculateGridBoundsFromSelectedCells'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -18,54 +19,51 @@ export const useEndPageLayoutDragSelection = ( pageLayoutIdFromProps, ); - const pageLayoutSelectedCellsState = useRecoilComponentCallbackState( + const pageLayoutSelectedCellsState = useRecoilComponentStateCallbackStateV2( pageLayoutSelectedCellsComponentState, pageLayoutId, ); - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, pageLayoutId, ); - const pageLayoutEditingWidgetIdState = useRecoilComponentCallbackState( + const pageLayoutEditingWidgetIdState = useRecoilComponentStateCallbackStateV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu(); - const endPageLayoutDragSelection = useRecoilCallback( - ({ snapshot, set }) => - () => { - const pageLayoutSelectedCells = snapshot - .getLoadable(pageLayoutSelectedCellsState) - .getValue(); + const store = useStore(); - if (pageLayoutSelectedCells.size > 0) { - const draggedBounds = calculateGridBoundsFromSelectedCells( - Array.from(pageLayoutSelectedCells), - ); + const endPageLayoutDragSelection = useCallback(() => { + const pageLayoutSelectedCells = store.get(pageLayoutSelectedCellsState); - if (isDefined(draggedBounds)) { - set(pageLayoutDraggedAreaState, draggedBounds); - set(pageLayoutEditingWidgetIdState, null); + if (pageLayoutSelectedCells.size > 0) { + const draggedBounds = calculateGridBoundsFromSelectedCells( + Array.from(pageLayoutSelectedCells), + ); - navigatePageLayoutCommandMenu({ - commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect, - resetNavigationStack: true, - }); - } - } + if (isDefined(draggedBounds)) { + store.set(pageLayoutDraggedAreaState, draggedBounds); + store.set(pageLayoutEditingWidgetIdState, null); - set(pageLayoutSelectedCellsState, new Set()); - }, - [ - navigatePageLayoutCommandMenu, - pageLayoutDraggedAreaState, - pageLayoutEditingWidgetIdState, - pageLayoutSelectedCellsState, - ], - ); + navigatePageLayoutCommandMenu({ + commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect, + resetNavigationStack: true, + }); + } + } + + store.set(pageLayoutSelectedCellsState, new Set()); + }, [ + navigatePageLayoutCommandMenu, + pageLayoutDraggedAreaState, + pageLayoutEditingWidgetIdState, + pageLayoutSelectedCellsState, + store, + ]); return { endPageLayoutDragSelection }; }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useMovePageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/hooks/useMovePageLayoutTab.ts index 58d5694625..918dbb160f 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useMovePageLayoutTab.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useMovePageLayoutTab.ts @@ -3,8 +3,9 @@ import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDr import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition'; import { calculateNewPosition } from '@/ui/layout/draggable-list/utils/calculateNewPosition'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useMovePageLayoutTab = (pageLayoutIdFromProps?: string) => { const pageLayoutId = useAvailableComponentInstanceIdOrThrow( @@ -12,67 +13,67 @@ export const useMovePageLayoutTab = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const moveLeft = useRecoilCallback( - ({ set }) => - (tabId: string) => { - set(pageLayoutDraftState, (prev) => { - const sorted = sortTabsByPosition(prev.tabs); - const index = sorted.findIndex((t) => t.id === tabId); - if (index <= 0) return prev; + const store = useStore(); - const items = sorted.filter((t) => t.id !== tabId); - const destinationIndex = index - 1; - const sourceIndex = index; + const moveLeft = useCallback( + (tabId: string) => { + store.set(pageLayoutDraftState, (prev) => { + const sorted = sortTabsByPosition(prev.tabs); + const index = sorted.findIndex((t) => t.id === tabId); + if (index <= 0) return prev; - const newPosition = calculateNewPosition({ - destinationIndex, - sourceIndex, - items, - }); + const items = sorted.filter((t) => t.id !== tabId); + const destinationIndex = index - 1; + const sourceIndex = index; - return { - ...prev, - tabs: prev.tabs.map((t) => - t.id === tabId ? { ...t, position: newPosition } : t, - ), - }; + const newPosition = calculateNewPosition({ + destinationIndex, + sourceIndex, + items, }); - }, - [pageLayoutDraftState], + + return { + ...prev, + tabs: prev.tabs.map((t) => + t.id === tabId ? { ...t, position: newPosition } : t, + ), + }; + }); + }, + [pageLayoutDraftState, store], ); - const moveRight = useRecoilCallback( - ({ set }) => - (tabId: string) => { - set(pageLayoutDraftState, (prev) => { - const sorted = sortTabsByPosition(prev.tabs); - const index = sorted.findIndex((t) => t.id === tabId); - if (index < 0 || index >= sorted.length - 1) return prev; + const moveRight = useCallback( + (tabId: string) => { + store.set(pageLayoutDraftState, (prev) => { + const sorted = sortTabsByPosition(prev.tabs); + const index = sorted.findIndex((t) => t.id === tabId); + if (index < 0 || index >= sorted.length - 1) return prev; - const items = sorted.filter((t) => t.id !== tabId); - const destinationIndex = index + 1; - const sourceIndex = index; + const items = sorted.filter((t) => t.id !== tabId); + const destinationIndex = index + 1; + const sourceIndex = index; - const newPosition = calculateNewPosition({ - destinationIndex, - sourceIndex, - items, - }); - - return { - ...prev, - tabs: prev.tabs.map((t) => - t.id === tabId ? { ...t, position: newPosition } : t, - ), - }; + const newPosition = calculateNewPosition({ + destinationIndex, + sourceIndex, + items, }); - }, - [pageLayoutDraftState], + + return { + ...prev, + tabs: prev.tabs.map((t) => + t.id === tabId ? { ...t, position: newPosition } : t, + ), + }; + }); + }, + [pageLayoutDraftState, store], ); return { moveLeft, moveRight }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutDraftState.ts b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutDraftState.ts index c47ec02dea..431f592fa3 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutDraftState.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutDraftState.ts @@ -1,7 +1,7 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; @@ -12,11 +12,11 @@ export const usePageLayoutDraftState = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const [pageLayoutDraft, setPageLayoutDraft] = useRecoilComponentState( + const [pageLayoutDraft, setPageLayoutDraft] = useRecoilComponentStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutPersisted = useRecoilComponentValue( + const pageLayoutPersisted = useRecoilComponentValueV2( pageLayoutPersistedComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutHandleLayoutChange.ts b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutHandleLayoutChange.ts index 7bf6b817fd..f6867694fc 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutHandleLayoutChange.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutHandleLayoutChange.ts @@ -2,10 +2,10 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/context import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useStore } from 'jotai'; import { type Layout, type Layouts } from 'react-grid-layout'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; @@ -22,69 +22,64 @@ export const usePageLayoutHandleLayoutChange = ( const store = useStore(); const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const handleLayoutChange = useRecoilCallback( - ({ snapshot, set }) => - (_: Layout[], allLayouts: Layouts) => { - const activeTabId = store.get( - activeTabIdComponentState.atomFamily({ - instanceId: tabListInstanceId, + const handleLayoutChange = useCallback( + (_: Layout[], allLayouts: Layouts) => { + const activeTabId = store.get( + activeTabIdComponentState.atomFamily({ + instanceId: tabListInstanceId, + }), + ); + + if (!isDefined(activeTabId)) return; + + const currentTabLayouts = store.get(pageLayoutCurrentLayoutsState); + + store.set(pageLayoutCurrentLayoutsState, { + ...currentTabLayouts, + [activeTabId]: structuredClone(allLayouts), + }); + + const pageLayoutDraft = store.get(pageLayoutDraftState); + + const currentTab = pageLayoutDraft.tabs.find( + (tab) => tab.id === activeTabId, + ); + + if (!currentTab) return; + + const updatedWidgets = convertLayoutsToWidgets( + currentTab.widgets, + allLayouts, + ); + + if (isDefined(activeTabId)) { + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: prev.tabs.map((tab) => { + if (tab.id === activeTabId) { + const tabWidgets = updatedWidgets.filter( + (w) => w.pageLayoutTabId === activeTabId, + ); + return { + ...tab, + widgets: tabWidgets, + }; + } + return tab; }), - ); - - if (!isDefined(activeTabId)) return; - - const currentTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); - - set(pageLayoutCurrentLayoutsState, { - ...currentTabLayouts, - [activeTabId]: structuredClone(allLayouts), - }); - - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); - - const currentTab = pageLayoutDraft.tabs.find( - (tab) => tab.id === activeTabId, - ); - - if (!currentTab) return; - - const updatedWidgets = convertLayoutsToWidgets( - currentTab.widgets, - allLayouts, - ); - - if (isDefined(activeTabId)) { - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: prev.tabs.map((tab) => { - if (tab.id === activeTabId) { - const tabWidgets = updatedWidgets.filter( - (w) => w.pageLayoutTabId === activeTabId, - ); - return { - ...tab, - widgets: tabWidgets, - }; - } - return tab; - }), - })); - } - }, + })); + } + }, [ tabListInstanceId, pageLayoutCurrentLayoutsState, diff --git a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutIdForRecord.ts b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutIdForRecord.ts index 5cb4821298..69e153cba6 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutIdForRecord.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutIdForRecord.ts @@ -1,5 +1,3 @@ -import { useRecoilValue } from 'recoil'; - import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; @@ -7,6 +5,7 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { recordPageLayoutByObjectMetadataIdFamilySelector } from '@/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector'; import { getDefaultRecordPageLayoutId } from '@/page-layout/utils/getDefaultRecordPageLayoutId'; import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; export const usePageLayoutIdForRecord = ({ @@ -29,10 +28,9 @@ export const usePageLayoutIdForRecord = ({ objectNameSingular: targetObjectNameSingular, }); - const recordPageLayout = useRecoilValue( - recordPageLayoutByObjectMetadataIdFamilySelector({ - objectMetadataId: objectMetadataItem.id, - }), + const recordPageLayout = useFamilySelectorValueV2( + recordPageLayoutByObjectMetadataIdFamilySelector, + { objectMetadataId: objectMetadataItem.id }, ); if (isDashboard) { diff --git a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow.ts b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow.ts index d5ee94a9db..ac47fe59d8 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow.ts @@ -5,7 +5,7 @@ import { buildWidgetVisibilityContext } from '@/page-layout/utils/buildWidgetVis import { filterVisibleWidgets } from '@/page-layout/utils/filterVisibleWidgets'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const usePageLayoutTabWithVisibleWidgetsOrThrow = ( @@ -14,7 +14,7 @@ export const usePageLayoutTabWithVisibleWidgetsOrThrow = ( const { currentPageLayout } = useCurrentPageLayout(); const isMobile = useIsMobile(); const { isInRightDrawer } = useLayoutRenderingContext(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow.ts b/packages/twenty-front/src/modules/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow.ts index e641ba3c99..e5b84f5ba9 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useRecordPageLayoutIdFromRecordStoreOrThrow.ts @@ -2,7 +2,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { recordPageLayoutByObjectMetadataIdFamilySelector } from '@/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector'; import { getDefaultRecordPageLayoutId } from '@/page-layout/utils/getDefaultRecordPageLayoutId'; import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier'; -import { useRecoilValue } from 'recoil'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useRecordPageLayoutIdFromRecordStoreOrThrow = ({ @@ -12,10 +12,9 @@ export const useRecordPageLayoutIdFromRecordStoreOrThrow = ({ objectNameSingular: targetObjectNameSingular, }); - const recordPageLayout = useRecoilValue( - recordPageLayoutByObjectMetadataIdFamilySelector({ - objectMetadataId: objectMetadataItem.id, - }), + const recordPageLayout = useFamilySelectorValueV2( + recordPageLayoutByObjectMetadataIdFamilySelector, + { objectMetadataId: objectMetadataItem.id }, ); const pageLayoutId = isDefined(recordPageLayout) diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useRemovePageLayoutWidgetAndPreservePosition.ts b/packages/twenty-front/src/modules/page-layout/hooks/useRemovePageLayoutWidgetAndPreservePosition.ts index 104b542a64..b2756947c2 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useRemovePageLayoutWidgetAndPreservePosition.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useRemovePageLayoutWidgetAndPreservePosition.ts @@ -6,8 +6,9 @@ import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pa import { removeWidgetFromTab } from '@/page-layout/utils/removeWidgetFromTab'; import { removeWidgetLayoutFromTab } from '@/page-layout/utils/removeWidgetLayoutFromTab'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRemovePageLayoutWidgetAndPreservePosition = ( @@ -18,80 +19,78 @@ export const useRemovePageLayoutWidgetAndPreservePosition = ( pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, pageLayoutId, ); - const pageLayoutDraggedAreaState = useRecoilComponentCallbackState( + const pageLayoutDraggedAreaState = useRecoilComponentStateCallbackStateV2( pageLayoutDraggedAreaComponentState, pageLayoutId, ); - const pageLayoutEditingWidgetIdState = useRecoilComponentCallbackState( + const pageLayoutEditingWidgetIdState = useRecoilComponentStateCallbackStateV2( pageLayoutEditingWidgetIdComponentState, pageLayoutId, ); - const removePageLayoutWidgetAndPreservePosition = useRecoilCallback( - ({ snapshot, set }) => - (widgetId: string) => { - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftState) - .getValue(); - const allTabLayouts = snapshot - .getLoadable(pageLayoutCurrentLayoutsState) - .getValue(); + const store = useStore(); - const tabWithWidget = pageLayoutDraft.tabs.find((tab) => - tab.widgets.some((w) => w.id === widgetId), - ); - const tabId = tabWithWidget?.id; + const removePageLayoutWidgetAndPreservePosition = useCallback( + (widgetId: string) => { + const pageLayoutDraft = store.get(pageLayoutDraftState); + const allTabLayouts = store.get(pageLayoutCurrentLayoutsState); - if (!isDefined(tabId)) { - return; - } + const tabWithWidget = pageLayoutDraft.tabs.find((tab) => + tab.widgets.some((w) => w.id === widgetId), + ); + const tabId = tabWithWidget?.id; - const tabLayouts = allTabLayouts[tabId]; - const widgetLayout = tabLayouts?.desktop?.find( - (layout) => layout.i === widgetId, - ); + if (!isDefined(tabId)) { + return; + } - if (!isDefined(widgetLayout)) { - return; - } + const tabLayouts = allTabLayouts[tabId]; + const widgetLayout = tabLayouts?.desktop?.find( + (layout) => layout.i === widgetId, + ); - set(pageLayoutDraggedAreaState, { - x: widgetLayout.x, - y: widgetLayout.y, - w: widgetLayout.w, - h: widgetLayout.h, - }); + if (!isDefined(widgetLayout)) { + return; + } - const updatedLayouts = removeWidgetLayoutFromTab( - allTabLayouts, - tabId, - widgetId, - ); - set(pageLayoutCurrentLayoutsState, updatedLayouts); + store.set(pageLayoutDraggedAreaState, { + x: widgetLayout.x, + y: widgetLayout.y, + w: widgetLayout.w, + h: widgetLayout.h, + }); - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: removeWidgetFromTab(prev.tabs, tabId, widgetId), - })); + const updatedLayouts = removeWidgetLayoutFromTab( + allTabLayouts, + tabId, + widgetId, + ); + store.set(pageLayoutCurrentLayoutsState, updatedLayouts); - set(pageLayoutEditingWidgetIdState, null); - }, + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: removeWidgetFromTab(prev.tabs, tabId, widgetId), + })); + + store.set(pageLayoutEditingWidgetIdState, null); + }, [ pageLayoutCurrentLayoutsState, pageLayoutDraftState, pageLayoutDraggedAreaState, pageLayoutEditingWidgetIdState, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useReorderPageLayoutWidgets.ts b/packages/twenty-front/src/modules/page-layout/hooks/useReorderPageLayoutWidgets.ts index 81cadf5fa3..8f8cd82bbb 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useReorderPageLayoutWidgets.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useReorderPageLayoutWidgets.ts @@ -1,9 +1,10 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { type DropResult } from '@hello-pangea/dnd'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useReorderPageLayoutWidgets = ( @@ -15,33 +16,34 @@ export const useReorderPageLayoutWidgets = ( pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const reorderWidgets = useRecoilCallback( - ({ set }) => - (result: DropResult) => { - if (!result.destination) return; + const store = useStore(); - set(pageLayoutDraftState, (prev) => { - const tab = prev.tabs.find((t) => t.id === tabId); - if (!isDefined(tab)) return prev; + const reorderWidgets = useCallback( + (result: DropResult) => { + if (!result.destination) return; - const newWidgets = Array.from(tab.widgets ?? []); - const [removed] = newWidgets.splice(result.source.index, 1); - newWidgets.splice(result.destination!.index, 0, removed); + store.set(pageLayoutDraftState, (prev) => { + const tab = prev.tabs.find((t) => t.id === tabId); + if (!isDefined(tab)) return prev; - return { - ...prev, - tabs: prev.tabs.map((t) => - t.id === tabId ? { ...t, widgets: newWidgets } : t, - ), - }; - }); - }, - [tabId, pageLayoutDraftState], + const newWidgets = Array.from(tab.widgets ?? []); + const [removed] = newWidgets.splice(result.source.index, 1); + newWidgets.splice(result.destination!.index, 0, removed); + + return { + ...prev, + tabs: prev.tabs.map((t) => + t.id === tabId ? { ...t, widgets: newWidgets } : t, + ), + }; + }); + }, + [tabId, pageLayoutDraftState, store], ); return { reorderWidgets }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useResetDraftPageLayoutToPersistedPageLayout.ts b/packages/twenty-front/src/modules/page-layout/hooks/useResetDraftPageLayoutToPersistedPageLayout.ts index 6ff41fb7e4..2d343e554b 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useResetDraftPageLayoutToPersistedPageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useResetDraftPageLayoutToPersistedPageLayout.ts @@ -8,9 +8,9 @@ import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLa import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useResetDraftPageLayoutToPersistedPageLayout = ( @@ -25,17 +25,17 @@ export const useResetDraftPageLayoutToPersistedPageLayout = ( const tabListComponentInstanceId = getTabListInstanceIdFromPageLayoutId(componentInstanceId); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, componentInstanceId, ); - const pageLayoutPersistedState = useRecoilComponentCallbackState( + const pageLayoutPersistedState = useRecoilComponentStateCallbackStateV2( pageLayoutPersistedComponentState, componentInstanceId, ); - const pageLayoutCurrentLayoutsState = useRecoilComponentCallbackState( + const pageLayoutCurrentLayoutsState = useRecoilComponentStateCallbackStateV2( pageLayoutCurrentLayoutsComponentState, componentInstanceId, ); @@ -44,64 +44,56 @@ export const useResetDraftPageLayoutToPersistedPageLayout = ( instanceId: tabListComponentInstanceId, }); - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, componentInstanceId, ); - const fieldsWidgetGroupsPersistedState = useRecoilComponentCallbackState( - fieldsWidgetGroupsPersistedComponentState, - componentInstanceId, - ); + const fieldsWidgetGroupsPersistedState = + useRecoilComponentStateCallbackStateV2( + fieldsWidgetGroupsPersistedComponentState, + componentInstanceId, + ); - const resetDraftPageLayoutToPersistedPageLayout = useRecoilCallback( - ({ set, snapshot }) => - () => { - const pageLayoutPersisted = snapshot - .getLoadable(pageLayoutPersistedState) - .getValue(); + const resetDraftPageLayoutToPersistedPageLayout = useCallback(() => { + const pageLayoutPersisted = store.get(pageLayoutPersistedState); - if (isDefined(pageLayoutPersisted)) { - const currentActiveTabId = store.get(activeTabIdAtom); + if (isDefined(pageLayoutPersisted)) { + const currentActiveTabId = store.get(activeTabIdAtom); - const persistedTabIds = pageLayoutPersisted.tabs.map((tab) => tab.id); - const isActiveTabInPersistedTabs = - currentActiveTabId && persistedTabIds.includes(currentActiveTabId); + const persistedTabIds = pageLayoutPersisted.tabs.map((tab) => tab.id); + const isActiveTabInPersistedTabs = + currentActiveTabId && persistedTabIds.includes(currentActiveTabId); - if ( - !isActiveTabInPersistedTabs && - pageLayoutPersisted.tabs.length > 0 - ) { - store.set(activeTabIdAtom, pageLayoutPersisted.tabs[0].id); - } + if (!isActiveTabInPersistedTabs && pageLayoutPersisted.tabs.length > 0) { + store.set(activeTabIdAtom, pageLayoutPersisted.tabs[0].id); + } - set(pageLayoutDraftState, { - id: pageLayoutPersisted.id, - name: pageLayoutPersisted.name, - type: pageLayoutPersisted.type, - objectMetadataId: pageLayoutPersisted.objectMetadataId, - tabs: pageLayoutPersisted.tabs, - }); + store.set(pageLayoutDraftState, { + id: pageLayoutPersisted.id, + name: pageLayoutPersisted.name, + type: pageLayoutPersisted.type, + objectMetadataId: pageLayoutPersisted.objectMetadataId, + tabs: pageLayoutPersisted.tabs, + }); - const tabLayouts = convertPageLayoutToTabLayouts(pageLayoutPersisted); - set(pageLayoutCurrentLayoutsState, tabLayouts); + const tabLayouts = convertPageLayoutToTabLayouts(pageLayoutPersisted); + store.set(pageLayoutCurrentLayoutsState, tabLayouts); - const fieldsWidgetGroupsPersisted = snapshot - .getLoadable(fieldsWidgetGroupsPersistedState) - .getValue(); - set(fieldsWidgetGroupsDraftState, fieldsWidgetGroupsPersisted); - } - }, - [ - pageLayoutDraftState, - pageLayoutPersistedState, - pageLayoutCurrentLayoutsState, - fieldsWidgetGroupsDraftState, - fieldsWidgetGroupsPersistedState, - activeTabIdAtom, - store, - ], - ); + const fieldsWidgetGroupsPersisted = store.get( + fieldsWidgetGroupsPersistedState, + ); + store.set(fieldsWidgetGroupsDraftState, fieldsWidgetGroupsPersisted); + } + }, [ + pageLayoutDraftState, + pageLayoutPersistedState, + pageLayoutCurrentLayoutsState, + fieldsWidgetGroupsDraftState, + fieldsWidgetGroupsPersistedState, + activeTabIdAtom, + store, + ]); return { resetDraftPageLayoutToPersistedPageLayout, diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useSaveFieldsWidgetGroups.ts b/packages/twenty-front/src/modules/page-layout/hooks/useSaveFieldsWidgetGroups.ts index e032c34f54..4afd568004 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useSaveFieldsWidgetGroups.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useSaveFieldsWidgetGroups.ts @@ -1,10 +1,11 @@ import { UPSERT_FIELDS_WIDGET } from '@/page-layout/graphql/mutations/upsertFieldsWidget'; import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; import { fieldsWidgetGroupsPersistedComponentState } from '@/page-layout/states/fieldsWidgetGroupsPersistedComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useRefreshAllCoreViews } from '@/views/hooks/useRefreshAllCoreViews'; import { useMutation } from '@apollo/client'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type ViewFragmentFragment } from '~/generated-metadata/graphql'; @@ -39,15 +40,16 @@ type UseSaveFieldsWidgetGroupsParams = { export const useSaveFieldsWidgetGroups = ({ pageLayoutId, }: UseSaveFieldsWidgetGroupsParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const fieldsWidgetGroupsPersistedState = useRecoilComponentCallbackState( - fieldsWidgetGroupsPersistedComponentState, - pageLayoutId, - ); + const fieldsWidgetGroupsPersistedState = + useRecoilComponentStateCallbackStateV2( + fieldsWidgetGroupsPersistedComponentState, + pageLayoutId, + ); const [upsertFieldsWidgetMutation] = useMutation< UpsertFieldsWidgetResult, @@ -56,65 +58,60 @@ export const useSaveFieldsWidgetGroups = ({ const { refreshAllCoreViews } = useRefreshAllCoreViews(); - const saveFieldsWidgetGroups = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const allDraftGroups = snapshot - .getLoadable(fieldsWidgetGroupsDraftState) - .getValue(); - const allPersistedGroups = snapshot - .getLoadable(fieldsWidgetGroupsPersistedState) - .getValue(); + const store = useStore(); - const widgetIds = new Set([ - ...Object.keys(allDraftGroups), - ...Object.keys(allPersistedGroups), - ]); + const saveFieldsWidgetGroups = useCallback(async () => { + const allDraftGroups = store.get(fieldsWidgetGroupsDraftState); + const allPersistedGroups = store.get(fieldsWidgetGroupsPersistedState); - for (const widgetId of widgetIds) { - const draftGroups = allDraftGroups[widgetId] ?? []; + const widgetIds = new Set([ + ...Object.keys(allDraftGroups), + ...Object.keys(allPersistedGroups), + ]); - await upsertFieldsWidgetMutation({ - variables: { - input: { - widgetId, - groups: draftGroups.map((group) => ({ - id: group.id, - name: group.name, - position: group.position, - isVisible: group.isVisible, - fields: group.fields.flatMap((field) => { - if (!isDefined(field.viewFieldId)) { - return []; - } + for (const widgetId of widgetIds) { + const draftGroups = allDraftGroups[widgetId] ?? []; - return [ - { - viewFieldId: field.viewFieldId, - isVisible: field.isVisible, - position: field.position, - }, - ]; - }), - })), - }, - }, - }); - } + await upsertFieldsWidgetMutation({ + variables: { + input: { + widgetId, + groups: draftGroups.map((group) => ({ + id: group.id, + name: group.name, + position: group.position, + isVisible: group.isVisible, + fields: group.fields.flatMap((field) => { + if (!isDefined(field.viewFieldId)) { + return []; + } - set(fieldsWidgetGroupsPersistedState, allDraftGroups); + return [ + { + viewFieldId: field.viewFieldId, + isVisible: field.isVisible, + position: field.position, + }, + ]; + }), + })), + }, + }, + }); + } - await refreshAllCoreViews(); + store.set(fieldsWidgetGroupsPersistedState, allDraftGroups); - return { status: 'successful' as const }; - }, - [ - fieldsWidgetGroupsDraftState, - fieldsWidgetGroupsPersistedState, - upsertFieldsWidgetMutation, - refreshAllCoreViews, - ], - ); + await refreshAllCoreViews(); + + return { status: 'successful' as const }; + }, [ + fieldsWidgetGroupsDraftState, + fieldsWidgetGroupsPersistedState, + upsertFieldsWidgetMutation, + refreshAllCoreViews, + store, + ]); return { saveFieldsWidgetGroups }; }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts b/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts index 4e32f90abe..e0f574d52f 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts @@ -9,8 +9,9 @@ import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLa import { reInjectDynamicRelationWidgetsFromDraft } from '@/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft'; import { transformPageLayout } from '@/page-layout/utils/transformPageLayout'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { PageLayoutType } from '~/generated-metadata/graphql'; @@ -20,17 +21,19 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => { pageLayoutIdFromProps, ); - const pageLayoutPersistedCallbackState = useRecoilComponentCallbackState( - pageLayoutPersistedComponentState, - pageLayoutId, - ); + const pageLayoutPersistedCallbackState = + useRecoilComponentStateCallbackStateV2( + pageLayoutPersistedComponentState, + pageLayoutId, + ); - const pageLayoutCurrentLayoutsCallbackState = useRecoilComponentCallbackState( - pageLayoutCurrentLayoutsComponentState, - pageLayoutId, - ); + const pageLayoutCurrentLayoutsCallbackState = + useRecoilComponentStateCallbackStateV2( + pageLayoutCurrentLayoutsComponentState, + pageLayoutId, + ); - const pageLayoutDraftCallbackState = useRecoilComponentCallbackState( + const pageLayoutDraftCallbackState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); @@ -38,54 +41,49 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => { const { updatePageLayoutWithTabsAndWidgets } = useUpdatePageLayoutWithTabsAndWidgets(); - const savePageLayout = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const pageLayoutDraft = snapshot - .getLoadable(pageLayoutDraftCallbackState) - .getValue(); - const updateInput = - convertPageLayoutDraftToUpdateInput(pageLayoutDraft); + const store = useStore(); - const result = await updatePageLayoutWithTabsAndWidgets( - pageLayoutId, - updateInput, - ); + const savePageLayout = useCallback(async () => { + const pageLayoutDraft = store.get(pageLayoutDraftCallbackState); + const updateInput = convertPageLayoutDraftToUpdateInput(pageLayoutDraft); - if (result.status === 'successful') { - const updatedPageLayout = - result.response.data?.updatePageLayoutWithTabsAndWidgets; - - if (isDefined(updatedPageLayout)) { - const serverLayout: PageLayout = - transformPageLayout(updatedPageLayout); - - const pageLayoutToPersist = - serverLayout.type === PageLayoutType.RECORD_PAGE - ? reInjectDynamicRelationWidgetsFromDraft( - serverLayout, - pageLayoutDraft, - ) - : serverLayout; - - set(pageLayoutPersistedCallbackState, pageLayoutToPersist); - set( - pageLayoutCurrentLayoutsCallbackState, - convertPageLayoutToTabLayouts(pageLayoutToPersist), - ); - } - } - - return result; - }, - [ - pageLayoutCurrentLayoutsCallbackState, - pageLayoutDraftCallbackState, + const result = await updatePageLayoutWithTabsAndWidgets( pageLayoutId, - pageLayoutPersistedCallbackState, - updatePageLayoutWithTabsAndWidgets, - ], - ); + updateInput, + ); + + if (result.status === 'successful') { + const updatedPageLayout = + result.response.data?.updatePageLayoutWithTabsAndWidgets; + + if (isDefined(updatedPageLayout)) { + const serverLayout: PageLayout = transformPageLayout(updatedPageLayout); + + const pageLayoutToPersist = + serverLayout.type === PageLayoutType.RECORD_PAGE + ? reInjectDynamicRelationWidgetsFromDraft( + serverLayout, + pageLayoutDraft, + ) + : serverLayout; + + store.set(pageLayoutPersistedCallbackState, pageLayoutToPersist); + store.set( + pageLayoutCurrentLayoutsCallbackState, + convertPageLayoutToTabLayouts(pageLayoutToPersist), + ); + } + } + + return result; + }, [ + pageLayoutCurrentLayoutsCallbackState, + pageLayoutDraftCallbackState, + pageLayoutId, + pageLayoutPersistedCallbackState, + updatePageLayoutWithTabsAndWidgets, + store, + ]); return { savePageLayout }; }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts b/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts index ffd56c6d05..fc210c33f1 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts @@ -1,13 +1,15 @@ import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; -import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; +import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { currentPageLayoutIdState } from '@/page-layout/states/currentPageLayoutIdState'; import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useSetIsPageLayoutInEditMode = (pageLayoutIdFromProps: string) => { const pageLayoutId = useAvailableComponentInstanceIdOrThrow( @@ -15,43 +17,48 @@ export const useSetIsPageLayoutInEditMode = (pageLayoutIdFromProps: string) => { pageLayoutIdFromProps, ); - const isPageLayoutInEditModeState = useRecoilComponentCallbackState( + const isPageLayoutInEditModeState = useRecoilComponentStateCallbackStateV2( isPageLayoutInEditModeComponentState, pageLayoutId, ); const contextStoreIsFullTabWidgetInEditModeState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( contextStoreIsPageInEditModeComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const setIsPageLayoutInEditMode = useRecoilCallback( - ({ set, snapshot }) => - (value: boolean) => { - set(isPageLayoutInEditModeState, value); + const store = useStore(); - set(contextStoreIsFullTabWidgetInEditModeState, value); + const setIsPageLayoutInEditMode = useCallback( + (value: boolean) => { + store.set(isPageLayoutInEditModeState, value); - set(currentPageLayoutIdState, value ? pageLayoutId : null); + store.set(contextStoreIsFullTabWidgetInEditModeState, value); - const isCommandMenuOpened = snapshot - .getLoadable(isCommandMenuOpenedState) - .getValue(); + jotaiStore.set( + currentPageLayoutIdState.atom, + value ? pageLayoutId : null, + ); - if (isCommandMenuOpened) { - set( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, - }), - value, - ); - } - }, + const isCommandMenuOpened = jotaiStore.get( + isCommandMenuOpenedStateV2.atom, + ); + + if (isCommandMenuOpened) { + store.set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID, + }), + value, + ); + } + }, [ isPageLayoutInEditModeState, contextStoreIsFullTabWidgetInEditModeState, pageLayoutId, + store, ], ); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useStartPageLayoutDragSelection.ts b/packages/twenty-front/src/modules/page-layout/hooks/useStartPageLayoutDragSelection.ts index 38df02bcb0..2c3ae8cab5 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useStartPageLayoutDragSelection.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useStartPageLayoutDragSelection.ts @@ -1,7 +1,8 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { pageLayoutSelectedCellsComponentState } from '@/page-layout/states/pageLayoutSelectedCellsComponentState'; export const useStartPageLayoutDragSelection = ( @@ -12,18 +13,16 @@ export const useStartPageLayoutDragSelection = ( pageLayoutIdFromProps, ); - const pageLayoutSelectedCellsState = useRecoilComponentCallbackState( + const pageLayoutSelectedCellsState = useRecoilComponentStateCallbackStateV2( pageLayoutSelectedCellsComponentState, pageLayoutId, ); - const startPageLayoutDragSelection = useRecoilCallback( - ({ set }) => - () => { - set(pageLayoutSelectedCellsState, new Set()); - }, - [pageLayoutSelectedCellsState], - ); + const store = useStore(); + + const startPageLayoutDragSelection = useCallback(() => { + store.set(pageLayoutSelectedCellsState, new Set()); + }, [pageLayoutSelectedCellsState, store]); return { startPageLayoutDragSelection }; }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutTab.ts index 138b94caed..6a99c7d52a 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutTab.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutTab.ts @@ -1,8 +1,9 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; export const useUpdatePageLayoutTab = (pageLayoutIdFromProps?: string) => { @@ -11,22 +12,23 @@ export const useUpdatePageLayoutTab = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const updatePageLayoutTab = useRecoilCallback( - ({ set }) => - (tabId: string, updates: Partial) => { - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: prev.tabs.map((tab) => - tab.id === tabId ? { ...tab, ...updates } : tab, - ), - })); - }, - [pageLayoutDraftState], + const store = useStore(); + + const updatePageLayoutTab = useCallback( + (tabId: string, updates: Partial) => { + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: prev.tabs.map((tab) => + tab.id === tabId ? { ...tab, ...updates } : tab, + ), + })); + }, + [pageLayoutDraftState, store], ); return { updatePageLayoutTab }; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutWidget.ts index acf0d1bccd..8e3fe30cf8 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useUpdatePageLayoutWidget.ts @@ -2,8 +2,9 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/context import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useUpdatePageLayoutWidget = (pageLayoutIdFromProps?: string) => { const pageLayoutId = useAvailableComponentInstanceIdOrThrow( @@ -11,25 +12,26 @@ export const useUpdatePageLayoutWidget = (pageLayoutIdFromProps?: string) => { pageLayoutIdFromProps, ); - const pageLayoutDraftState = useRecoilComponentCallbackState( + const pageLayoutDraftState = useRecoilComponentStateCallbackStateV2( pageLayoutDraftComponentState, pageLayoutId, ); - const updatePageLayoutWidget = useRecoilCallback( - ({ set }) => - (widgetId: string, updates: Partial) => { - set(pageLayoutDraftState, (prev) => ({ - ...prev, - tabs: prev.tabs.map((tab) => ({ - ...tab, - widgets: tab.widgets.map((widget) => - widget.id === widgetId ? { ...widget, ...updates } : widget, - ), - })), - })); - }, - [pageLayoutDraftState], + const store = useStore(); + + const updatePageLayoutWidget = useCallback( + (widgetId: string, updates: Partial) => { + store.set(pageLayoutDraftState, (prev) => ({ + ...prev, + tabs: prev.tabs.map((tab) => ({ + ...tab, + widgets: tab.widgets.map((widget) => + widget.id === widgetId ? { ...widget, ...updates } : widget, + ), + })), + })); + }, + [pageLayoutDraftState, store], ); return { updatePageLayoutWidget }; diff --git a/packages/twenty-front/src/modules/page-layout/states/currentPageLayoutIdState.ts b/packages/twenty-front/src/modules/page-layout/states/currentPageLayoutIdState.ts index 5cbf25d4db..45504046d5 100644 --- a/packages/twenty-front/src/modules/page-layout/states/currentPageLayoutIdState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/currentPageLayoutIdState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const currentPageLayoutIdState = createState({ +export const currentPageLayoutIdState = createStateV2({ key: 'currentPageLayoutIdState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsDraftComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsDraftComponentState.ts index 93ab19e09f..b6aefd393b 100644 --- a/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsDraftComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsDraftComponentState.ts @@ -1,9 +1,9 @@ import { type FieldsWidgetGroup } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const fieldsWidgetGroupsDraftComponentState = createComponentState< +export const fieldsWidgetGroupsDraftComponentState = createComponentStateV2< Record >({ key: 'fieldsWidgetGroupsDraftComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsPersistedComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsPersistedComponentState.ts index 3545b4b3a8..8afcc2ea4e 100644 --- a/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsPersistedComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/fieldsWidgetGroupsPersistedComponentState.ts @@ -1,9 +1,9 @@ import { type FieldsWidgetGroup } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const fieldsWidgetGroupsPersistedComponentState = createComponentState< +export const fieldsWidgetGroupsPersistedComponentState = createComponentStateV2< Record >({ key: 'fieldsWidgetGroupsPersistedComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState.ts index 02310f66e5..b44da0de84 100644 --- a/packages/twenty-front/src/modules/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const hasInitializedFieldsWidgetGroupsDraftComponentState = - createComponentState>({ + createComponentStateV2>({ key: 'hasInitializedFieldsWidgetGroupsDraftComponentState', defaultValue: {}, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/isPageLayoutInEditModeComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/isPageLayoutInEditModeComponentState.ts index 2e411dfccd..6b66f9ec0c 100644 --- a/packages/twenty-front/src/modules/page-layout/states/isPageLayoutInEditModeComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/isPageLayoutInEditModeComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const isPageLayoutInEditModeComponentState = - createComponentState({ + createComponentStateV2({ key: 'isPageLayoutInEditModeComponentState', defaultValue: false, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/isPageLayoutTabDraggingComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/isPageLayoutTabDraggingComponentState.ts index d598f6a35c..5a7d752b5a 100644 --- a/packages/twenty-front/src/modules/page-layout/states/isPageLayoutTabDraggingComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/isPageLayoutTabDraggingComponentState.ts @@ -1,8 +1,8 @@ import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const isPageLayoutTabDraggingComponentState = - createComponentState({ + createComponentStateV2({ key: 'isPageLayoutTabDraggingComponentState', defaultValue: false, componentInstanceContext: TabListComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentBreakpointComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentBreakpointComponentState.ts index 6e71380160..998940dfc6 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentBreakpointComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentBreakpointComponentState.ts @@ -1,10 +1,10 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type PageLayoutBreakpoint } from '@/page-layout/constants/PageLayoutBreakpoints'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutCurrentBreakpointComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutCurrentBreakpointComponentState', defaultValue: 'desktop', componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentLayoutsComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentLayoutsComponentState.ts index 1b43aa16c9..9877a9a768 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentLayoutsComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutCurrentLayoutsComponentState.ts @@ -1,10 +1,10 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type TabLayouts } from '@/page-layout/types/TabLayouts'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutCurrentLayoutsComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutCurrentLayoutsComponentState', defaultValue: {}, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraftComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraftComponentState.ts index 0d19653308..044ec0ce6c 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraftComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraftComponentState.ts @@ -1,11 +1,11 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutType } from '~/generated-metadata/graphql'; import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutDraftComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutDraftComponentState', defaultValue: { id: '', diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggedAreaComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggedAreaComponentState.ts index 0555927f4d..409c964180 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggedAreaComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggedAreaComponentState.ts @@ -1,10 +1,10 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type PageLayoutDraggedArea } from '@/page-layout/types/page-layout-dragged-area'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutDraggedAreaComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutDraggedAreaComponentState', defaultValue: null, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggingWidgetIdComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggingWidgetIdComponentState.ts index 4a16f216be..a356c5aba0 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggingWidgetIdComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutDraggingWidgetIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const pageLayoutDraggingWidgetIdComponentState = createComponentState< +export const pageLayoutDraggingWidgetIdComponentState = createComponentStateV2< string | null >({ key: 'pageLayoutDraggingWidgetIdComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutEditingWidgetIdComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutEditingWidgetIdComponentState.ts index c276e9b92b..9e6f6cb301 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutEditingWidgetIdComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutEditingWidgetIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const pageLayoutEditingWidgetIdComponentState = createComponentState< +export const pageLayoutEditingWidgetIdComponentState = createComponentStateV2< string | null >({ key: 'pageLayoutEditingWidgetIdComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts index 61db2da1fd..720faf27ed 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutIsInitializedComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutIsInitializedComponentState', defaultValue: false, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutPersistedComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutPersistedComponentState.ts index 408683f43a..3c00731176 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutPersistedComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutPersistedComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type PageLayout } from '@/page-layout/types/PageLayout'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const pageLayoutPersistedComponentState = createComponentState< +export const pageLayoutPersistedComponentState = createComponentStateV2< PageLayout | undefined >({ key: 'pageLayoutPersistedComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutResizingWidgetIdComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutResizingWidgetIdComponentState.ts index f36868d25e..5d5822aa2d 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutResizingWidgetIdComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutResizingWidgetIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const pageLayoutResizingWidgetIdComponentState = createComponentState< +export const pageLayoutResizingWidgetIdComponentState = createComponentStateV2< string | null >({ key: 'pageLayoutResizingWidgetIdComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutSelectedCellsComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutSelectedCellsComponentState.ts index b7ddad373c..986594e819 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutSelectedCellsComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutSelectedCellsComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const pageLayoutSelectedCellsComponentState = createComponentState< +export const pageLayoutSelectedCellsComponentState = createComponentStateV2< Set >({ key: 'pageLayoutSelectedCellsComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState.ts index d2d2d6af13..43d428dc9a 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutTabListCurrentDragDroppableIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutTabListCurrentDragDroppableIdComponentState', defaultValue: undefined, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState.ts index 5d652d5f50..1c4f65b66c 100644 --- a/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; export const pageLayoutTabSettingsOpenTabIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'pageLayoutTabSettingsOpenTabIdComponentState', defaultValue: null, componentInstanceContext: PageLayoutComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/states/recordPageLayoutsState.ts b/packages/twenty-front/src/modules/page-layout/states/recordPageLayoutsState.ts index bf5e625d0d..f7a6129ceb 100644 --- a/packages/twenty-front/src/modules/page-layout/states/recordPageLayoutsState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/recordPageLayoutsState.ts @@ -1,7 +1,7 @@ import { type PageLayout } from '@/page-layout/types/PageLayout'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const recordPageLayoutsState = createState({ +export const recordPageLayoutsState = createStateV2({ key: 'recordPageLayoutsState', defaultValue: [], }); diff --git a/packages/twenty-front/src/modules/page-layout/states/savedPageLayoutsComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/savedPageLayoutsComponentState.ts index 17149255a8..d82fa8d973 100644 --- a/packages/twenty-front/src/modules/page-layout/states/savedPageLayoutsComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/states/savedPageLayoutsComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type PageLayout } from '@/page-layout/types/PageLayout'; import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; -export const savedPageLayoutsComponentState = createComponentState< +export const savedPageLayoutsComponentState = createComponentStateV2< PageLayout[] >({ key: 'savedPageLayoutsComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts b/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts index 534393bd42..a5828a3db5 100644 --- a/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts +++ b/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts @@ -1,19 +1,17 @@ import { recordPageLayoutsState } from '@/page-layout/states/recordPageLayoutsState'; import { type PageLayout } from '@/page-layout/types/PageLayout'; -import { selectorFamily } from 'recoil'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; -export const recordPageLayoutByObjectMetadataIdFamilySelector = selectorFamily< - PageLayout | undefined, - { objectMetadataId: string } ->({ - key: 'recordPageLayoutByObjectMetadataIdFamilySelector', - get: - ({ objectMetadataId }) => - ({ get }) => { - const recordPageLayouts = get(recordPageLayoutsState); +export const recordPageLayoutByObjectMetadataIdFamilySelector = + createFamilySelectorV2({ + key: 'recordPageLayoutByObjectMetadataIdFamilySelector', + get: + ({ objectMetadataId }) => + ({ get }) => { + const recordPageLayouts = get(recordPageLayoutsState); - return recordPageLayouts.find( - (pageLayout) => pageLayout.objectMetadataId === objectMetadataId, - ); - }, -}); + return recordPageLayouts.find( + (pageLayout) => pageLayout.objectMetadataId === objectMetadataId, + ); + }, + }); diff --git a/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutFromIdFamilySelector.ts b/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutFromIdFamilySelector.ts index 49cbcbfabf..159fc958da 100644 --- a/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutFromIdFamilySelector.ts +++ b/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutFromIdFamilySelector.ts @@ -1,8 +1,8 @@ import { recordPageLayoutsState } from '@/page-layout/states/recordPageLayoutsState'; import { type PageLayout } from '@/page-layout/types/PageLayout'; -import { selectorFamily } from 'recoil'; +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; -export const recordPageLayoutFromIdFamilySelector = selectorFamily< +export const recordPageLayoutFromIdFamilySelector = createFamilySelectorV2< PageLayout | undefined, { pageLayoutId: string } >({ diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/DashboardWidgetPlaceholder.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/DashboardWidgetPlaceholder.tsx index 0655a177ee..69f797089f 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/DashboardWidgetPlaceholder.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/DashboardWidgetPlaceholder.tsx @@ -5,7 +5,7 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPag import { WidgetCard } from '@/page-layout/widgets/widget-card/components/WidgetCard'; import { WidgetCardHeader } from '@/page-layout/widgets/widget-card/components/WidgetCardHeader'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { t } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; import { CommandMenuPages } from 'twenty-shared/types'; @@ -23,7 +23,7 @@ export const DashboardWidgetPlaceholder = () => { PageLayoutComponentInstanceContext, ); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx index 574aea62e1..44ed06f41d 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx @@ -22,8 +22,8 @@ import { WidgetCardContent } from '@/page-layout/widgets/widget-card/components/ import { WidgetCardHeader } from '@/page-layout/widgets/widget-card/components/WidgetCardHeader'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentFamilyStateV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { type MouseEvent } from 'react'; @@ -50,19 +50,19 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => { const { deletePageLayoutWidget } = useDeletePageLayoutWidget(); const { handleEditWidget } = useEditPageLayoutWidget(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); - const draggingWidgetId = useRecoilComponentValue( + const draggingWidgetId = useRecoilComponentValueV2( pageLayoutDraggingWidgetIdComponentState, ); - const resizingWidgetId = useRecoilComponentValue( + const resizingWidgetId = useRecoilComponentValueV2( pageLayoutResizingWidgetIdComponentState, ); - const currentlyEditingWidgetId = useRecoilComponentValue( + const currentlyEditingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, ); @@ -109,7 +109,7 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => { deletePageLayoutWidget(widget.id); }; - const setIsHovered = useSetRecoilComponentFamilyState( + const setIsHovered = useSetRecoilComponentFamilyStateV2( widgetCardHoveredComponentFamilyState, widget.id, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/DashboardWidgetPlaceholder.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/DashboardWidgetPlaceholder.stories.tsx index b5cbf4abb8..afc910a47c 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/DashboardWidgetPlaceholder.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/DashboardWidgetPlaceholder.stories.tsx @@ -11,7 +11,6 @@ import { type PageLayout } from '@/page-layout/types/PageLayout'; import { DashboardWidgetPlaceholder } from '@/page-layout/widgets/components/DashboardWidgetPlaceholder'; import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext'; import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { type MutableSnapshot } from 'recoil'; import { ComponentDecorator } from 'twenty-ui/testing'; import { PageLayoutTabLayoutMode, @@ -34,22 +33,20 @@ const meta: Meta = { component: DashboardWidgetPlaceholder, decorators: [ (Story) => { - const initializeState = (snapshot: MutableSnapshot) => { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - mockPageLayout, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + mockPageLayout, + ); return ( - + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget(widget); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget(widget); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + PageLayoutType.RECORD_PAGE, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + isPageLayoutInEditModeComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + false, + ); + jotaiStore.set( + recordStoreFamilyState.atomFamily(TEST_RECORD_ID), + mockCompanyRecord, + ); + // Set the related WorkspaceMember record for relation field display + if ( + mockCompanyRecord.accountOwner !== null && + mockCompanyRecord.accountOwner !== undefined + ) { jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, + recordStoreFamilyState.atomFamily( + (mockCompanyRecord.accountOwner as ObjectRecord).id, + ), + mockCompanyRecord.accountOwner, ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - PageLayoutType.RECORD_PAGE, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - isPageLayoutInEditModeComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - false, - ); - snapshot.set(recordStoreFamilyState(TEST_RECORD_ID), mockCompanyRecord); - // Set the related WorkspaceMember record for relation field display - if ( - mockCompanyRecord.accountOwner !== null && - mockCompanyRecord.accountOwner !== undefined - ) { - snapshot.set( - recordStoreFamilyState( - (mockCompanyRecord.accountOwner as ObjectRecord).id, - ), - mockCompanyRecord.accountOwner, - ); - } - }; + } return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - PageLayoutType.RECORD_PAGE, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - isPageLayoutInEditModeComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - false, - ); - snapshot.set(recordStoreFamilyState(TEST_RECORD_ID), mockCompanyRecord); - snapshot.set( - recordStoreFamilyState(TEST_PERSON_RECORD_ID), - mockPersonRecord, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + PageLayoutType.RECORD_PAGE, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + isPageLayoutInEditModeComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + false, + ); + jotaiStore.set( + recordStoreFamilyState.atomFamily(TEST_RECORD_ID), + mockCompanyRecord, + ); + jotaiStore.set( + recordStoreFamilyState.atomFamily(TEST_PERSON_RECORD_ID), + mockPersonRecord, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - PageLayoutType.RECORD_PAGE, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - isPageLayoutInEditModeComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - false, - ); - snapshot.set(recordStoreFamilyState(TEST_RECORD_ID), mockCompanyRecord); - snapshot.set( - recordStoreFamilyState(TEST_PERSON_RECORD_ID), - mockPersonRecord, - ); - // Set hover state to make the "See all" button visible - snapshot.set( - widgetCardHoveredComponentFamilyState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - familyKey: WIDGET_ID_ONE_TO_MANY_RELATION, - }), - true, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + PageLayoutType.RECORD_PAGE, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + isPageLayoutInEditModeComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + false, + ); + jotaiStore.set( + recordStoreFamilyState.atomFamily(TEST_RECORD_ID), + mockCompanyRecord, + ); + jotaiStore.set( + recordStoreFamilyState.atomFamily(TEST_PERSON_RECORD_ID), + mockPersonRecord, + ); + // Set hover state to make the "See all" button visible + jotaiStore.set( + widgetCardHoveredComponentFamilyState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + familyKey: WIDGET_ID_ONE_TO_MANY_RELATION, + }), + true, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - PageLayoutType.RECORD_PAGE, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + PageLayoutType.RECORD_PAGE, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - PageLayoutType.RECORD_PAGE, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + PageLayoutType.RECORD_PAGE, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); return (
- + = { deletedAt: null, }; - const initializeState = (snapshot: MutableSnapshot) => { + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + + if (state === 'hover') { jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, + widgetCardHoveredComponentFamilyState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + familyKey: widget.id, + }), + true, ); - jotaiStore.set(isAppMetadataReadyState.atom, true); + } - if (state === 'hover') { - snapshot.set( - widgetCardHoveredComponentFamilyState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - familyKey: widget.id, - }), - true, - ); - } - - if (state === 'selected') { - snapshot.set( - pageLayoutEditingWidgetIdComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - widget.id, - ); - } - - if (state === 'dragging') { - snapshot.set( - pageLayoutDraggingWidgetIdComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - widget.id, - ); - } - - // currentUserWorkspaceState is now a Jotai state, set it directly - if (isRestricted === true) { - jotaiStore.set(currentUserWorkspaceState.atom, { - permissionFlags: [], - twoFactorAuthenticationMethodSummary: null, - objectsPermissions: [ - { - objectMetadataId: companyObjectMetadataItem.id, - canReadObjectRecords: false, - canUpdateObjectRecords: false, - canSoftDeleteObjectRecords: false, - canDestroyObjectRecords: false, - restrictedFields: {}, - rowLevelPermissionPredicates: [], - rowLevelPermissionPredicateGroups: [], - }, - ], - }); - } else { - jotaiStore.set(currentUserWorkspaceState.atom, { - permissionFlags: [], - twoFactorAuthenticationMethodSummary: null, - objectsPermissions: [ - { - objectMetadataId: companyObjectMetadataItem.id, - canReadObjectRecords: true, - canUpdateObjectRecords: true, - canSoftDeleteObjectRecords: true, - canDestroyObjectRecords: true, - restrictedFields: {}, - rowLevelPermissionPredicates: [], - rowLevelPermissionPredicateGroups: [], - }, - ], - }); - } - - const pageLayoutData: PageLayout = { - id: PAGE_LAYOUT_TEST_INSTANCE_ID, - name: 'Mock Page Layout', - type: pageLayoutType, - objectMetadataId: companyObjectMetadataItem.id, - tabs: - variant === 'side-column' - ? [ - { - __typename: 'PageLayoutTab', - applicationId: '', - id: 'pinned-tab', - title: 'Pinned Tab', - position: 0, - pageLayoutId: PAGE_LAYOUT_TEST_INSTANCE_ID, - widgets: [widget], - createdAt: '2024-01-01T00:00:00Z', - updatedAt: '2024-01-01T00:00:00Z', - deletedAt: null, - }, - { - __typename: 'PageLayoutTab', - applicationId: '', - id: 'other-tab', - title: 'Other Tab', - position: 1, - pageLayoutId: PAGE_LAYOUT_TEST_INSTANCE_ID, - widgets: [], - createdAt: '2024-01-01T00:00:00Z', - updatedAt: '2024-01-01T00:00:00Z', - deletedAt: null, - }, - ] - : [ - { - __typename: 'PageLayoutTab', - applicationId: '', - id: TAB_ID_OVERVIEW, - title: 'Overview', - position: 0, - pageLayoutId: PAGE_LAYOUT_TEST_INSTANCE_ID, - widgets: [widget], - createdAt: '2024-01-01T00:00:00Z', - updatedAt: '2024-01-01T00:00:00Z', - deletedAt: null, - }, - ], - createdAt: '2024-01-01T00:00:00Z', - updatedAt: '2024-01-01T00:00:00Z', - deletedAt: null, - }; - - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ + if (state === 'selected') { + jotaiStore.set( + pageLayoutEditingWidgetIdComponentState.atomFamily({ instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, }), - pageLayoutData, + widget.id, ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ + } + + if (state === 'dragging') { + jotaiStore.set( + pageLayoutDraggingWidgetIdComponentState.atomFamily({ instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, }), - pageLayoutData, - ); - snapshot.set( - isPageLayoutInEditModeComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - isInEditMode, + widget.id, ); + } + + // currentUserWorkspaceState is now a Jotai state, set it directly + if (isRestricted === true) { + jotaiStore.set(currentUserWorkspaceState.atom, { + permissionFlags: [], + twoFactorAuthenticationMethodSummary: null, + objectsPermissions: [ + { + objectMetadataId: companyObjectMetadataItem.id, + canReadObjectRecords: false, + canUpdateObjectRecords: false, + canSoftDeleteObjectRecords: false, + canDestroyObjectRecords: false, + restrictedFields: {}, + rowLevelPermissionPredicates: [], + rowLevelPermissionPredicateGroups: [], + }, + ], + }); + } else { + jotaiStore.set(currentUserWorkspaceState.atom, { + permissionFlags: [], + twoFactorAuthenticationMethodSummary: null, + objectsPermissions: [ + { + objectMetadataId: companyObjectMetadataItem.id, + canReadObjectRecords: true, + canUpdateObjectRecords: true, + canSoftDeleteObjectRecords: true, + canDestroyObjectRecords: true, + restrictedFields: {}, + rowLevelPermissionPredicates: [], + rowLevelPermissionPredicateGroups: [], + }, + ], + }); + } + + const pageLayoutData: PageLayout = { + id: PAGE_LAYOUT_TEST_INSTANCE_ID, + name: 'Mock Page Layout', + type: pageLayoutType, + objectMetadataId: companyObjectMetadataItem.id, + tabs: + variant === 'side-column' + ? [ + { + __typename: 'PageLayoutTab', + applicationId: '', + id: 'pinned-tab', + title: 'Pinned Tab', + position: 0, + pageLayoutId: PAGE_LAYOUT_TEST_INSTANCE_ID, + widgets: [widget], + createdAt: '2024-01-01T00:00:00Z', + updatedAt: '2024-01-01T00:00:00Z', + deletedAt: null, + }, + { + __typename: 'PageLayoutTab', + applicationId: '', + id: 'other-tab', + title: 'Other Tab', + position: 1, + pageLayoutId: PAGE_LAYOUT_TEST_INSTANCE_ID, + widgets: [], + createdAt: '2024-01-01T00:00:00Z', + updatedAt: '2024-01-01T00:00:00Z', + deletedAt: null, + }, + ] + : [ + { + __typename: 'PageLayoutTab', + applicationId: '', + id: TAB_ID_OVERVIEW, + title: 'Overview', + position: 0, + pageLayoutId: PAGE_LAYOUT_TEST_INSTANCE_ID, + widgets: [widget], + createdAt: '2024-01-01T00:00:00Z', + updatedAt: '2024-01-01T00:00:00Z', + deletedAt: null, + }, + ], + createdAt: '2024-01-01T00:00:00Z', + updatedAt: '2024-01-01T00:00:00Z', + deletedAt: null, }; + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + isPageLayoutInEditModeComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + isInEditMode, + ); + const containerClassName = state === 'hover' ? 'hover-state' : ''; return ( @@ -1815,7 +1795,7 @@ export const Catalog: CatalogStory = { > - + { resolvedFieldMetadataId ?? '', ); - const record = useRecoilValue( - recordStoreFamilySelector({ - recordId: targetRecord.id, - fieldName: fieldMetadataItem?.name ?? '', - }), - ); + const record = useFamilySelectorValueV2(recordStoreFamilySelectorV2, { + recordId: targetRecord.id, + fieldName: fieldMetadataItem?.name ?? '', + }); if (isPrefetchLoading) { return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetCellEditModePortal.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetCellEditModePortal.tsx index b4793a4468..9d431d6ff3 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetCellEditModePortal.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetCellEditModePortal.tsx @@ -7,7 +7,7 @@ import { FieldWidgetInputContextProvider } from '@/page-layout/widgets/field/com import { useIsFieldWidgetEditing } from '@/page-layout/widgets/field/hooks/useIsFieldWidgetEditing'; import { useOpenFieldWidgetFieldInputEditMode } from '@/page-layout/widgets/field/hooks/useOpenFieldWidgetFieldInputEditMode'; import { fieldWidgetHoverComponentState } from '@/page-layout/widgets/field/states/fieldWidgetHoverComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; type FieldWidgetCellEditModePortalProps = { objectMetadataItem: ObjectMetadataItem; @@ -24,7 +24,7 @@ export const FieldWidgetCellEditModePortal = ({ }: FieldWidgetCellEditModePortalProps) => { const { isEditing } = useIsFieldWidgetEditing(); - const setIsHovered = useSetRecoilComponentState( + const setIsHovered = useSetRecoilComponentStateV2( fieldWidgetHoverComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx index c4326aa945..94213e6bb8 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx @@ -17,7 +17,7 @@ import { generateFieldWidgetInstanceId } from '@/page-layout/widgets/field/utils import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import styled from '@emotion/styled'; const StyledContainer = styled.div` @@ -41,7 +41,7 @@ export const FieldWidgetDisplay = ({ }: FieldWidgetDisplayProps) => { const widget = useCurrentWidget(); - const [isHovered, setIsHovered] = useRecoilComponentState( + const [isHovered, setIsHovered] = useRecoilComponentStateV2( fieldWidgetHoverComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx index 99741c7832..359695cdc0 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/__stories__/FieldWidget.stories.tsx @@ -5,7 +5,6 @@ import { } from '@apollo/client'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { MemoryRouter } from 'react-router-dom'; -import { type MutableSnapshot } from 'recoil'; import { expect, userEvent, waitFor, within } from 'storybook/test'; import { ApolloCoreClientContext } from '@/object-metadata/contexts/ApolloCoreClientContext'; @@ -259,13 +258,9 @@ const mockCompanyRecord: ObjectRecord = { }, }; -// Sets a record in both Recoil and Jotai stores so field display hooks can read it -const setRecordInStores = ( - snapshot: MutableSnapshot, - recordId: string, - record: ObjectRecord, -) => { - snapshot.set(recordStoreFamilyState(recordId), record); +// Sets a record in both Jotai stores so field display hooks can read it +const setRecordInStores = (recordId: string, record: ObjectRecord) => { + jotaiStore.set(recordStoreFamilyState.atomFamily(recordId), record); jotaiStore.set(recordStoreFamilyStateV2.atomFamily(recordId), record); }; @@ -364,39 +359,34 @@ export const TextFieldWidget: Story = { deletedAt: null, }; - const initializeState = (snapshot: MutableSnapshot) => { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); + // Set the related WorkspaceMember record for relation field display + if ( + mockCompanyRecord.accountOwner !== null && + mockCompanyRecord.accountOwner !== undefined + ) { + setRecordInStores( + mockCompanyRecord.accountOwner.id, + mockCompanyRecord.accountOwner, ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - // Set the related WorkspaceMember record for relation field display - if ( - mockCompanyRecord.accountOwner !== null && - mockCompanyRecord.accountOwner !== undefined - ) { - setRecordInStores( - snapshot, - mockCompanyRecord.accountOwner.id, - mockCompanyRecord.accountOwner, - ); - } - }; + } return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - // Set the related Person record for ONE_TO_MANY relation display - setRecordInStores(snapshot, TEST_PERSON_RECORD_ID, mockPersonRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); + // Set the related Person record for ONE_TO_MANY relation display + setRecordInStores(TEST_PERSON_RECORD_ID, mockPersonRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - personObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_PERSON_RECORD_ID, mockPersonRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + personObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_PERSON_RECORD_ID, mockPersonRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - personObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_PERSON_RECORD_ID, mockPersonRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + personObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_PERSON_RECORD_ID, mockPersonRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - opportunityObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores( - snapshot, - TEST_OPPORTUNITY_RECORD_ID, - mockOpportunityRecord, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + opportunityObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_OPPORTUNITY_RECORD_ID, mockOpportunityRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - timelineActivityObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores( - snapshot, - TEST_TIMELINE_ACTIVITY_RECORD_ID, - mockTimelineActivityRecord, - ); - // Set the related WorkspaceMember record for TimelineActivity relation display - setRecordInStores( - snapshot, - 'test-workspace-member-xyz', - mockWorkspaceMemberRecord, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + timelineActivityObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores( + TEST_TIMELINE_ACTIVITY_RECORD_ID, + mockTimelineActivityRecord, + ); + // Set the related WorkspaceMember record for TimelineActivity relation display + setRecordInStores('test-workspace-member-xyz', mockWorkspaceMemberRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); + if ( + mockCompanyRecord.accountOwner !== null && + mockCompanyRecord.accountOwner !== undefined + ) { + setRecordInStores( + mockCompanyRecord.accountOwner.id, + mockCompanyRecord.accountOwner, ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - if ( - mockCompanyRecord.accountOwner !== null && - mockCompanyRecord.accountOwner !== undefined - ) { - setRecordInStores( - snapshot, - mockCompanyRecord.accountOwner.id, - mockCompanyRecord.accountOwner, - ); - } - }; + } return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, mockCompanyRecord); - setRecordInStores(snapshot, TEST_PERSON_RECORD_ID, mockPersonRecord); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, mockCompanyRecord); + setRecordInStores(TEST_PERSON_RECORD_ID, mockPersonRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - timelineActivityObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores( - snapshot, - TEST_TIMELINE_ACTIVITY_RECORD_ID, - mockTimelineActivityRecord, - ); - setRecordInStores( - snapshot, - 'test-workspace-member-xyz', - mockWorkspaceMemberRecord, - ); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + timelineActivityObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores( + TEST_TIMELINE_ACTIVITY_RECORD_ID, + mockTimelineActivityRecord, + ); + setRecordInStores('test-workspace-member-xyz', mockWorkspaceMemberRecord); return (
- + { - jotaiStore.set( - objectMetadataItemsState.atom, - generatedMockObjectMetadataItems, - ); - jotaiStore.set(isAppMetadataReadyState.atom, true); - const pageLayoutData = createPageLayoutWithWidget( - widget, - companyObjectMetadataItem.id, - ); - snapshot.set( - pageLayoutPersistedComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - snapshot.set( - pageLayoutDraftComponentState.atomFamily({ - instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, - }), - pageLayoutData, - ); - setRecordInStores(snapshot, TEST_RECORD_ID, companyWithManyPeople); - // Set each person record in the store - mockPeople.forEach((person) => { - setRecordInStores(snapshot, person.id, person); - }); - }; + jotaiStore.set( + objectMetadataItemsState.atom, + generatedMockObjectMetadataItems, + ); + jotaiStore.set(isAppMetadataReadyState.atom, true); + const pageLayoutData = createPageLayoutWithWidget( + widget, + companyObjectMetadataItem.id, + ); + jotaiStore.set( + pageLayoutPersistedComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + jotaiStore.set( + pageLayoutDraftComponentState.atomFamily({ + instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID, + }), + pageLayoutData, + ); + setRecordInStores(TEST_RECORD_ID, companyWithManyPeople); + // Set each person record in the store + mockPeople.forEach((person) => { + setRecordInStores(person.id, person); + }); return (
- + { @@ -51,111 +51,106 @@ export const useOpenFieldWidgetFieldInputEditMode = () => { RecordFieldComponentInstanceContext, ); - const openFieldInput = useRecoilCallback( - ({ snapshot }) => - ({ - fieldDefinition, - recordId, - }: { - fieldDefinition: FieldDefinition; - recordId: string; - }) => { - if ( - isFieldRelationOneToMany(fieldDefinition) && - ['taskTarget', 'noteTarget'].includes( - fieldDefinition.metadata.relationObjectMetadataNameSingular, - ) - ) { - const fieldValue = snapshot - .getLoadable>( - recordStoreFamilySelector({ - recordId, - fieldName: fieldDefinition.metadata.fieldName, - }), - ) - .getValue(); - - const activity = snapshot - .getLoadable(recordStoreFamilyState(recordId)) - .getValue(); - - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); - - const activityTargetObjectRecords = getActivityTargetObjectRecords({ - activityRecord: activity as Task | Note, - objectMetadataItems, - activityTargets: fieldValue as NoteTarget[] | TaskTarget[], - }); - - openActivityTargetCellEditMode({ - recordPickerInstanceId: instanceId, - activityTargetObjectRecords, - }); - return; - } - - if (isFieldRelationManyToOne(fieldDefinition)) { - openRelationToOneFieldInput({ + const openFieldInput = useCallback( + ({ + fieldDefinition, + recordId, + }: { + fieldDefinition: FieldDefinition; + recordId: string; + }) => { + if ( + isFieldRelationOneToMany(fieldDefinition) && + ['taskTarget', 'noteTarget'].includes( + fieldDefinition.metadata.relationObjectMetadataNameSingular, + ) + ) { + const fieldValue = jotaiStore.get( + recordStoreFamilySelectorV2.selectorFamily({ + recordId, fieldName: fieldDefinition.metadata.fieldName, - recordId, - prefix: instanceId, - }); + }), + ) as FieldRelationValue; - return; - } + const activity = jotaiStore.get( + recordStoreFamilyState.atomFamily(recordId), + ); - if (isFieldMorphRelationOneToMany(fieldDefinition)) { - if (!isFieldMorphRelation(fieldDefinition)) { - throw new Error('Field is not a morph relation one to many'); - } + const objectMetadataItems = jotaiStore.get( + objectMetadataItemsState.atom, + ); - openMorphRelationOneToManyFieldInput({ - recordId, - prefix: instanceId, - fieldDefinition, - }); - return; - } - - if (isFieldRelationOneToMany(fieldDefinition)) { - if ( - isDefined( - fieldDefinition.metadata.relationObjectMetadataNameSingular, - ) - ) { - openRelationFromManyFieldInput({ - fieldName: fieldDefinition.metadata.fieldName, - objectNameSingular: - fieldDefinition.metadata.relationObjectMetadataNameSingular, - recordId, - prefix: instanceId, - }); - return; - } - } - - if (isFieldMorphRelationManyToOne(fieldDefinition)) { - openMorphRelationManyToOneFieldInput({ - recordId, - prefix: instanceId, - fieldDefinition, - }); - return; - } - - pushFocusItemToFocusStack({ - focusId: instanceId, - component: { - type: FocusComponentType.OPENED_FIELD_INPUT, - instanceId: instanceId, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, + const activityTargetObjectRecords = getActivityTargetObjectRecords({ + activityRecord: activity as Task | Note, + objectMetadataItems, + activityTargets: fieldValue as NoteTarget[] | TaskTarget[], }); - }, + + openActivityTargetCellEditMode({ + recordPickerInstanceId: instanceId, + activityTargetObjectRecords, + }); + return; + } + + if (isFieldRelationManyToOne(fieldDefinition)) { + openRelationToOneFieldInput({ + fieldName: fieldDefinition.metadata.fieldName, + recordId, + prefix: instanceId, + }); + + return; + } + + if (isFieldMorphRelationOneToMany(fieldDefinition)) { + if (!isFieldMorphRelation(fieldDefinition)) { + throw new Error('Field is not a morph relation one to many'); + } + + openMorphRelationOneToManyFieldInput({ + recordId, + prefix: instanceId, + fieldDefinition, + }); + return; + } + + if (isFieldRelationOneToMany(fieldDefinition)) { + if ( + isDefined(fieldDefinition.metadata.relationObjectMetadataNameSingular) + ) { + openRelationFromManyFieldInput({ + fieldName: fieldDefinition.metadata.fieldName, + objectNameSingular: + fieldDefinition.metadata.relationObjectMetadataNameSingular, + recordId, + prefix: instanceId, + }); + return; + } + } + + if (isFieldMorphRelationManyToOne(fieldDefinition)) { + openMorphRelationManyToOneFieldInput({ + recordId, + prefix: instanceId, + fieldDefinition, + }); + return; + } + + pushFocusItemToFocusStack({ + focusId: instanceId, + component: { + type: FocusComponentType.OPENED_FIELD_INPUT, + instanceId: instanceId, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + }, [ instanceId, openActivityTargetCellEditMode, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/states/fieldWidgetHoverComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/field/states/fieldWidgetHoverComponentState.ts index cf5fb42f73..01c3072e3d 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/states/fieldWidgetHoverComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/states/fieldWidgetHoverComponentState.ts @@ -1,7 +1,7 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const fieldWidgetHoverComponentState = createComponentState({ +export const fieldWidgetHoverComponentState = createComponentStateV2({ key: 'fieldWidgetHoverComponentState', defaultValue: false, componentInstanceContext: WidgetComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx index 03681f1a21..806ec25b32 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx @@ -27,7 +27,7 @@ import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/ import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { @@ -87,7 +87,7 @@ export const FieldsWidget = ({ widget }: FieldsWidgetProps) => { objectMetadataId: objectMetadataItem.id, }); - const setRecordFieldListHoverPosition = useSetRecoilComponentState( + const setRecordFieldListHoverPosition = useSetRecoilComponentStateV2( recordFieldListHoverPositionComponentState, instanceId, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellEditModePortal.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellEditModePortal.tsx index db1cb929ab..4f06bafdcd 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellEditModePortal.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellEditModePortal.tsx @@ -7,7 +7,7 @@ import { FieldInput } from '@/object-record/record-field/ui/components/FieldInpu import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal'; import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; type FieldsWidgetCellEditModePortalProps = { @@ -25,7 +25,7 @@ export const FieldsWidgetCellEditModePortal = ({ RecordFieldListComponentInstanceContext, ); - const editModePosition = useRecoilComponentValue( + const editModePosition = useRecoilComponentValueV2( recordFieldListCellEditModePositionComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellHoveredPortal.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellHoveredPortal.tsx index 633939e7f2..c1f1bacf0a 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellHoveredPortal.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetCellHoveredPortal.tsx @@ -6,7 +6,7 @@ import { RecordFieldListComponentInstanceContext } from '@/object-record/record- import { recordFieldListHoverPositionComponentState } from '@/object-record/record-field-list/states/recordFieldListHoverPositionComponentState'; import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; type FieldsWidgetCellHoveredPortalProps = { @@ -24,7 +24,7 @@ export const FieldsWidgetCellHoveredPortal = ({ RecordFieldListComponentInstanceContext, ); - const hoverPosition = useRecoilComponentValue( + const hoverPosition = useRecoilComponentValueV2( recordFieldListHoverPositionComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useCreateFieldsWidgetEditorGroup.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useCreateFieldsWidgetEditorGroup.ts index 147159377e..8ad1afa7bb 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useCreateFieldsWidgetEditorGroup.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useCreateFieldsWidgetEditorGroup.ts @@ -1,7 +1,7 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; import { v4 } from 'uuid'; type UseCreateFieldsWidgetEditorGroupParams = { @@ -13,48 +13,39 @@ export const useCreateFieldsWidgetEditorGroup = ({ pageLayoutId, widgetId, }: UseCreateFieldsWidgetEditorGroupParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const createGroup = useRecoilCallback( - ({ set, snapshot }) => - (name: string) => { - const allDraftGroups = snapshot - .getLoadable(fieldsWidgetGroupsDraftState) - .getValue(); + const store = useStore(); - const currentGroups = allDraftGroups[widgetId] ?? []; - const maxPosition = Math.max( - ...currentGroups.map((g) => g.position), - -1, - ); - const newId = v4(); + const createGroup = useCallback( + (name: string) => { + const allDraftGroups = store.get(fieldsWidgetGroupsDraftState); - set(fieldsWidgetGroupsDraftState, (prev) => ({ - ...prev, - [widgetId]: [ - ...(prev[widgetId] ?? []), - { - id: newId, - name, - position: maxPosition + 1, - isVisible: true, - fields: [], - }, - ], - })); + const currentGroups = allDraftGroups[widgetId] ?? []; + const maxPosition = Math.max(...currentGroups.map((g) => g.position), -1); + const newId = v4(); - return newId; - }, - [fieldsWidgetGroupsDraftState, widgetId], + store.set(fieldsWidgetGroupsDraftState, (prev) => ({ + ...prev, + [widgetId]: [ + ...(prev[widgetId] ?? []), + { + id: newId, + name, + position: maxPosition + 1, + isVisible: true, + fields: [], + }, + ], + })); + + return newId; + }, + [fieldsWidgetGroupsDraftState, widgetId, store], ); - const createGroupCallback = useCallback( - (name: string) => createGroup(name), - [createGroup], - ); - - return { createGroup: createGroupCallback }; + return { createGroup }; }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useDeleteFieldsWidgetEditorGroup.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useDeleteFieldsWidgetEditorGroup.ts index 65d730e1ae..aa66333796 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useDeleteFieldsWidgetEditorGroup.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useDeleteFieldsWidgetEditorGroup.ts @@ -1,7 +1,7 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; type UseDeleteFieldsWidgetEditorGroupParams = { pageLayoutId: string; @@ -12,27 +12,23 @@ export const useDeleteFieldsWidgetEditorGroup = ({ pageLayoutId, widgetId, }: UseDeleteFieldsWidgetEditorGroupParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const deleteGroupRecoilCallback = useRecoilCallback( - ({ set }) => - (groupId: string) => { - set(fieldsWidgetGroupsDraftState, (prev) => ({ - ...prev, - [widgetId]: (prev[widgetId] ?? []).filter( - (group) => group.id !== groupId, - ), - })); - }, - [fieldsWidgetGroupsDraftState, widgetId], - ); + const store = useStore(); const deleteGroup = useCallback( - (groupId: string) => deleteGroupRecoilCallback(groupId), - [deleteGroupRecoilCallback], + (groupId: string) => { + store.set(fieldsWidgetGroupsDraftState, (prev) => ({ + ...prev, + [widgetId]: (prev[widgetId] ?? []).filter( + (group) => group.id !== groupId, + ), + })); + }, + [fieldsWidgetGroupsDraftState, widgetId, store], ); return { deleteGroup }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsDraft.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsDraft.ts index e141cb1a02..3a59dbce8e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsDraft.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsDraft.ts @@ -1,6 +1,6 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; import { type FieldsWidgetGroup } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useMemo } from 'react'; type UseFieldsWidgetGroupsDraftParams = { @@ -14,7 +14,7 @@ export const useFieldsWidgetGroupsDraft = ({ }: UseFieldsWidgetGroupsDraftParams): { draftGroups: FieldsWidgetGroup[]; } => { - const allDraftGroups = useRecoilComponentValue( + const allDraftGroups = useRecoilComponentValueV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsForDisplay.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsForDisplay.ts index b8bcc9de32..792605357b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsForDisplay.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useFieldsWidgetGroupsForDisplay.ts @@ -3,7 +3,7 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPag import { useFieldsWidgetGroups } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetGroups'; import { type FieldsWidgetGroup } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup'; import { filterDraftGroupsForDisplay } from '@/page-layout/widgets/fields/utils/filterDraftGroupsForDisplay'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -18,11 +18,11 @@ export const useFieldsWidgetGroupsForDisplay = ({ viewId, objectNameSingular, }: UseFieldsWidgetGroupsForDisplayParams) => { - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); - const allDraftGroups = useRecoilComponentValue( + const allDraftGroups = useRecoilComponentValueV2( fieldsWidgetGroupsDraftComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useInitializeFieldsWidgetGroupsDraft.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useInitializeFieldsWidgetGroupsDraft.ts index 97d13da21d..c9c3db14ab 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useInitializeFieldsWidgetGroupsDraft.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useInitializeFieldsWidgetGroupsDraft.ts @@ -2,9 +2,9 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fiel import { fieldsWidgetGroupsPersistedComponentState } from '@/page-layout/states/fieldsWidgetGroupsPersistedComponentState'; import { hasInitializedFieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState'; import { type FieldsWidgetGroup } from '@/page-layout/widgets/fields/types/FieldsWidgetGroup'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; +import { useCallback, useEffect } from 'react'; type UseInitializeFieldsWidgetGroupsDraftParams = { pageLayoutId: string; @@ -17,64 +17,62 @@ export const useInitializeFieldsWidgetGroupsDraft = ({ widgetId, serverGroups, }: UseInitializeFieldsWidgetGroupsDraftParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const fieldsWidgetGroupsPersistedState = useRecoilComponentCallbackState( - fieldsWidgetGroupsPersistedComponentState, - pageLayoutId, - ); + const fieldsWidgetGroupsPersistedState = + useRecoilComponentStateCallbackStateV2( + fieldsWidgetGroupsPersistedComponentState, + pageLayoutId, + ); const hasInitializedFieldsWidgetGroupsDraftState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( hasInitializedFieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const initializeDraft = useRecoilCallback( - ({ set, snapshot }) => - () => { - const hasInitialized = snapshot - .getLoadable(hasInitializedFieldsWidgetGroupsDraftState) - .getValue(); + const store = useStore(); - if (hasInitialized[widgetId]) { - return; - } - - const currentDraft = snapshot - .getLoadable(fieldsWidgetGroupsDraftState) - .getValue(); - - const hasDraftForWidget = widgetId in currentDraft; - - if (!hasDraftForWidget) { - set(fieldsWidgetGroupsDraftState, (prev) => ({ - ...prev, - [widgetId]: serverGroups, - })); - - set(fieldsWidgetGroupsPersistedState, (prev) => ({ - ...prev, - [widgetId]: serverGroups, - })); - } - - set(hasInitializedFieldsWidgetGroupsDraftState, (prev) => ({ - ...prev, - [widgetId]: true, - })); - }, - [ + const initializeDraft = useCallback(() => { + const hasInitialized = store.get( hasInitializedFieldsWidgetGroupsDraftState, - fieldsWidgetGroupsDraftState, - fieldsWidgetGroupsPersistedState, - widgetId, - serverGroups, - ], - ); + ); + + if (hasInitialized[widgetId]) { + return; + } + + const currentDraft = store.get(fieldsWidgetGroupsDraftState); + + const hasDraftForWidget = widgetId in currentDraft; + + if (!hasDraftForWidget) { + store.set(fieldsWidgetGroupsDraftState, (prev) => ({ + ...prev, + [widgetId]: serverGroups, + })); + + store.set(fieldsWidgetGroupsPersistedState, (prev) => ({ + ...prev, + [widgetId]: serverGroups, + })); + } + + store.set(hasInitializedFieldsWidgetGroupsDraftState, (prev) => ({ + ...prev, + [widgetId]: true, + })); + }, [ + hasInitializedFieldsWidgetGroupsDraftState, + fieldsWidgetGroupsDraftState, + fieldsWidgetGroupsPersistedState, + widgetId, + serverGroups, + store, + ]); useEffect(() => { if (serverGroups.length > 0) { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useMoveFieldInDraft.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useMoveFieldInDraft.ts index 1a43885706..a410e87433 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useMoveFieldInDraft.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useMoveFieldInDraft.ts @@ -1,7 +1,7 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; type UseMoveFieldInDraftParams = { pageLayoutId: string; @@ -12,99 +12,12 @@ export const useMoveFieldInDraft = ({ pageLayoutId, widgetId, }: UseMoveFieldInDraftParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const moveFieldRecoilCallback = useRecoilCallback( - ({ set }) => - ( - sourceGroupId: string, - destinationGroupId: string, - sourceIndex: number, - destinationIndex: number, - ) => { - set(fieldsWidgetGroupsDraftState, (prev) => { - const currentGroups = prev[widgetId] ?? []; - - const sourceGroup = currentGroups.find((g) => g.id === sourceGroupId); - - if (!sourceGroup) { - return prev; - } - - const sortedSourceFields = [...sourceGroup.fields].sort( - (a, b) => a.position - b.position, - ); - - const [movedField] = sortedSourceFields.splice(sourceIndex, 1); - - if (!movedField) { - return prev; - } - - if (sourceGroupId === destinationGroupId) { - sortedSourceFields.splice(destinationIndex, 0, movedField); - - const updatedFields = sortedSourceFields.map((field, index) => ({ - ...field, - position: index, - })); - - return { - ...prev, - [widgetId]: currentGroups.map((group) => - group.id === sourceGroupId - ? { ...group, fields: updatedFields } - : group, - ), - }; - } - - const destinationGroup = currentGroups.find( - (g) => g.id === destinationGroupId, - ); - - if (!destinationGroup) { - return prev; - } - - const updatedSourceFields = sortedSourceFields.map( - (field, index) => ({ - ...field, - position: index, - }), - ); - - const sortedDestFields = [...destinationGroup.fields].sort( - (a, b) => a.position - b.position, - ); - sortedDestFields.splice(destinationIndex, 0, movedField); - - const updatedDestFields = sortedDestFields.map((field, index) => ({ - ...field, - position: index, - })); - - return { - ...prev, - [widgetId]: currentGroups.map((group) => { - if (group.id === sourceGroupId) { - return { ...group, fields: updatedSourceFields }; - } - - if (group.id === destinationGroupId) { - return { ...group, fields: updatedDestFields }; - } - - return group; - }), - }; - }); - }, - [fieldsWidgetGroupsDraftState, widgetId], - ); + const store = useStore(); const moveField = useCallback( ( @@ -112,14 +25,84 @@ export const useMoveFieldInDraft = ({ destinationGroupId: string, sourceIndex: number, destinationIndex: number, - ) => - moveFieldRecoilCallback( - sourceGroupId, - destinationGroupId, - sourceIndex, - destinationIndex, - ), - [moveFieldRecoilCallback], + ) => { + store.set(fieldsWidgetGroupsDraftState, (prev) => { + const currentGroups = prev[widgetId] ?? []; + + const sourceGroup = currentGroups.find((g) => g.id === sourceGroupId); + + if (!sourceGroup) { + return prev; + } + + const sortedSourceFields = [...sourceGroup.fields].sort( + (a, b) => a.position - b.position, + ); + + const [movedField] = sortedSourceFields.splice(sourceIndex, 1); + + if (!movedField) { + return prev; + } + + if (sourceGroupId === destinationGroupId) { + sortedSourceFields.splice(destinationIndex, 0, movedField); + + const updatedFields = sortedSourceFields.map((field, index) => ({ + ...field, + position: index, + })); + + return { + ...prev, + [widgetId]: currentGroups.map((group) => + group.id === sourceGroupId + ? { ...group, fields: updatedFields } + : group, + ), + }; + } + + const destinationGroup = currentGroups.find( + (g) => g.id === destinationGroupId, + ); + + if (!destinationGroup) { + return prev; + } + + const updatedSourceFields = sortedSourceFields.map((field, index) => ({ + ...field, + position: index, + })); + + const sortedDestFields = [...destinationGroup.fields].sort( + (a, b) => a.position - b.position, + ); + sortedDestFields.splice(destinationIndex, 0, movedField); + + const updatedDestFields = sortedDestFields.map((field, index) => ({ + ...field, + position: index, + })); + + return { + ...prev, + [widgetId]: currentGroups.map((group) => { + if (group.id === sourceGroupId) { + return { ...group, fields: updatedSourceFields }; + } + + if (group.id === destinationGroupId) { + return { ...group, fields: updatedDestFields }; + } + + return group; + }), + }; + }); + }, + [fieldsWidgetGroupsDraftState, widgetId, store], ); return { moveField }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useReorderFieldsWidgetEditorGroups.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useReorderFieldsWidgetEditorGroups.ts index 57ece347d2..0f40d627db 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useReorderFieldsWidgetEditorGroups.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useReorderFieldsWidgetEditorGroups.ts @@ -1,7 +1,7 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; type UseReorderFieldsWidgetEditorGroupsParams = { pageLayoutId: string; @@ -12,42 +12,37 @@ export const useReorderFieldsWidgetEditorGroups = ({ pageLayoutId, widgetId, }: UseReorderFieldsWidgetEditorGroupsParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const reorderGroupsRecoilCallback = useRecoilCallback( - ({ set }) => - (reorderedGroupIds: string[]) => { - set(fieldsWidgetGroupsDraftState, (prev) => { - const currentGroups = prev[widgetId] ?? []; - - const reorderedGroups = reorderedGroupIds - .map((groupId, index) => { - const group = currentGroups.find((g) => g.id === groupId); - - if (!group) { - return null; - } - - return { ...group, position: index }; - }) - .filter((g): g is NonNullable => g !== null); - - return { - ...prev, - [widgetId]: reorderedGroups, - }; - }); - }, - [fieldsWidgetGroupsDraftState, widgetId], - ); + const store = useStore(); const reorderGroups = useCallback( - (reorderedGroupIds: string[]) => - reorderGroupsRecoilCallback(reorderedGroupIds), - [reorderGroupsRecoilCallback], + (reorderedGroupIds: string[]) => { + store.set(fieldsWidgetGroupsDraftState, (prev) => { + const currentGroups = prev[widgetId] ?? []; + + const reorderedGroups = reorderedGroupIds + .map((groupId, index) => { + const group = currentGroups.find((g) => g.id === groupId); + + if (!group) { + return null; + } + + return { ...group, position: index }; + }) + .filter((g): g is NonNullable => g !== null); + + return { + ...prev, + [widgetId]: reorderedGroups, + }; + }); + }, + [fieldsWidgetGroupsDraftState, widgetId, store], ); return { reorderGroups }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useToggleFieldVisibilityInDraft.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useToggleFieldVisibilityInDraft.ts index 7ff1d7b24c..19dc34d972 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useToggleFieldVisibilityInDraft.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useToggleFieldVisibilityInDraft.ts @@ -1,7 +1,7 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; type UseToggleFieldVisibilityInDraftParams = { pageLayoutId: string; @@ -12,41 +12,36 @@ export const useToggleFieldVisibilityInDraft = ({ pageLayoutId, widgetId, }: UseToggleFieldVisibilityInDraftParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const toggleFieldVisibilityRecoilCallback = useRecoilCallback( - ({ set }) => - (groupId: string, fieldMetadataId: string) => { - set(fieldsWidgetGroupsDraftState, (prev) => { - const currentGroups = prev[widgetId] ?? []; - - return { - ...prev, - [widgetId]: currentGroups.map((group) => - group.id === groupId - ? { - ...group, - fields: group.fields.map((field) => - field.fieldMetadataItem.id === fieldMetadataId - ? { ...field, isVisible: !field.isVisible } - : field, - ), - } - : group, - ), - }; - }); - }, - [fieldsWidgetGroupsDraftState, widgetId], - ); + const store = useStore(); const toggleFieldVisibility = useCallback( - (groupId: string, fieldMetadataId: string) => - toggleFieldVisibilityRecoilCallback(groupId, fieldMetadataId), - [toggleFieldVisibilityRecoilCallback], + (groupId: string, fieldMetadataId: string) => { + store.set(fieldsWidgetGroupsDraftState, (prev) => { + const currentGroups = prev[widgetId] ?? []; + + return { + ...prev, + [widgetId]: currentGroups.map((group) => + group.id === groupId + ? { + ...group, + fields: group.fields.map((field) => + field.fieldMetadataItem.id === fieldMetadataId + ? { ...field, isVisible: !field.isVisible } + : field, + ), + } + : group, + ), + }; + }); + }, + [fieldsWidgetGroupsDraftState, widgetId, store], ); return { toggleFieldVisibility }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useUpdateFieldsWidgetEditorGroup.ts b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useUpdateFieldsWidgetEditorGroup.ts index 3ca66e83a5..db66da7e60 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useUpdateFieldsWidgetEditorGroup.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/hooks/useUpdateFieldsWidgetEditorGroup.ts @@ -1,7 +1,7 @@ import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useStore } from 'jotai'; import { useCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; type UpdateGroupParams = { @@ -20,38 +20,34 @@ export const useUpdateFieldsWidgetEditorGroup = ({ pageLayoutId, widgetId, }: UseUpdateFieldsWidgetEditorGroupParams) => { - const fieldsWidgetGroupsDraftState = useRecoilComponentCallbackState( + const fieldsWidgetGroupsDraftState = useRecoilComponentStateCallbackStateV2( fieldsWidgetGroupsDraftComponentState, pageLayoutId, ); - const updateGroupRecoilCallback = useRecoilCallback( - ({ set }) => - ({ groupId, name, position, isVisible }: UpdateGroupParams) => { - set(fieldsWidgetGroupsDraftState, (prev) => { - const currentGroups = prev[widgetId] ?? []; - - return { - ...prev, - [widgetId]: currentGroups.map((group) => - group.id === groupId - ? { - ...group, - ...(isDefined(name) ? { name } : {}), - ...(isDefined(position) ? { position } : {}), - ...(isDefined(isVisible) ? { isVisible } : {}), - } - : group, - ), - }; - }); - }, - [fieldsWidgetGroupsDraftState, widgetId], - ); + const store = useStore(); const updateGroup = useCallback( - (params: UpdateGroupParams) => updateGroupRecoilCallback(params), - [updateGroupRecoilCallback], + ({ groupId, name, position, isVisible }: UpdateGroupParams) => { + store.set(fieldsWidgetGroupsDraftState, (prev) => { + const currentGroups = prev[widgetId] ?? []; + + return { + ...prev, + [widgetId]: currentGroups.map((group) => + group.id === groupId + ? { + ...group, + ...(isDefined(name) ? { name } : {}), + ...(isDefined(position) ? { position } : {}), + ...(isDefined(isVisible) ? { isVisible } : {}), + } + : group, + ), + }; + }); + }, + [fieldsWidgetGroupsDraftState, widgetId, store], ); return { updateGroup }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx index b817e35a2c..a672d5ca0b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx @@ -4,10 +4,10 @@ import { Suspense, lazy } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { isWidgetConfigurationOfType } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfType'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; const StyledContainer = styled.div<{ isInEditMode: boolean }>` height: 100%; @@ -29,7 +29,7 @@ type FrontComponentWidgetRendererProps = { export const FrontComponentWidgetRenderer = ({ widget, }: FrontComponentWidgetRendererProps) => { - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/__tests__/GraphWidgetTestWrapper.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/__tests__/GraphWidgetTestWrapper.tsx index f2eaff3307..0916595198 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/__tests__/GraphWidgetTestWrapper.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/__tests__/GraphWidgetTestWrapper.tsx @@ -1,7 +1,6 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; import { type ReactNode } from 'react'; -import { RecoilRoot, type MutableSnapshot } from 'recoil'; export const GRAPH_WIDGET_TEST_INSTANCE_ID = '30303030-f244-4ae0-906b-78958aa07642'; @@ -11,12 +10,10 @@ export const PAGE_LAYOUT_TEST_INSTANCE_ID = export const GraphWidgetTestWrapper = ({ children, - initializeState, instanceId: instanceIdFromProps, pageLayoutInstanceId: pageLayoutInstanceIdFromProps, }: { children: ReactNode; - initializeState?: (snapshot: MutableSnapshot) => void; instanceId?: string; pageLayoutInstanceId?: string; }) => { @@ -25,14 +22,12 @@ export const GraphWidgetTestWrapper = ({ pageLayoutInstanceIdFromProps ?? PAGE_LAYOUT_TEST_INSTANCE_ID; return ( - - - - {children} - - - + + + {children} + + ); }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect.tsx index f3f2f367f7..d8ea976458 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartHasTooManyGroupsEffect.tsx @@ -1,5 +1,5 @@ import { hasWidgetTooManyGroupsComponentState } from '@/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; type GraphWidgetChartHasTooManyGroupsEffectProps = { @@ -9,7 +9,7 @@ type GraphWidgetChartHasTooManyGroupsEffectProps = { export const GraphWidgetChartHasTooManyGroupsEffect = ({ hasTooManyGroups, }: GraphWidgetChartHasTooManyGroupsEffectProps) => { - const setHasWidgetTooManyGroups = useSetRecoilComponentState( + const setHasWidgetTooManyGroups = useSetRecoilComponentStateV2( hasWidgetTooManyGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx index 5570816f2e..80499a23f9 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx @@ -8,9 +8,9 @@ import { useLegendItemToggle } from '@/page-layout/widgets/graph/hooks/useLegend import { graphWidgetHiddenLegendIdsComponentState } from '@/page-layout/widgets/graph/states/graphWidgetHiddenLegendIdsComponentState'; import { graphWidgetHighlightedLegendIdComponentState } from '@/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState'; import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDimensionEffect'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { AnimatePresence, motion } from 'framer-motion'; @@ -146,17 +146,17 @@ export const GraphWidgetLegend = ({ const theme = useTheme(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); const isInteractive = !isPageLayoutInEditMode; - const setHighlightedLegendId = useSetRecoilComponentState( + const setHighlightedLegendId = useSetRecoilComponentStateV2( graphWidgetHighlightedLegendIdComponentState, ); - const [hiddenLegendIds, setHiddenLegendIds] = useRecoilComponentState( + const [hiddenLegendIds, setHiddenLegendIds] = useRecoilComponentStateV2( graphWidgetHiddenLegendIdsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx index 10110ca2f7..92657d79ad 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx @@ -14,7 +14,7 @@ import { formatGraphValue, type GraphValueFormatOptions, } from '@/page-layout/widgets/graph/utils/graphFormatters'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { type MouseEvent } from 'react'; @@ -77,7 +77,7 @@ export const BarChart = ({ hasNoData = false, }: BarChartProps) => { const theme = useTheme(); - const highlightedLegendId = useRecoilComponentValue( + const highlightedLegendId = useRecoilComponentValueV2( graphWidgetHighlightedLegendIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTooltip.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTooltip.tsx index 7ad8de5c52..3bf496eb51 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTooltip.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTooltip.tsx @@ -1,4 +1,5 @@ import { GraphWidgetFloatingTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { BAR_CHART_CONSTANTS } from '@/page-layout/widgets/graph/graphWidgetBarChart/constants/BarChartConstants'; import { graphWidgetBarTooltipComponentState } from '@/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState'; import { type BarChartDatum } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartDatum'; @@ -7,7 +8,6 @@ import { type BarChartSlice } from '@/page-layout/widgets/graph/graphWidgetBarCh import { getBarChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/getBarChartTooltipData'; import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset'; import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { type RefObject } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -30,7 +30,7 @@ export const BarChartTooltip = ({ onMouseEnter, onMouseLeave, }: BarChartTooltipProps) => { - const tooltipState = useRecoilComponentValue( + const tooltipState = useRecoilComponentValueV2( graphWidgetBarTooltipComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx index 4c0f037091..57ebc55ed1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx @@ -19,9 +19,9 @@ import { computeEffectiveValueRange } from '@/page-layout/widgets/graph/utils/co import { createGraphColorRegistry } from '@/page-layout/widgets/graph/utils/createGraphColorRegistry'; import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters'; import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDimensionEffect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useMemo, useRef, useState } from 'react'; @@ -91,23 +91,23 @@ export const GraphWidgetBarChart = ({ const [chartHeight, setChartHeight] = useState(0); const containerRef = useRef(null); - const setActiveBarTooltip = useSetRecoilComponentState( + const setActiveBarTooltip = useSetRecoilComponentStateV2( graphWidgetBarTooltipComponentState, ); - const setHoveredSliceIndex = useSetRecoilComponentState( + const setHoveredSliceIndex = useSetRecoilComponentStateV2( graphWidgetHoveredSliceIndexComponentState, ); - const hoveredSliceIndexValue = useRecoilComponentValue( + const hoveredSliceIndexValue = useRecoilComponentValueV2( graphWidgetHoveredSliceIndexComponentState, ); - const draggingWidgetId = useRecoilComponentValue( + const draggingWidgetId = useRecoilComponentValueV2( pageLayoutDraggingWidgetIdComponentState, ); - const resizingWidgetId = useRecoilComponentValue( + const resizingWidgetId = useRecoilComponentValueV2( pageLayoutResizingWidgetIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx index 44f14e94b8..c6b887fbaa 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChartRenderer.tsx @@ -10,7 +10,7 @@ import { isFilteredViewRedirectionSupported } from '@/page-layout/widgets/graph/ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { useUserFirstDayOfTheWeek } from '@/ui/input/components/internal/date/hooks/useUserFirstDayOfTheWeek'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; import { lazy, Suspense } from 'react'; @@ -58,7 +58,7 @@ export const GraphWidgetBarChartRenderer = () => { const navigate = useNavigate(); const configuration = widget.configuration; - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartData.ts index 1c55403a30..ab7d0cae49 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartData.ts @@ -5,7 +5,7 @@ import { graphWidgetHiddenLegendIdsComponentState } from '@/page-layout/widgets/ import { type GraphColorMode } from '@/page-layout/widgets/graph/types/GraphColorMode'; import { type GraphColorRegistry } from '@/page-layout/widgets/graph/types/GraphColorRegistry'; import { getColorScheme } from '@/page-layout/widgets/graph/utils/getColorScheme'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useMemo } from 'react'; type UseBarChartDataProps = { @@ -24,7 +24,7 @@ export const useBarChartData = ({ seriesLabels, colorMode, }: UseBarChartDataProps) => { - const hiddenLegendIds = useRecoilComponentValue( + const hiddenLegendIds = useRecoilComponentValueV2( graphWidgetHiddenLegendIdsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState.ts index 36e45c11ec..0930d69d35 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState.ts @@ -1,9 +1,9 @@ import { type BarChartSliceHoverData } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartSliceHoverData'; import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const graphWidgetBarTooltipComponentState = - createComponentState({ + createComponentStateV2({ key: 'graphWidgetBarTooltipComponentState', defaultValue: null, componentInstanceContext: WidgetComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetHoveredSliceIndexComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetHoveredSliceIndexComponentState.ts index 90adbaf021..1307555365 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetHoveredSliceIndexComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetHoveredSliceIndexComponentState.ts @@ -1,10 +1,9 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const graphWidgetHoveredSliceIndexComponentState = createComponentState< - string | null ->({ - key: 'graphWidgetHoveredSliceIndexComponentState', - defaultValue: null, - componentInstanceContext: WidgetComponentInstanceContext, -}); +export const graphWidgetHoveredSliceIndexComponentState = + createComponentStateV2({ + key: 'graphWidgetHoveredSliceIndexComponentState', + defaultValue: null, + componentInstanceContext: WidgetComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx index a51b8510f0..36001f08df 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx @@ -1,6 +1,6 @@ import { LINE_CHART_CONSTANTS } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartConstants'; import { graphWidgetLineCrosshairXComponentState } from '@/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineCrosshairXComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useTheme } from '@emotion/react'; import { type LineSeries, type Point } from '@nivo/line'; import { motion } from 'framer-motion'; @@ -41,7 +41,7 @@ export const CustomCrosshairLayer = ({ onRectLeave, }: CustomCrosshairLayerProps) => { const theme = useTheme(); - const crosshairX = useRecoilComponentValue( + const crosshairX = useRecoilComponentValueV2( graphWidgetLineCrosshairXComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomLinesLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomLinesLayer.tsx index b84d4bf5b3..aa8fdbce46 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomLinesLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomLinesLayer.tsx @@ -1,6 +1,6 @@ import { LEGEND_HIGHLIGHT_DIMMED_OPACITY } from '@/page-layout/widgets/graph/constants/LegendHighlightDimmedOpacity.constant'; import { graphWidgetHighlightedLegendIdComponentState } from '@/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useAnimatedPath } from '@nivo/core'; import { type ComputedSeries, @@ -31,7 +31,7 @@ const AnimatedLinePath = ({ }: AnimatedLinePathProps) => { const animatedPath = useAnimatedPath(path); - const highlightedLegendId = useRecoilComponentValue( + const highlightedLegendId = useRecoilComponentValueV2( graphWidgetHighlightedLegendIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphLineChartTooltip.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphLineChartTooltip.tsx index 2caea5c896..40d75b5887 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphLineChartTooltip.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphLineChartTooltip.tsx @@ -5,7 +5,7 @@ import { type LineChartEnrichedSeries } from '@/page-layout/widgets/graph/graphW import { getLineChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetLineChart/utils/getLineChartTooltipData'; import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset'; import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type LineSeries, type Point } from '@nivo/line'; import { type RefObject } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -29,7 +29,7 @@ export const GraphLineChartTooltip = ({ onMouseEnter, onMouseLeave, }: GraphLineChartTooltipProps) => { - const tooltipState = useRecoilComponentValue( + const tooltipState = useRecoilComponentValueV2( graphWidgetLineTooltipComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx index 5027ff40ce..5ceb4edfe1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx @@ -25,7 +25,7 @@ import { type GraphValueFormatOptions, } from '@/page-layout/widgets/graph/utils/graphFormatters'; import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDimensionEffect'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { @@ -131,11 +131,11 @@ export const GraphWidgetLineChart = ({ const hasClickableItems = isDefined(onSliceClick); - const setActiveLineTooltip = useSetRecoilComponentState( + const setActiveLineTooltip = useSetRecoilComponentStateV2( graphWidgetLineTooltipComponentState, ); - const setCrosshairX = useSetRecoilComponentState( + const setCrosshairX = useSetRecoilComponentStateV2( graphWidgetLineCrosshairXComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx index f3784a923c..ca8ce1084b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChartRenderer.tsx @@ -10,7 +10,7 @@ import { isFilteredViewRedirectionSupported } from '@/page-layout/widgets/graph/ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { useUserFirstDayOfTheWeek } from '@/ui/input/components/internal/date/hooks/useUserFirstDayOfTheWeek'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; import { type LineSeries, type Point } from '@nivo/line'; @@ -56,7 +56,7 @@ export const GraphWidgetLineChartRenderer = () => { const navigate = useNavigate(); const configuration = widget.configuration; - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/LineAnimatedAreaPath.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/LineAnimatedAreaPath.tsx index 2b6d8ce233..045efc7cf1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/LineAnimatedAreaPath.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/LineAnimatedAreaPath.tsx @@ -1,6 +1,6 @@ import { LEGEND_HIGHLIGHT_DIMMED_OPACITY } from '@/page-layout/widgets/graph/constants/LegendHighlightDimmedOpacity.constant'; import { graphWidgetHighlightedLegendIdComponentState } from '@/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useAnimatedPath } from '@nivo/core'; import { animated } from '@react-spring/web'; import { isDefined } from 'twenty-shared/utils'; @@ -18,7 +18,7 @@ export const LineAnimatedAreaPath = ({ }: LineAnimatedAreaPathProps) => { const animatedPath = useAnimatedPath(path); - const highlightedLegendId = useRecoilComponentValue( + const highlightedLegendId = useRecoilComponentValueV2( graphWidgetHighlightedLegendIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartData.ts index 7344a79b6a..27bf72e154 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartData.ts @@ -5,7 +5,7 @@ import { graphWidgetHiddenLegendIdsComponentState } from '@/page-layout/widgets/ import { type GraphColorMode } from '@/page-layout/widgets/graph/types/GraphColorMode'; import { type GraphColorRegistry } from '@/page-layout/widgets/graph/types/GraphColorRegistry'; import { getColorScheme } from '@/page-layout/widgets/graph/utils/getColorScheme'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type LineSeries } from '@nivo/line'; import { useMemo } from 'react'; @@ -22,7 +22,7 @@ export const useLineChartData = ({ id, colorMode, }: UseLineChartDataProps) => { - const hiddenLegendIds = useRecoilComponentValue( + const hiddenLegendIds = useRecoilComponentValueV2( graphWidgetHiddenLegendIdsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineCrosshairXComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineCrosshairXComponentState.ts index ddce162c9e..d3760dee85 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineCrosshairXComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineCrosshairXComponentState.ts @@ -1,7 +1,7 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const graphWidgetLineCrosshairXComponentState = createComponentState< +export const graphWidgetLineCrosshairXComponentState = createComponentStateV2< number | null >({ key: 'graphWidgetLineCrosshairXComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineTooltipComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineTooltipComponentState.ts index 00bd02a3c0..7c3ba5748d 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineTooltipComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineTooltipComponentState.ts @@ -1,8 +1,8 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type LineSeries, type SliceTooltipProps } from '@nivo/line'; -export const graphWidgetLineTooltipComponentState = createComponentState<{ +export const graphWidgetLineTooltipComponentState = createComponentStateV2<{ slice: SliceTooltipProps['slice']; offsetLeft: number; offsetTop: number; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/CustomArcsLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/CustomArcsLayer.tsx index 306b363d5b..195e08787d 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/CustomArcsLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/CustomArcsLayer.tsx @@ -1,7 +1,7 @@ import { LEGEND_HIGHLIGHT_DIMMED_OPACITY } from '@/page-layout/widgets/graph/constants/LegendHighlightDimmedOpacity.constant'; import { type PieChartDataItemWithColor } from '@/page-layout/widgets/graph/graphWidgetPieChart/types/PieChartDataItem'; import { graphWidgetHighlightedLegendIdComponentState } from '@/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useArcsTransition } from '@nivo/arcs'; import { type MouseEventHandler, type PieCustomLayerProps } from '@nivo/pie'; import { animated } from '@react-spring/web'; @@ -27,7 +27,7 @@ export const CustomArcsLayer = ({ onMouseLeave, onClick, }: CustomArcsLayerProps) => { - const highlightedLegendId = useRecoilComponentValue( + const highlightedLegendId = useRecoilComponentValueV2( graphWidgetHighlightedLegendIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphPieChartTooltip.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphPieChartTooltip.tsx index 47a04e48cd..41ed3ba40e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphPieChartTooltip.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphPieChartTooltip.tsx @@ -6,7 +6,7 @@ import { type PieChartEnrichedData } from '@/page-layout/widgets/graph/graphWidg import { getPieChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetPieChart/utils/getPieChartTooltipData'; import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset'; import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type RefObject } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -25,7 +25,7 @@ export const GraphPieChartTooltip = ({ displayType, onSliceClick, }: GraphPieChartTooltipProps) => { - const tooltipState = useRecoilComponentValue( + const tooltipState = useRecoilComponentValueV2( graphWidgetPieTooltipComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx index 316953fa8e..1553258074 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx @@ -13,7 +13,7 @@ import { getPieChartFormattedValue } from '@/page-layout/widgets/graph/graphWidg import { type GraphColorMode } from '@/page-layout/widgets/graph/types/GraphColorMode'; import { createGraphColorRegistry } from '@/page-layout/widgets/graph/utils/createGraphColorRegistry'; import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { @@ -91,7 +91,7 @@ export const GraphWidgetPieChart = ({ const theme = useTheme(); const colorRegistry = createGraphColorRegistry(theme); const containerRef = useRef(null); - const setActivePieTooltip = useSetRecoilComponentState( + const setActivePieTooltip = useSetRecoilComponentStateV2( graphWidgetPieTooltipComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx index 2259d9418f..320eba3ad4 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChartRenderer.tsx @@ -9,7 +9,7 @@ import { isFilteredViewRedirectionSupported } from '@/page-layout/widgets/graph/ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { useUserFirstDayOfTheWeek } from '@/ui/input/components/internal/date/hooks/useUserFirstDayOfTheWeek'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; import { lazy, Suspense } from 'react'; @@ -49,7 +49,7 @@ export const GraphWidgetPieChartRenderer = () => { const navigate = useNavigate(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); const indexViewId = useFamilySelectorValueV2( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartCenterMetricData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartCenterMetricData.ts index bcac1f1de3..9747ee8e8b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartCenterMetricData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartCenterMetricData.ts @@ -5,14 +5,14 @@ import { getAggregateOperationLabel } from '@/object-record/record-board/record- import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation'; import { useGraphWidgetQueryCommon } from '@/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { UserContext } from '@/users/contexts/UserContext'; import { t } from '@lingui/core/macro'; import { useContext, useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; import { FIELD_FOR_TOTAL_COUNT_AGGREGATE_OPERATION } from 'twenty-shared/constants'; import { findById, isDefined } from 'twenty-shared/utils'; import { type PieChartConfiguration } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; type UsePieChartCenterMetricDataProps = { objectMetadataItemId: string; @@ -80,7 +80,7 @@ export const usePieChartCenterMetricData = ({ }); const { dateFormat, timeFormat, timeZone } = useContext(UserContext); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const aggregateFieldMetadataItem = objectMetadataItem.readableFields.find( findById(configuration.aggregateFieldMetadataId), diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartData.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartData.ts index 2b0d8568d8..bc58c9b06e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartData.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartData.ts @@ -6,7 +6,7 @@ import { graphWidgetHiddenLegendIdsComponentState } from '@/page-layout/widgets/ import { type GraphColorMode } from '@/page-layout/widgets/graph/types/GraphColorMode'; import { type GraphColorRegistry } from '@/page-layout/widgets/graph/types/GraphColorRegistry'; import { getColorScheme } from '@/page-layout/widgets/graph/utils/getColorScheme'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useMemo } from 'react'; type UsePieChartDataProps = { @@ -20,7 +20,7 @@ export const usePieChartData = ({ colorRegistry, colorMode, }: UsePieChartDataProps) => { - const hiddenLegendIds = useRecoilComponentValue( + const hiddenLegendIds = useRecoilComponentValueV2( graphWidgetHiddenLegendIdsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/states/graphWidgetPieTooltipComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/states/graphWidgetPieTooltipComponentState.ts index 7f58f52d96..fbf1824f24 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/states/graphWidgetPieTooltipComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/states/graphWidgetPieTooltipComponentState.ts @@ -1,9 +1,9 @@ import { type PieChartDataItemWithColor } from '@/page-layout/widgets/graph/graphWidgetPieChart/types/PieChartDataItem'; import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type ComputedDatum } from '@nivo/pie'; -export const graphWidgetPieTooltipComponentState = createComponentState<{ +export const graphWidgetPieTooltipComponentState = createComponentStateV2<{ datum: ComputedDatum; offsetLeft: number; offsetTop: number; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts index 8655154212..f4148fb4a5 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useGraphWidgetAggregateQuery.ts @@ -8,14 +8,14 @@ import { convertAggregateOperationToExtendedAggregateOperation } from '@/object- import { buildRatioNumeratorFilter } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/utils/buildRatioNumeratorFilter'; import { computeRatioDisplayValue } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/utils/computeRatioDisplayValue'; import { useGraphWidgetQueryCommon } from '@/page-layout/widgets/graph/hooks/useGraphWidgetQueryCommon'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { UserContext } from '@/users/contexts/UserContext'; import { t } from '@lingui/core/macro'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { FIELD_FOR_TOTAL_COUNT_AGGREGATE_OPERATION } from 'twenty-shared/constants'; import { findById, isDefined } from 'twenty-shared/utils'; import { type AggregateChartConfiguration } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; export const useGraphWidgetAggregateQuery = ({ objectMetadataItemId, @@ -88,7 +88,7 @@ export const useGraphWidgetAggregateQuery = ({ }); const { dateFormat, timeFormat, timeZone } = useContext(UserContext); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); if (isRatioQuery) { const isRatioLoading = ratioNumeratorLoading || ratioDenominatorLoading; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useLegendItemToggle.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useLegendItemToggle.ts index 27e034fe30..9aa26c43f7 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useLegendItemToggle.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/hooks/useLegendItemToggle.ts @@ -1,5 +1,5 @@ import { graphWidgetHiddenLegendIdsComponentState } from '@/page-layout/widgets/graph/states/graphWidgetHiddenLegendIdsComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useCallback } from 'react'; type UseLegendItemToggleProps = { @@ -11,7 +11,7 @@ export const useLegendItemToggle = ({ itemIds, isInteractive, }: UseLegendItemToggleProps) => { - const setHiddenLegendIds = useSetRecoilComponentState( + const setHiddenLegendIds = useSetRecoilComponentStateV2( graphWidgetHiddenLegendIdsComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHiddenLegendIdsComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHiddenLegendIdsComponentState.ts index 1d523b2039..bc02bd46da 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHiddenLegendIdsComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHiddenLegendIdsComponentState.ts @@ -1,7 +1,7 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const graphWidgetHiddenLegendIdsComponentState = createComponentState< +export const graphWidgetHiddenLegendIdsComponentState = createComponentStateV2< string[] >({ key: 'graphWidgetHiddenLegendIdsComponentState', diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState.ts index 2bdaee0121..4ff6297469 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/states/graphWidgetHighlightedLegendIdComponentState.ts @@ -1,8 +1,8 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; export const graphWidgetHighlightedLegendIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'graphWidgetHighlightedLegendIdComponentState', defaultValue: null, componentInstanceContext: WidgetComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState.ts index 6fb876f9a8..f20575c766 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState.ts @@ -1,8 +1,9 @@ import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; -export const hasWidgetTooManyGroupsComponentState = createComponentState({ - key: 'hasWidgetTooManyGroupsComponentState', - defaultValue: false, - componentInstanceContext: WidgetComponentInstanceContext, -}); +export const hasWidgetTooManyGroupsComponentState = + createComponentStateV2({ + key: 'hasWidgetTooManyGroupsComponentState', + defaultValue: false, + componentInstanceContext: WidgetComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts index 3d9b25e6e7..604469c080 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts @@ -4,14 +4,14 @@ import { buildWidgetVisibilityContext } from '@/page-layout/utils/buildWidgetVis import { filterVisibleWidgets } from '@/page-layout/utils/filterVisibleWidgets'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useIsCurrentWidgetLastOfTab = (widgetId: string): boolean => { const { currentPageLayout } = useCurrentPageLayout(); const isMobile = useIsMobile(); const { isInRightDrawer } = useLayoutRenderingContext(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts index e6182d1312..6f823912bd 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts @@ -4,7 +4,7 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPag import { getTabsByDisplayMode } from '@/page-layout/utils/getTabsByDisplayMode'; import { getTabsWithVisibleWidgets } from '@/page-layout/utils/getTabsWithVisibleWidgets'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; import { useIsMobile } from 'twenty-ui/utilities'; @@ -15,7 +15,7 @@ export const useIsInPinnedTab = () => { const { isInRightDrawer } = useLayoutRenderingContext(); const { currentPageLayout } = useCurrentPageLayoutOrThrow(); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx index e76a1df7b9..fd0c37dea7 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx @@ -1,8 +1,8 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import styled from '@emotion/styled'; import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -56,7 +56,7 @@ export type IframeWidgetProps = { }; export const IframeWidget = ({ widget }: IframeWidgetProps) => { - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextEditorContent.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextEditorContent.tsx index 35a16ee033..8d36f704c1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextEditorContent.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextEditorContent.tsx @@ -16,13 +16,13 @@ import { parseInitialBlocknote } from '@/blocknote-editor/utils/parseInitialBloc import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import '@blocknote/core/fonts/inter.css'; import '@blocknote/mantine/style.css'; import { useCreateBlockNote } from '@blocknote/react'; import '@blocknote/react/style.css'; import { t } from '@lingui/core/macro'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; import { useDebouncedCallback } from 'use-debounce'; import { WidgetConfigurationType } from '~/generated-metadata/graphql'; @@ -45,29 +45,28 @@ export const StandaloneRichTextEditorContent = ({ const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const isPageLayoutInEditModeState = useRecoilComponentCallbackState( + const isPageLayoutInEditModeState = useRecoilComponentStateCallbackStateV2( isPageLayoutInEditModeComponentState, ); - const pageLayoutEditingWidgetIdState = useRecoilComponentCallbackState( + const pageLayoutEditingWidgetIdState = useRecoilComponentStateCallbackStateV2( pageLayoutEditingWidgetIdComponentState, ); const { syncAttachments } = useAttachmentSync(attachments); - const shouldPersistDraft = useRecoilCallback( - ({ snapshot }) => - () => { - const isPageLayoutInEditMode = snapshot - .getLoadable(isPageLayoutInEditModeState) - .getValue(); - const editingWidgetId = snapshot - .getLoadable(pageLayoutEditingWidgetIdState) - .getValue(); + const store = useStore(); - return isPageLayoutInEditMode && editingWidgetId === widget.id; - }, - [isPageLayoutInEditModeState, pageLayoutEditingWidgetIdState, widget.id], - ); + const shouldPersistDraft = useCallback(() => { + const isPageLayoutInEditMode = store.get(isPageLayoutInEditModeState); + const editingWidgetId = store.get(pageLayoutEditingWidgetIdState); + + return isPageLayoutInEditMode && editingWidgetId === widget.id; + }, [ + isPageLayoutInEditModeState, + pageLayoutEditingWidgetIdState, + widget.id, + store, + ]); const initialContent = useMemo( () => filterSupportedBlocks(parseInitialBlocknote(currentBody)), diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx index b6f4700870..99deca84f0 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx @@ -10,7 +10,7 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { StandaloneRichTextEditorContent } from '@/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextEditorContent'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; @@ -39,11 +39,11 @@ export const StandaloneRichTextWidget = ({ widget, }: StandaloneRichTextWidgetProps) => { const containerElementRef = useRef(null); - const isPageLayoutInEditMode = useRecoilComponentValue( + const isPageLayoutInEditMode = useRecoilComponentValueV2( isPageLayoutInEditModeComponentState, ); - const editingWidgetId = useRecoilComponentValue( + const editingWidgetId = useRecoilComponentValueV2( pageLayoutEditingWidgetIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/states/widgetCardHoveredComponentFamilyState.ts b/packages/twenty-front/src/modules/page-layout/widgets/states/widgetCardHoveredComponentFamilyState.ts index 5c61c78fd8..5c4add85f8 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/states/widgetCardHoveredComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/states/widgetCardHoveredComponentFamilyState.ts @@ -1,11 +1,9 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; -export const widgetCardHoveredComponentFamilyState = createComponentFamilyState< - boolean, - string ->({ - key: 'widgetCardHoveredComponentFamilyState', - defaultValue: false, - componentInstanceContext: PageLayoutComponentInstanceContext, -}); +export const widgetCardHoveredComponentFamilyState = + createComponentFamilyStateV2({ + key: 'widgetCardHoveredComponentFamilyState', + defaultValue: false, + componentInstanceContext: PageLayoutComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx index da0d16ce75..8a604ca7b3 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx @@ -1,7 +1,7 @@ import { WidgetActionRenderer } from '@/page-layout/widgets/components/WidgetActionRenderer'; import { widgetCardHoveredComponentFamilyState } from '@/page-layout/widgets/states/widgetCardHoveredComponentFamilyState'; import { type WidgetAction } from '@/page-layout/widgets/types/WidgetAction'; -import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -90,7 +90,7 @@ export const WidgetCardHeader = ({ }: WidgetCardHeaderProps) => { const theme = useTheme(); - const isWidgetCardHovered = useRecoilComponentFamilyValue( + const isWidgetCardHovered = useRecoilComponentFamilyValueV2( widgetCardHoveredComponentFamilyState, widgetId, ); diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetFieldValueEffect.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetFieldValueEffect.tsx index aa9ccec5ae..59be85e8e0 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetFieldValueEffect.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetFieldValueEffect.tsx @@ -1,6 +1,6 @@ -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; +import { useSetAtom } from 'jotai'; type SettingsDataModelSetFieldValueEffectProps = { recordId: string; @@ -13,8 +13,8 @@ export const SettingsDataModelSetFieldValueEffect = ({ gqlFieldName, value, }: SettingsDataModelSetFieldValueEffectProps) => { - const setFieldValue = useSetRecoilState( - recordStoreFamilySelector({ + const setFieldValue = useSetAtom( + recordStoreFamilySelectorV2.selectorFamily({ recordId, fieldName: gqlFieldName, }), diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetLabelIdentifierRecordEffect.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetLabelIdentifierRecordEffect.tsx index c62260996e..50ed6ba1b9 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetLabelIdentifierRecordEffect.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelSetLabelIdentifierRecordEffect.tsx @@ -1,7 +1,7 @@ import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { usePreviewRecord } from '@/settings/data-model/fields/preview/hooks/usePreviewRecord'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; type SettingsDataModelSetLabelIdentifierRecordEffectProps = { objectNameSingular: string; @@ -16,7 +16,7 @@ export const SettingsDataModelSetLabelIdentifierRecordEffect = ({ objectNameSingular: objectNameSingular, }); - const setRecord = useSetRecoilState(recordStoreFamilyState(recordId)); + const setRecord = useSetFamilyRecoilStateV2(recordStoreFamilyState, recordId); useEffect(() => { setRecord(recordPreviewForLabelIdentifier); diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx index bfe08903e2..e12db89860 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx @@ -13,8 +13,8 @@ import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useMemo } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldMetadataType, SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { @@ -139,10 +139,9 @@ export const SettingsObjectFieldItemTableRow = ({ const { deleteOneFieldMetadataItem } = useDeleteOneFieldMetadataItem(); - const [, setActiveSettingsObjectFields] = useRecoilState( - settingsObjectFieldsFamilyState({ - objectMetadataItemId: objectMetadataItem.id, - }), + const setActiveSettingsObjectFields = useSetFamilyRecoilStateV2( + settingsObjectFieldsFamilyState, + { objectMetadataItemId: objectMetadataItem.id }, ); const handleToggleField = () => { 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 321daf2b3f..fc8079260e 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 @@ -11,7 +11,6 @@ import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMe 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'; import { SettingsPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; @@ -28,7 +27,7 @@ export const SettingsUpdateDataModelObjectAboutForm = ({ objectMetadataItem, }); const navigate = useNavigateSettings(); - const setUpdatedObjectNamePlural = useSetRecoilState( + const setUpdatedObjectNamePlural = useSetRecoilStateV2( updatedObjectNamePluralState, ); const setNavigationMemorizedUrl = useSetRecoilStateV2( diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectFieldsFamilyState.ts b/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectFieldsFamilyState.ts index e19b61f53e..34a6b99a0d 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectFieldsFamilyState.ts +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectFieldsFamilyState.ts @@ -1,11 +1,11 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; export type SortedFieldByTableFamilyStateKey = { objectMetadataItemId: string; }; -export const settingsObjectFieldsFamilyState = createFamilyState< +export const settingsObjectFieldsFamilyState = createFamilyStateV2< FieldMetadataItem[] | null, SortedFieldByTableFamilyStateKey >({ diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectIndexesFamilyState.ts b/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectIndexesFamilyState.ts index 0330de1629..6a68a22f12 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectIndexesFamilyState.ts +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/states/settingsObjectIndexesFamilyState.ts @@ -1,11 +1,11 @@ import { type IndexMetadataItem } from '@/object-metadata/types/IndexMetadataItem'; -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; export type SortedIndexByTableFamilyStateKey = { objectMetadataItemId: string; }; -export const settingsObjectIndexesFamilyState = createFamilyState< +export const settingsObjectIndexesFamilyState = createFamilyStateV2< IndexMetadataItem[] | null, SortedIndexByTableFamilyStateKey >({ diff --git a/packages/twenty-front/src/modules/settings/developers/states/apiKeyTokenFamilyState.ts b/packages/twenty-front/src/modules/settings/developers/states/apiKeyTokenFamilyState.ts index 5fd5c17887..32e1879f96 100644 --- a/packages/twenty-front/src/modules/settings/developers/states/apiKeyTokenFamilyState.ts +++ b/packages/twenty-front/src/modules/settings/developers/states/apiKeyTokenFamilyState.ts @@ -1,6 +1,9 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const apiKeyTokenFamilyState = createFamilyState({ +export const apiKeyTokenFamilyState = createFamilyStateV2< + string | null, + string +>({ key: 'apiKeyTokenState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/settings/domains/components/SettingPublicDomain.tsx b/packages/twenty-front/src/modules/settings/domains/components/SettingPublicDomain.tsx index 66b5d3a33b..80d150475f 100644 --- a/packages/twenty-front/src/modules/settings/domains/components/SettingPublicDomain.tsx +++ b/packages/twenty-front/src/modules/settings/domains/components/SettingPublicDomain.tsx @@ -19,7 +19,7 @@ import { import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { CheckPublicDomainValidRecordsEffect } from '@/settings/domains/components/CheckPublicDomainValidRecordsEffect'; import { selectedPublicDomainState } from '@/settings/domains/states/selectedPublicDomainState'; -import { useRecoilState } from 'recoil'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useState } from 'react'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { getDomainValidationSchema } from '@/settings/domains/utils/get-domain-validation-schema'; @@ -48,7 +48,7 @@ const StyledRecordsWrapper = styled.div` `; export const SettingPublicDomain = () => { - const [selectedPublicDomain, setSelectedPublicDomain] = useRecoilState( + const [selectedPublicDomain, setSelectedPublicDomain] = useRecoilStateV2( selectedPublicDomainState, ); const { t } = useLingui(); diff --git a/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx b/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx index 4ffc994384..c70f63c041 100644 --- a/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx +++ b/packages/twenty-front/src/modules/settings/domains/components/SettingsCustomDomain.tsx @@ -4,7 +4,6 @@ import { TextInput } from '@/ui/input/components/TextInput'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { Controller, useFormContext } from 'react-hook-form'; -import { useRecoilValue } from 'recoil'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { H2Title, IconReload, IconTrash } from 'twenty-ui/display'; import { Button, ButtonGroup } from 'twenty-ui/input'; @@ -38,7 +37,7 @@ const StyledRecordsWrapper = styled.div` `; export const SettingsCustomDomain = () => { - const { customDomainRecords, isLoading } = useRecoilValue( + const { customDomainRecords, isLoading } = useRecoilValueV2( customDomainRecordsState, ); diff --git a/packages/twenty-front/src/modules/settings/domains/components/SettingsPublicDomainsListCard.tsx b/packages/twenty-front/src/modules/settings/domains/components/SettingsPublicDomainsListCard.tsx index 663c1d8017..53c54500b6 100644 --- a/packages/twenty-front/src/modules/settings/domains/components/SettingsPublicDomainsListCard.tsx +++ b/packages/twenty-front/src/modules/settings/domains/components/SettingsPublicDomainsListCard.tsx @@ -2,8 +2,8 @@ import { SettingsCard } from '@/settings/components/SettingsCard'; import { SettingsListCard } from '@/settings/components/SettingsListCard'; import { SettingPublicDomainRowDropdownMenu } from '@/settings/domains/components/SettingPublicDomainRowDropdownMenu'; import { selectedPublicDomainState } from '@/settings/domains/states/selectedPublicDomainState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useLingui } from '@lingui/react/macro'; -import { useSetRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { IconAt, IconMailCog, Status } from 'twenty-ui/display'; import { @@ -17,7 +17,9 @@ export const SettingsPublicDomainsListCard = () => { const { t } = useLingui(); - const setSelectedPublicDomain = useSetRecoilState(selectedPublicDomainState); + const setSelectedPublicDomain = useSetRecoilStateV2( + selectedPublicDomainState, + ); const { data, loading } = useFindManyPublicDomainsQuery(); diff --git a/packages/twenty-front/src/modules/settings/domains/hooks/useCheckCustomDomainValidRecords.ts b/packages/twenty-front/src/modules/settings/domains/hooks/useCheckCustomDomainValidRecords.ts index f6219b8a9e..98019fa846 100644 --- a/packages/twenty-front/src/modules/settings/domains/hooks/useCheckCustomDomainValidRecords.ts +++ b/packages/twenty-front/src/modules/settings/domains/hooks/useCheckCustomDomainValidRecords.ts @@ -1,5 +1,5 @@ import { useCheckCustomDomainValidRecordsMutation } from '~/generated-metadata/graphql'; -import { useRecoilState } from 'recoil'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { isDefined } from 'twenty-shared/utils'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { customDomainRecordsState } from '@/settings/domains/states/customDomainRecordsState'; @@ -12,7 +12,7 @@ export const useCheckCustomDomainValidRecords = () => { const { enqueueErrorSnackBar } = useSnackBar(); const currentWorkspace = useRecoilValueV2(currentWorkspaceState); - const [{ isLoading }, setCustomDomainRecords] = useRecoilState( + const [{ isLoading }, setCustomDomainRecords] = useRecoilStateV2( customDomainRecordsState, ); diff --git a/packages/twenty-front/src/modules/settings/domains/states/customDomainRecordsState.ts b/packages/twenty-front/src/modules/settings/domains/states/customDomainRecordsState.ts index 3cab5bb895..ed46edc507 100644 --- a/packages/twenty-front/src/modules/settings/domains/states/customDomainRecordsState.ts +++ b/packages/twenty-front/src/modules/settings/domains/states/customDomainRecordsState.ts @@ -1,7 +1,7 @@ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type DomainValidRecords } from '~/generated-metadata/graphql'; -import { createState } from '@/ui/utilities/state/utils/createState'; -export const customDomainRecordsState = createState<{ +export const customDomainRecordsState = createStateV2<{ customDomainRecords: DomainValidRecords | null; isLoading: boolean; }>({ diff --git a/packages/twenty-front/src/modules/settings/domains/states/selectedPublicDomainState.ts b/packages/twenty-front/src/modules/settings/domains/states/selectedPublicDomainState.ts index cd25f2ad50..e61f627d2e 100644 --- a/packages/twenty-front/src/modules/settings/domains/states/selectedPublicDomainState.ts +++ b/packages/twenty-front/src/modules/settings/domains/states/selectedPublicDomainState.ts @@ -1,7 +1,9 @@ import { type PublicDomain } from '~/generated-metadata/graphql'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const selectedPublicDomainState = createState({ +export const selectedPublicDomainState = createStateV2< + PublicDomain | undefined +>({ key: 'selectedPublicDomainState', defaultValue: undefined, }); diff --git a/packages/twenty-front/src/modules/settings/logic-functions/components/tabs/SettingsLogicFunctionTestTab.tsx b/packages/twenty-front/src/modules/settings/logic-functions/components/tabs/SettingsLogicFunctionTestTab.tsx index 2ed0d7631e..29d081f633 100644 --- a/packages/twenty-front/src/modules/settings/logic-functions/components/tabs/SettingsLogicFunctionTestTab.tsx +++ b/packages/twenty-front/src/modules/settings/logic-functions/components/tabs/SettingsLogicFunctionTestTab.tsx @@ -1,11 +1,9 @@ import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult'; -import { - type LogicFunctionTestData, - logicFunctionTestDataFamilyState, -} from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; +import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilState } from 'recoil'; import { H2Title, IconPlayerPlay } from 'twenty-ui/display'; import { Button, CodeEditor, CoreEditorHeader } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; @@ -33,10 +31,14 @@ export const SettingsLogicFunctionTestTab = ({ isTesting?: boolean; }) => { const { t } = useLingui(); - const [logicFunctionTestData, setLogicFunctionTestData] = - useRecoilState( - logicFunctionTestDataFamilyState(logicFunctionId), - ); + const logicFunctionTestData = useFamilyRecoilValueV2( + logicFunctionTestDataFamilyState, + logicFunctionId, + ); + const setLogicFunctionTestData = useSetFamilyRecoilStateV2( + logicFunctionTestDataFamilyState, + logicFunctionId, + ); const onChange = (newInput: string) => { setLogicFunctionTestData((prev) => ({ diff --git a/packages/twenty-front/src/modules/settings/logic-functions/states/logicFunctionsState.ts b/packages/twenty-front/src/modules/settings/logic-functions/states/logicFunctionsState.ts index ef87ae13ae..52f4ddb5e9 100644 --- a/packages/twenty-front/src/modules/settings/logic-functions/states/logicFunctionsState.ts +++ b/packages/twenty-front/src/modules/settings/logic-functions/states/logicFunctionsState.ts @@ -1,10 +1,10 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type FindManyLogicFunctionsQuery } from '~/generated-metadata/graphql'; export type LogicFunction = FindManyLogicFunctionsQuery['findManyLogicFunctions'][number]; -export const logicFunctionsState = createState({ +export const logicFunctionsState = createStateV2({ key: 'logicFunctionsState', defaultValue: [], }); diff --git a/packages/twenty-front/src/modules/settings/members/hooks/useWorkspaceMemberRoles.ts b/packages/twenty-front/src/modules/settings/members/hooks/useWorkspaceMemberRoles.ts index 72880c66e8..b3f62b7383 100644 --- a/packages/twenty-front/src/modules/settings/members/hooks/useWorkspaceMemberRoles.ts +++ b/packages/twenty-front/src/modules/settings/members/hooks/useWorkspaceMemberRoles.ts @@ -1,10 +1,9 @@ -import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector'; +import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles'; import { settingsRolesIsLoadingStateV2 } from '@/settings/roles/states/settingsRolesIsLoadingStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; -import { useRecoilValue } from 'recoil'; export const useWorkspaceMemberRoles = (workspaceMemberId: string) => { - const settingsAllRoles = useRecoilValue(settingsAllRolesSelector); + const settingsAllRoles = useSettingsAllRoles(); const settingsRolesIsLoading = useRecoilValueV2( settingsRolesIsLoadingStateV2, ); diff --git a/packages/twenty-front/src/modules/settings/playground/components/GraphQLPlayground.tsx b/packages/twenty-front/src/modules/settings/playground/components/GraphQLPlayground.tsx index ee4a56b862..ac5ea65569 100644 --- a/packages/twenty-front/src/modules/settings/playground/components/GraphQLPlayground.tsx +++ b/packages/twenty-front/src/modules/settings/playground/components/GraphQLPlayground.tsx @@ -1,5 +1,6 @@ import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { explorerPlugin } from '@graphiql/plugin-explorer'; import '@graphiql/plugin-explorer/dist/style.css'; @@ -7,7 +8,6 @@ import { createGraphiQLFetcher } from '@graphiql/toolkit'; import { GraphiQL } from 'graphiql'; import 'graphiql/graphiql.css'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { ThemeContext } from 'twenty-ui/theme'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; @@ -35,7 +35,7 @@ export const GraphQLPlayground = ({ onError, schema, }: GraphQLPlaygroundProps) => { - const playgroundApiKey = useRecoilValue(playgroundApiKeyState); + const playgroundApiKey = useRecoilValueV2(playgroundApiKeyState); const baseUrl = REACT_APP_SERVER_BASE_URL + '/' + schemaToPath[schema]; const { theme } = useContext(ThemeContext); diff --git a/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx b/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx index 3086154432..5e3d7300b1 100644 --- a/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx +++ b/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx @@ -4,11 +4,11 @@ import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas import { PlaygroundTypes } from '@/settings/playground/types/PlaygroundTypes'; import { Select } from '@/ui/input/components/Select'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import styled from '@emotion/styled'; import { zodResolver } from '@hookform/resolvers/zod'; import { useLingui } from '@lingui/react/macro'; import { Controller, useForm } from 'react-hook-form'; -import { useRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { CustomError } from 'twenty-shared/utils'; import { IconApi, IconBrandGraphql } from 'twenty-ui/display'; @@ -37,7 +37,7 @@ const StyledForm = styled.form` export const PlaygroundSetupForm = () => { const { t } = useLingui(); const navigateSettings = useNavigateSettings(); - const [playgroundApiKey, setPlaygroundApiKey] = useRecoilState( + const [playgroundApiKey, setPlaygroundApiKey] = useRecoilStateV2( playgroundApiKeyState, ); diff --git a/packages/twenty-front/src/modules/settings/playground/components/RestPlayground.tsx b/packages/twenty-front/src/modules/settings/playground/components/RestPlayground.tsx index fae596418f..6713e84e0e 100644 --- a/packages/twenty-front/src/modules/settings/playground/components/RestPlayground.tsx +++ b/packages/twenty-front/src/modules/settings/playground/components/RestPlayground.tsx @@ -1,10 +1,10 @@ import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; import { type PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { lazy, Suspense } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; @@ -51,7 +51,7 @@ type RestPlaygroundProps = { export const RestPlayground = ({ onError, schema }: RestPlaygroundProps) => { const theme = useTheme(); - const playgroundApiKey = useRecoilValue(playgroundApiKeyState); + const playgroundApiKey = useRecoilValueV2(playgroundApiKeyState); if (!playgroundApiKey) { onError(); diff --git a/packages/twenty-front/src/modules/settings/playground/components/__stories__/GraphQLPlayground.stories.tsx b/packages/twenty-front/src/modules/settings/playground/components/__stories__/GraphQLPlayground.stories.tsx index d3c8a4ea9c..4c76cb99b5 100644 --- a/packages/twenty-front/src/modules/settings/playground/components/__stories__/GraphQLPlayground.stories.tsx +++ b/packages/twenty-front/src/modules/settings/playground/components/__stories__/GraphQLPlayground.stories.tsx @@ -1,8 +1,8 @@ import { GraphQLPlayground } from '@/settings/playground/components/GraphQLPlayground'; import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { action } from 'storybook/actions'; import { ComponentDecorator, @@ -11,7 +11,7 @@ import { import { graphqlMocks } from '~/testing/graphqlMocks'; const PlaygroundApiKeySetterEffect = () => { - const setPlaygroundApiKey = useSetRecoilState(playgroundApiKeyState); + const setPlaygroundApiKey = useSetRecoilStateV2(playgroundApiKeyState); useEffect(() => { setPlaygroundApiKey('test-api-key-123'); diff --git a/packages/twenty-front/src/modules/settings/playground/components/__stories__/RestPlayground.stories.tsx b/packages/twenty-front/src/modules/settings/playground/components/__stories__/RestPlayground.stories.tsx index cdf153ca98..0c7174dd9e 100644 --- a/packages/twenty-front/src/modules/settings/playground/components/__stories__/RestPlayground.stories.tsx +++ b/packages/twenty-front/src/modules/settings/playground/components/__stories__/RestPlayground.stories.tsx @@ -1,15 +1,15 @@ import { RestPlayground } from '@/settings/playground/components/RestPlayground'; import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { HttpResponse, http } from 'msw'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { action } from 'storybook/actions'; import { ComponentDecorator } from 'twenty-ui/testing'; const PlaygroundApiKeySetterEffect = () => { - const setPlaygroundApiKey = useSetRecoilState(playgroundApiKeyState); + const setPlaygroundApiKey = useSetRecoilStateV2(playgroundApiKeyState); useEffect(() => { setPlaygroundApiKey('test-api-key-123'); diff --git a/packages/twenty-front/src/modules/settings/playground/states/openAPIReference.ts b/packages/twenty-front/src/modules/settings/playground/states/openAPIReference.ts index 35a129f0ad..808337a2d8 100644 --- a/packages/twenty-front/src/modules/settings/playground/states/openAPIReference.ts +++ b/packages/twenty-front/src/modules/settings/playground/states/openAPIReference.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const openAPIReferenceState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const openAPIReferenceState = createStateV2({ key: 'OpenAPIReference', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/settings/playground/states/playgroundApiKeyState.ts b/packages/twenty-front/src/modules/settings/playground/states/playgroundApiKeyState.ts index cb902faa78..e78626a77e 100644 --- a/packages/twenty-front/src/modules/settings/playground/states/playgroundApiKeyState.ts +++ b/packages/twenty-front/src/modules/settings/playground/states/playgroundApiKeyState.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 playgroundApiKeyState = atom({ +export const playgroundApiKeyState = createStateV2({ key: 'playgroundApiKeyState', - default: null, - effects: [localStorageEffect()], + defaultValue: null, + useLocalStorage: true, }); diff --git a/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesContainer.tsx b/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesContainer.tsx index a9c3ef3974..54727a877b 100644 --- a/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesContainer.tsx +++ b/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesContainer.tsx @@ -6,18 +6,17 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { SettingsRoleDefaultRole } from '@/settings/roles/components/SettingsRolesDefaultRole'; import { SettingsRolesList } from '@/settings/roles/components/SettingsRolesList'; -import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector'; +import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles'; import { settingsRolesIsLoadingStateV2 } from '@/settings/roles/states/settingsRolesIsLoadingStateV2'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { Trans, useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { H3Title } from 'twenty-ui/display'; export const SettingsRolesContainer = () => { const { t } = useLingui(); - const settingsAllRoles = useRecoilValue(settingsAllRolesSelector); + const settingsAllRoles = useSettingsAllRoles(); const settingsRolesIsLoading = useRecoilValueV2( settingsRolesIsLoadingStateV2, ); diff --git a/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesList.tsx b/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesList.tsx index 48f6ed6721..1e253d3208 100644 --- a/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesList.tsx +++ b/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesList.tsx @@ -7,11 +7,10 @@ import { t } from '@lingui/core/macro'; import { SettingsRolesTableHeader } from '@/settings/roles/components/SettingsRolesTableHeader'; import { SettingsRolesTableRow } from '@/settings/roles/components/SettingsRolesTableRow'; -import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector'; +import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { H2Title, @@ -61,7 +60,7 @@ export const SettingsRolesList = () => { const [showAgentRoles, setShowAgentRoles] = useState(false); const [showApiKeyRoles, setShowApiKeyRoles] = useState(false); - const settingsAllRoles = useRecoilValue(settingsAllRolesSelector); + const settingsAllRoles = useSettingsAllRoles(); const sortedSettingsAllRoles = [...settingsAllRoles].sort((a, b) => sortByAscString(a.label, b.label), diff --git a/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesQueryEffect.tsx b/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesQueryEffect.tsx index 8861277de7..5188cacc4e 100644 --- a/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesQueryEffect.tsx +++ b/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesQueryEffect.tsx @@ -1,14 +1,11 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState'; import { settingsRoleIdsState } from '@/settings/roles/states/settingsRoleIdsState'; -import { settingsRoleIdsStateV2 } from '@/settings/roles/states/settingsRoleIdsStateV2'; import { settingsRolesIsLoadingStateV2 } from '@/settings/roles/states/settingsRolesIsLoadingStateV2'; import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useEffect } from 'react'; import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useGetRolesQuery } from '~/generated-metadata/graphql'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -24,34 +21,30 @@ export const SettingsRolesQueryEffect = () => { const store = useStore(); - const populateRoles = useRecoilCallback( - ({ set, snapshot }) => - (roles: RoleWithPartialMembers[]) => { - const roleIds = roles.map((role) => role.id); - set(settingsRoleIdsState, roleIds); - store.set(settingsRoleIdsStateV2.atom, roleIds); - roles.forEach((role) => { - const persistedRole = getSnapshotValue( - snapshot, - settingsPersistedRoleFamilyState(role.id), - ); + const populateRoles = useCallback( + (roles: RoleWithPartialMembers[]) => { + const roleIds = roles.map((role) => role.id); + store.set(settingsRoleIdsState.atom, roleIds); + roles.forEach((role) => { + const persistedRole = store.get( + settingsPersistedRoleFamilyState.atomFamily(role.id), + ); - const currentDraftRole = getSnapshotValue( - snapshot, - settingsDraftRoleFamilyState(role.id), - ); + const currentDraftRole = store.get( + settingsDraftRoleFamilyState.atomFamily(role.id), + ); - if (isDeeplyEqual(role, persistedRole)) { - return; - } + if (isDeeplyEqual(role, persistedRole)) { + return; + } - set(settingsPersistedRoleFamilyState(role.id), role); + store.set(settingsPersistedRoleFamilyState.atomFamily(role.id), role); - if (!isDeeplyEqual(currentDraftRole, role)) { - set(settingsDraftRoleFamilyState(role.id), role); - } - }); - }, + if (!isDeeplyEqual(currentDraftRole, role)) { + store.set(settingsDraftRoleFamilyState.atomFamily(role.id), role); + } + }); + }, [store], ); diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsAllRoles.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsAllRoles.ts new file mode 100644 index 0000000000..dbe21a6db7 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsAllRoles.ts @@ -0,0 +1,18 @@ +import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState'; +import { settingsRoleIdsState } from '@/settings/roles/states/settingsRoleIdsState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useStore } from 'jotai'; +import { isDefined } from 'twenty-shared/utils'; + +export const useSettingsAllRoles = () => { + const roleIds = useRecoilValueV2(settingsRoleIdsState); + const store = useStore(); + + const roles = roleIds + .map((roleId) => + store.get(settingsPersistedRoleFamilyState.atomFamily(roleId)), + ) + .filter(isDefined); + + return roles; +}; diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateAgentRole.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateAgentRole.ts index f90d0d6376..6582a0612f 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateAgentRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateAgentRole.ts @@ -1,13 +1,19 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilState } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useAssignRoleToAgentMutation, type Agent, } from '~/generated-metadata/graphql'; export const useUpdateAgentRole = (roleId: string) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const [assignRoleToAgentMutation] = useAssignRoleToAgentMutation(); diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateApiKeyRole.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateApiKeyRole.ts index 69f0562318..820db4e5a9 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateApiKeyRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateApiKeyRole.ts @@ -1,13 +1,19 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilState } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useAssignRoleToApiKeyMutation, type ApiKeyForRole, } from '~/generated-metadata/graphql'; export const useUpdateApiKeyRole = (roleId: string) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const [assignRoleToApiKeyMutation] = useAssignRoleToApiKeyMutation(); diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateWorkspaceMemberRole.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateWorkspaceMemberRole.ts index b7e90fc002..88b50ef4bf 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateWorkspaceMemberRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useUpdateWorkspaceMemberRole.ts @@ -1,8 +1,9 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState'; -import { useRecoilState, useSetRecoilState } from 'recoil'; -import { useUpdateWorkspaceMemberRoleMutation } from '~/generated-metadata/graphql'; import { type PartialWorkspaceMember } from '@/settings/roles/types/RoleWithPartialMembers'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; +import { useUpdateWorkspaceMemberRoleMutation } from '~/generated-metadata/graphql'; type AddWorkspaceMemberToRoleAndUpdateStateParams = { workspaceMemberId: string; @@ -18,11 +19,17 @@ type AddWorkspaceMembersToRoleParams = { }; export const useUpdateWorkspaceMemberRole = (roleId: string) => { - const setSettingsPersistedRole = useSetRecoilState( - settingsPersistedRoleFamilyState(roleId), + const setSettingsPersistedRole = useSetFamilyRecoilStateV2( + settingsPersistedRoleFamilyState, + roleId, ); - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const [updateWorkspaceMemberRoleMutation] = diff --git a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignment.tsx b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignment.tsx index a0de2a010a..1235b21230 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignment.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignment.tsx @@ -6,14 +6,14 @@ import { useUpdateWorkspaceMemberRole } from '@/settings/roles/hooks/useUpdateWo import { RoleAssignmentSection } from '@/settings/roles/role-assignment/components/RoleAssignmentSection'; import { SettingsRoleAssignmentConfirmationModal } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentConfirmationModal'; import { type SettingsRoleAssignmentConfirmationModalSelectedRoleTarget } from '@/settings/roles/role-assignment/types/SettingsRoleAssignmentConfirmationModalSelectedRoleTarget'; -import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector'; +import { useSettingsAllRoles } from '@/settings/roles/hooks/useSettingsAllRoles'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { SettingsPath } from 'twenty-shared/types'; import { @@ -40,8 +40,9 @@ export const SettingsRoleAssignment = ({ }: SettingsRoleAssignmentProps) => { const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const navigateSettings = useNavigateSettings(); @@ -69,7 +70,7 @@ export const SettingsRoleAssignment = ({ currentWorkspaceMembersState, ); const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState); - const settingsAllRoles = useRecoilValue(settingsAllRolesSelector); + const settingsAllRoles = useSettingsAllRoles(); const roleMaps = buildRoleMaps(settingsAllRoles); diff --git a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTable.tsx b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTable.tsx index 253954594e..28bd289e59 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTable.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTable.tsx @@ -4,13 +4,13 @@ import { } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentTableRow'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { useMemo, useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { H2Title, IconSearch } from 'twenty-ui/display'; import { type Agent, type ApiKeyForRole } from '~/generated-metadata/graphql'; @@ -52,8 +52,9 @@ export const SettingsRoleAssignmentTable = ({ roleTargetType, roleId, }: SettingsRoleAssignmentTableProps) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const [searchFilter, setSearchFilter] = useState(''); diff --git a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTableRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTableRow.tsx index 3e28fd8d4a..2ac4affd4c 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/SettingsRoleAssignmentTableRow.tsx @@ -6,7 +6,6 @@ import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import styled from '@emotion/styled'; import { useContext } from 'react'; -import { useRecoilValue } from 'recoil'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { Avatar, @@ -15,7 +14,7 @@ import { useIcons, } from 'twenty-ui/display'; import { type Agent, type ApiKeyForRole } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { formatDateString } from '~/utils/string/formatDateString'; import { type PartialWorkspaceMember } from '@/settings/roles/types/RoleWithPartialMembers'; @@ -61,7 +60,7 @@ export const SettingsRoleAssignmentTableRow = ({ ); const { getIcon } = useIcons(); const { dateFormat, timeZone } = useContext(UserContext); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const renderIcon = () => { switch (roleTarget.type) { diff --git a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/stories/SettingsRoleAssignment.stories.tsx b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/stories/SettingsRoleAssignment.stories.tsx index 3e5dae8d86..823e3fe393 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/stories/SettingsRoleAssignment.stories.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/stories/SettingsRoleAssignment.stories.tsx @@ -1,7 +1,7 @@ import { SettingsRoleAssignment } from '@/settings/roles/role-assignment/components/SettingsRoleAssignment'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { getRolesMock } from '~/testing/mock-data/roles'; @@ -9,8 +9,9 @@ import { getRolesMock } from '~/testing/mock-data/roles'; const SettingsRoleAssignmentWrapper = ( args: React.ComponentProps, ) => { - const setDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(args.roleId), + const setDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + args.roleId, ); const role = getRolesMock().find((role) => role.id === args.roleId); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/components/stories/SettingsRolePermissions.stories.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/components/stories/SettingsRolePermissions.stories.tsx index 4a74bf8a85..88008ca2b0 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/components/stories/SettingsRolePermissions.stories.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/components/stories/SettingsRolePermissions.stories.tsx @@ -1,7 +1,7 @@ import { SettingsRolePermissions } from '@/settings/roles/role-permissions/components/SettingsRolePermissions'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { getRolesMock } from '~/testing/mock-data/roles'; @@ -9,8 +9,9 @@ import { getRolesMock } from '~/testing/mock-data/roles'; const SettingsRolePermissionsWrapper = ( args: React.ComponentProps, ) => { - const setDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(args.roleId), + const setDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + args.roleId, ); const role = getRolesMock().find((role) => role.id === args.roleId); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx index f1ccaef0ee..6eee593f1b 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx @@ -4,9 +4,9 @@ import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permis import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectLevelPermissionToRoleObjectPermissionMapping'; import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { AppTooltip, TooltipDelay } from 'twenty-ui/display'; @@ -27,8 +27,9 @@ export const SettingsRolePermissionsObjectLevelOverrideCell = ({ roleId, objectLabel, }: SettingsRolePermissionsObjectLevelOverrideCellProps) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const roleLabel = settingsDraftRole.label; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx index 274347468e..1bc199729c 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx @@ -5,11 +5,11 @@ import { useFilterObjectMetadataItemsWithPermissionOverride } from '@/settings/r import { useObjectMetadataItemsThatCanHavePermission } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useObjectMetadataItemsThatCanHavePermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { Table } from '@/ui/layout/table/components/Table'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; @@ -49,8 +49,9 @@ export const SettingsRolePermissionsObjectLevelSection = ({ }: SettingsRolePermissionsObjectLevelSectionProps) => { const navigateSettings = useNavigateSettings(); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { objectMetadataItemsThatCanHavePermission } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSeeFieldsValueForObject.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSeeFieldsValueForObject.tsx index 0b4d7a4c1a..57395f6f81 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSeeFieldsValueForObject.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSeeFieldsValueForObject.tsx @@ -2,8 +2,8 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { isHiddenSystemField } from '@/object-metadata/utils/isHiddenSystemField'; import { useObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useObjectPermissionDerivedStates'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; type SettingsRolePermissionsObjectLevelSeeFieldsValueForObjectProps = { roleId: string; @@ -16,8 +16,9 @@ export const SettingsRolePermissionsObjectLevelSeeFieldsValueForObject = ({ }: SettingsRolePermissionsObjectLevelSeeFieldsValueForObjectProps) => { const { t } = useLingui(); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const objectMetadataItemId = objectMetadataItem.id; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject.tsx index f8dad00f11..808ab4fa4c 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject.tsx @@ -2,8 +2,8 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { filterUserFacingFieldMetadataItems } from '@/object-metadata/utils/filterUserFacingFieldMetadataItems'; import { useObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useObjectPermissionDerivedStates'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; type SettingsRolePermissionsObjectLevelUpdateFieldsValueForObjectProps = { roleId: string; @@ -16,8 +16,9 @@ export const SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject = ({ }: SettingsRolePermissionsObjectLevelUpdateFieldsValueForObjectProps) => { const { t } = useLingui(); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const objectMetadataItemId = objectMetadataItem.id; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx index 5ca85d1f76..3eda23872f 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx @@ -18,7 +18,6 @@ import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFami import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { isNonEmptyArray } from 'twenty-shared/utils'; import { H2Title, IconSearch } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; @@ -70,8 +69,9 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTable = ({ ), ); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const fieldPermissions = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableAllHeaderRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableAllHeaderRow.tsx index 15353289ab..cbd4a7311c 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableAllHeaderRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableAllHeaderRow.tsx @@ -7,9 +7,9 @@ import { useRestrictReadOnAllFieldsOfObject } from '@/settings/roles/role-permis import { useRestrictUpdateOnAllFieldsOfObject } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictUpdateOnAllFieldsOfObject'; import { OverridableCheckbox } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/OverridableCheckbox'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilState } from 'recoil'; import { Label } from 'twenty-ui/display'; const StyledSectionHeader = styled.div` @@ -40,8 +40,9 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableAllHead }) => { const { t } = useLingui(); - const [settingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { cannotAllowFieldReadRestrict, cannotAllowFieldUpdateRestrict } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/tests/useGetObjectPermissionDerivedStates.test.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/tests/useGetObjectPermissionDerivedStates.test.ts index 0b05443eb8..f81f1fc143 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/tests/useGetObjectPermissionDerivedStates.test.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/tests/useGetObjectPermissionDerivedStates.test.ts @@ -5,11 +5,15 @@ import { MOCK_OBJECT_PERMISSION_3_NULL_ALL, MOCK_ROLE_ID_GRANTS_ALL, MOCK_ROLE_ID_REVOKES_ALL, + initializeRolesMockJotaiStore, rolesMockHookWrapper, } from '~/testing/mock-data/roles/roles-mock'; import { useGetObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useGetObjectPermissionDerivedStates'; describe('useGetObjectPermissionDerivedStates', () => { + beforeEach(() => { + initializeRolesMockJotaiStore(); + }); it('should return expected for object that revoke permissions', () => { const { result } = renderHook( () => diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useGetObjectPermissionDerivedStates.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useGetObjectPermissionDerivedStates.ts index f66c7f7dfd..d5e680ef72 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useGetObjectPermissionDerivedStates.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useGetObjectPermissionDerivedStates.ts @@ -1,5 +1,5 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; export const useGetObjectPermissionDerivedStates = ({ @@ -7,8 +7,9 @@ export const useGetObjectPermissionDerivedStates = ({ }: { roleId: string; }) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const getObjectPermissionDerivedStates = (objectMetadataItemId: string) => { diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveFieldPermissionInDraftRole.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveFieldPermissionInDraftRole.ts index 32aceb648d..d87c158961 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveFieldPermissionInDraftRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveFieldPermissionInDraftRole.ts @@ -1,23 +1,25 @@ import { getRoleWithRemovedFieldPermission } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/utils/getRoleWithRemovedFieldPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const useRemoveFieldPermissionInDraftRole = () => { - const removeFieldPermissionInDraftRole = useRecoilCallback( - ({ set, snapshot }) => - (roleId: string, fieldPermissionFieldMetadataId: string) => { - const currentSettingsDraftRole = snapshot - .getLoadable(settingsDraftRoleFamilyState(roleId)) - .getValue(); + const store = useStore(); - const newRole = getRoleWithRemovedFieldPermission( - currentSettingsDraftRole, - fieldPermissionFieldMetadataId, - ); + const removeFieldPermissionInDraftRole = useCallback( + (roleId: string, fieldPermissionFieldMetadataId: string) => { + const currentSettingsDraftRole = store.get( + settingsDraftRoleFamilyState.atomFamily(roleId), + ); - set(settingsDraftRoleFamilyState(roleId), newRole); - }, - [], + const newRole = getRoleWithRemovedFieldPermission( + currentSettingsDraftRole, + fieldPermissionFieldMetadataId, + ); + + store.set(settingsDraftRoleFamilyState.atomFamily(roleId), newRole); + }, + [store], ); return { diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveReadOverrideOnAllFieldsOfObject.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveReadOverrideOnAllFieldsOfObject.ts index 2a5f19aaa1..b0dd56bda9 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveReadOverrideOnAllFieldsOfObject.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveReadOverrideOnAllFieldsOfObject.ts @@ -1,15 +1,16 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; export const useRemoveReadOverrideOnAllFieldsOfObject = ({ roleId, }: { roleId: string; }) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { upsertFieldPermissionInDraftRole } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveUpdateOverrideOnAllFieldsOfObject.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveUpdateOverrideOnAllFieldsOfObject.ts index 93112878fe..65ab4bb922 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveUpdateOverrideOnAllFieldsOfObject.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRemoveUpdateOverrideOnAllFieldsOfObject.ts @@ -1,15 +1,16 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; export const useRemoveUpdateOverrideOnAllFieldsOfObject = ({ roleId, }: { roleId: string; }) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { upsertFieldPermissionInDraftRole } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictReadOnAllFieldsOfObject.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictReadOnAllFieldsOfObject.ts index 408b5cf42e..c55403c22d 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictReadOnAllFieldsOfObject.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictReadOnAllFieldsOfObject.ts @@ -2,7 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { filterUserFacingFieldMetadataItems } from '@/object-metadata/utils/filterUserFacingFieldMetadataItems'; import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; @@ -11,8 +11,9 @@ export const useRestrictReadOnAllFieldsOfObject = ({ }: { roleId: string; }) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { upsertFieldPermissionInDraftRole } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictUpdateOnAllFieldsOfObject.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictUpdateOnAllFieldsOfObject.ts index a55de7a61b..4fba6f7a39 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictUpdateOnAllFieldsOfObject.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useRestrictUpdateOnAllFieldsOfObject.ts @@ -2,7 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { filterUserFacingFieldMetadataItems } from '@/object-metadata/utils/filterUserFacingFieldMetadataItems'; import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; @@ -11,8 +11,9 @@ export const useRestrictUpdateOnAllFieldsOfObject = ({ }: { roleId: string; }) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { upsertFieldPermissionInDraftRole } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole.ts index 60eb31bb49..130fff1bbe 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole.ts @@ -1,11 +1,12 @@ import { getRoleWithUpsertedFieldPermission } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/utils/getRoleWithUpsertedFieldPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useSetRecoilState } from 'recoil'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { type FieldPermission } from '~/generated-metadata/graphql'; export const useUpsertFieldPermissionInDraftRole = (roleId: string) => { - const setSettingsDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(roleId), + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const upsertFieldPermissionInDraftRole = ( diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useResetObjectPermission.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useResetObjectPermission.ts index f41f0e004b..de570229b6 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useResetObjectPermission.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useResetObjectPermission.ts @@ -2,7 +2,7 @@ import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permi import { useUpsertObjectPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole'; import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { type FieldPermission, @@ -17,8 +17,9 @@ const OBJECT_PERMISSION_KEYS: SettingsRoleObjectPermissionKey[] = [ ]; export const useResetObjectPermission = (roleId: string) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { upsertObjectPermissionInDraftRole } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermission.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermission.ts index bcbc5f04c6..41afe0b0a2 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermission.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermission.ts @@ -1,13 +1,14 @@ import { useUpsertObjectPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole'; import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { type ObjectPermission } from '~/generated-metadata/graphql'; export const useUpsertObjectPermission = ({ roleId }: { roleId: string }) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { upsertObjectPermissionInDraftRole } = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole.ts index 2c8c5d27ae..f1ee318a71 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole.ts @@ -1,11 +1,12 @@ import { getRoleWithUpsertedObjectPermission } from '@/settings/roles/role-permissions/object-level-permissions/hooks/getRoleWithUpsertedObjectPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useSetRecoilState } from 'recoil'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { type ObjectPermission } from '~/generated-metadata/graphql'; export const useUpsertObjectPermissionInDraftRole = (roleId: string) => { - const setSettingsDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(roleId), + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const upsertObjectPermissionInDraftRole = ( diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx index 632eebcdc6..e62f72dc3d 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectForm.tsx @@ -7,10 +7,10 @@ import { SettingsRolePermissionsObjectLevelObjectFormObjectLevel } from '@/setti import { SettingsRolePermissionsObjectLevelRecordLevelSection } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelSection'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap'; import { t } from '@lingui/core/macro'; import { useSearchParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { SettingsPath, type ViewFilterOperand } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; @@ -36,8 +36,9 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({ const currentWorkspace = useRecoilValueV2(currentWorkspaceState); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { data: agentData } = useFindOneAgentQuery({ diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevel.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevel.tsx index c2a6218782..4c03bb7713 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevel.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevel.tsx @@ -3,9 +3,9 @@ import { SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableHeader } fr import { SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow'; import { type SettingsRolePermissionsObjectLevelPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { H2Title } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; @@ -27,8 +27,9 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevel = ({ roleId, objectMetadataItem, }: SettingsRolePermissionsObjectLevelObjectFormObjectLevelProps) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const settingsDraftRoleObjectPermissions = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow.tsx index 26cf7a52cb..d5dac3bb30 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/object-form/components/SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow.tsx @@ -7,10 +7,10 @@ import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-perm import { type SettingsRolePermissionsObjectLevelPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { TableCell } from '@/ui/layout/table/components/TableCell'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { type ObjectPermission, type Role } from '~/generated-metadata/graphql'; @@ -70,8 +70,9 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow = settingsDraftRoleObjectPermissions, roleId, }: SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRowProps) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const label = permission.label; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelect.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelect.tsx index 221473162d..041d13346f 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelect.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelect.tsx @@ -9,7 +9,7 @@ import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/o import { SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu'; import { SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; const StyledContainer = styled.div` flex: 2; @@ -28,7 +28,7 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelect useAdvancedFilterFieldSelectDropdown(recordFilterId); const [objectFilterDropdownIsSelectingCompositeField] = - useRecoilComponentState( + useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu.tsx index db1d1e805b..24eaae5f47 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectFieldMenu.tsx @@ -24,8 +24,8 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useContext } from 'react'; import { FieldMetadataType } from 'twenty-shared/types'; @@ -45,7 +45,7 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectF advancedFilterFieldSelectDropdownId, } = useAdvancedFilterFieldSelectDropdown(recordFilterId); - const [objectFilterDropdownSearchInput] = useRecoilComponentState( + const [objectFilterDropdownSearchInput] = useRecoilComponentStateV2( objectFilterDropdownSearchInputComponentState, ); @@ -77,16 +77,17 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectF const { selectFieldUsedInAdvancedFilterDropdown } = useSelectFieldUsedInAdvancedFilterDropdown(); - const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentState( - objectFilterDropdownSubMenuFieldTypeComponentState, - ); + const [, setObjectFilterDropdownSubMenuFieldType] = + useRecoilComponentStateV2( + objectFilterDropdownSubMenuFieldTypeComponentState, + ); const [, setObjectFilterDropdownIsSelectingCompositeField] = - useRecoilComponentState( + useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, ); - const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentState( + const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2( fieldMetadataItemIdUsedInDropdownComponentState, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu.tsx index 76c143d8dc..455bc11c04 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenu.tsx @@ -27,8 +27,8 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; type SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenuProps = @@ -42,19 +42,19 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectS }: SettingsRolePermissionsObjectLevelRecordLevelPermissionFieldSelectSubFieldMenuProps) => { const { getIcon } = useIcons(); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); const [, setObjectFilterDropdownIsSelectingCompositeField] = - useRecoilComponentState( + useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, ); const [ objectFilterDropdownSubMenuFieldType, setObjectFilterDropdownSubMenuFieldType, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( objectFilterDropdownSubMenuFieldTypeComponentState, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilderContent.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilderContent.tsx index 7f91d53930..13286dd8a0 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilderContent.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilderContent.tsx @@ -2,7 +2,6 @@ import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { IconFilter, IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; @@ -23,8 +22,10 @@ import { useRecordLevelPermissionFilterActions } from '@/settings/roles/role-per import { useRecordLevelPermissionFilterInitialization } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionFilterInitialization'; import { useRecordLevelPermissionSyncToDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionSyncToDraftRole'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; const StyledContainer = styled.div` align-items: start; @@ -55,34 +56,35 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilde roleId, objectMetadataItem, }: SettingsRolePermissionsObjectLevelRecordLevelPermissionFilterBuilderContentProps) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems( objectMetadataItem.id, ); - const setCurrentRecordFilters = useSetRecoilComponentState( + const setCurrentRecordFilters = useSetRecoilComponentStateV2( currentRecordFiltersComponentState, ); - const setCurrentRecordFilterGroups = useSetRecoilComponentState( + const setCurrentRecordFilterGroups = useSetRecoilComponentStateV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); const { setRecordFilterUsedInAdvancedFilterDropdownRow } = useSetRecordFilterUsedInAdvancedFilterDropdownRow(); - const rootRecordFilterGroup = useRecoilComponentValue( + const rootRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx index 1a46a2e56b..50bc46f7e8 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelect.tsx @@ -29,7 +29,8 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; const StyledSearchInput = styled.input` background: transparent; @@ -76,11 +77,11 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionMeValueSelec objectNameSingular: CoreObjectNameSingular.WorkspaceMember, }); - const selectedFieldMetadataItem = useRecoilComponentValue( + const selectedFieldMetadataItem = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionValueInput.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionValueInput.tsx index f2a02f9f8b..994ccb0d4b 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionValueInput.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionValueInput.tsx @@ -25,7 +25,7 @@ import { FormMultiSelectFieldInput } from '@/object-record/record-field/ui/form- import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type CompositeFieldType } from '@/settings/data-model/types/CompositeFieldType'; import { createRecordLevelPermissionVariablePicker } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/components/SettingsRolePermissionsObjectLevelRecordLevelPermissionVariablePicker'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; const StyledContainer = styled.div` align-items: stretch; @@ -102,7 +102,7 @@ export const SettingsRolePermissionsObjectLevelRecordLevelPermissionValueInput = const { objectMetadataItem } = useContext(AdvancedFilterContext); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionFilterActions.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionFilterActions.ts index 7ac9449ed1..ff242cd31c 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionFilterActions.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionFilterActions.ts @@ -23,7 +23,7 @@ import { type RecordFilter } from '@/object-record/record-filter/types/RecordFil import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType'; import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { RECORD_LEVEL_PERMISSION_PREDICATE_FIELD_TYPES } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/constants/RecordLevelPermissionPredicateFieldTypes'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; type UseRecordLevelPermissionFilterActionsProps = { @@ -49,7 +49,7 @@ export const useRecordLevelPermissionFilterActions = ({ }, ); - const rootRecordFilterGroup = useRecoilComponentValue( + const rootRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionSyncToDraftRole.ts b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionSyncToDraftRole.ts index 67cfb6354a..999341a6b8 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionSyncToDraftRole.ts +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/record-level-permissions/hooks/useRecordLevelPermissionSyncToDraftRole.ts @@ -1,7 +1,6 @@ /* @license Enterprise */ import { useCallback, useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; @@ -12,6 +11,7 @@ import { convertRecordFilterToPredicate, } from '@/settings/roles/role-permissions/object-level-permissions/record-level-permissions/utils/recordLevelPermissionPredicateConversion'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; type UseRecordLevelPermissionSyncToDraftRoleProps = { roleId: string; @@ -28,8 +28,9 @@ export const useRecordLevelPermissionSyncToDraftRole = ({ currentRecordFilterGroups, hasInitialized, }: UseRecordLevelPermissionSyncToDraftRoleProps) => { - const setSettingsDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(roleId), + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const syncToDraftRole = useCallback(() => { diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsSection.tsx index d776039ae7..057577ae9f 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsSection.tsx @@ -2,9 +2,10 @@ import { SettingsRolePermissionsObjectsTableHeader } from '@/settings/roles/role import { SettingsRolePermissionsObjectsTableRow } from '@/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsTableRow'; import { type SettingsRolePermissionsObjectPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilState } from 'recoil'; import { H2Title } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; @@ -26,8 +27,13 @@ export const SettingsRolePermissionsObjectsSection = ({ roleId, isEditable, }: SettingsRolePermissionsObjectsSectionProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const objectPermissions = settingsDraftRole.objectPermissions; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsTableHeader.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsTableHeader.tsx index a1d4270a71..471f70f8c8 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsTableHeader.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsTableHeader.tsx @@ -1,10 +1,11 @@ import { type SettingsRolePermissionsObjectPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilState } from 'recoil'; import { Checkbox } from 'twenty-ui/input'; const StyledNameHeader = styled(TableHeader)` @@ -29,8 +30,13 @@ export const SettingsRolePermissionsObjectsTableHeader = ({ objectPermissionsConfig, isEditable, }: SettingsRolePermissionsObjectsTableHeaderProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const allPermissionsEnabled = objectPermissionsConfig.every( diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsSection.tsx index d1738a6e7e..e13c43b513 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsSection.tsx @@ -3,9 +3,10 @@ import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/rol import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow'; import { useSettingsRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useSettingsRolePermissionFlagConfig'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilState } from 'recoil'; import { H2Title, IconSettings } from 'twenty-ui/display'; import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout'; @@ -31,8 +32,13 @@ export const SettingsRolePermissionsSettingsSection = ({ roleId, isEditable, }: SettingsRolePermissionsSettingsSectionProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const settingsPermissionsConfig = useSettingsRolePermissionFlagConfig({ diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableHeader.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableHeader.tsx index 1b36331c91..1dee75b999 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableHeader.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableHeader.tsx @@ -6,7 +6,8 @@ import { Checkbox } from 'twenty-ui/input'; import { type SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/permission-flags/types/SettingsRolePermissionsSettingPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; -import { useRecoilState } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { v4 } from 'uuid'; type SettingsRolePermissionsSettingsTableHeaderProps = { @@ -27,8 +28,13 @@ export const SettingsRolePermissionsSettingsTableHeader = ({ settingsPermissionsConfig, isEditable, }: SettingsRolePermissionsSettingsTableHeaderProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const allSettingsPermissionsEnabled = settingsPermissionsConfig.every( (permission) => diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow.tsx index b3afe08e11..04af8e384b 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow.tsx @@ -1,10 +1,11 @@ import { type SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/permission-flags/types/SettingsRolePermissionsSettingPermission'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { TableCell } from '@/ui/layout/table/components/TableCell'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useRecoilState } from 'recoil'; import { Checkbox } from 'twenty-ui/input'; import { v4 } from 'uuid'; @@ -53,8 +54,13 @@ export const SettingsRolePermissionsSettingsTableRow = ({ isEditable, }: SettingsRolePermissionsSettingsTableRowProps) => { const theme = useTheme(); - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const isPermissionEnabled = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx index 738ab91236..0820decbc9 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx @@ -3,9 +3,10 @@ import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/rol import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow'; import { useActionRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagConfig'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilState } from 'recoil'; import { H2Title, IconTool } from 'twenty-ui/display'; import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout'; @@ -32,8 +33,13 @@ export const SettingsRolePermissionsToolSection = ({ roleId, isEditable, }: SettingsRolePermissionsToolSectionProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const toolPermissionsConfig = useActionRolePermissionFlagConfig({ diff --git a/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettings.tsx b/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettings.tsx index 8f98404636..2544dd1861 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettings.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettings.tsx @@ -1,12 +1,13 @@ import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { useRecoilState } from 'recoil'; import { SettingsRoleApplicability } from '@/settings/roles/role-settings/components/SettingsRoleApplicability'; import { SettingsRoleSettingsDeleteRoleConfirmationModal } from '@/settings/roles/role-settings/components/SettingsRoleSettingsDeleteRoleConfirmationModal'; import { ROLE_SETTINGS_DELETE_ROLE_CONFIRMATION_MODAL_ID } from '@/settings/roles/role-settings/components/constants/RoleSettingsDeleteRoleConfirmationModalId'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { IconPicker } from '@/ui/input/components/IconPicker'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { TextArea } from '@/ui/input/components/TextArea'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; @@ -37,8 +38,13 @@ export const SettingsRoleSettings = ({ isEditable, isCreateMode, }: SettingsRoleSettingsProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const { openModal } = useModal(); diff --git a/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle.tsx b/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle.tsx index 3b74a107b3..c8134e0a81 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-settings/components/SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle.tsx @@ -1,6 +1,6 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { t } from '@lingui/core/macro'; -import { useRecoilValue } from 'recoil'; type SettingsRoleSettingsDeleteRoleConfirmationModalSubtitleProps = { roleId: string; @@ -9,8 +9,9 @@ type SettingsRoleSettingsDeleteRoleConfirmationModalSubtitleProps = { export const SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle = ({ roleId, }: SettingsRoleSettingsDeleteRoleConfirmationModalSubtitleProps) => { - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const roleName = settingsDraftRole.label; diff --git a/packages/twenty-front/src/modules/settings/roles/role-settings/components/stories/SettingsRoleSettings.stories.tsx b/packages/twenty-front/src/modules/settings/roles/role-settings/components/stories/SettingsRoleSettings.stories.tsx index d4dbd6deec..b450d77c09 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-settings/components/stories/SettingsRoleSettings.stories.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-settings/components/stories/SettingsRoleSettings.stories.tsx @@ -1,7 +1,7 @@ import { SettingsRoleSettings } from '@/settings/roles/role-settings/components/SettingsRoleSettings'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { getRolesMock } from '~/testing/mock-data/roles'; @@ -9,8 +9,9 @@ import { getRolesMock } from '~/testing/mock-data/roles'; const SettingsRoleSettingsWrapper = ( args: React.ComponentProps, ) => { - const setDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(args.roleId), + const setDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + args.roleId, ); const role = getRolesMock().find((role) => role.id === args.roleId); diff --git a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx index 31bec0e346..350e1dea6b 100644 --- a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRole.tsx @@ -16,10 +16,11 @@ import { TabList } from '@/ui/layout/tab-list/components/TabList'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { t } from '@lingui/core/macro'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useState } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { IconLockOpen, IconSettings, IconUserPlus } from 'twenty-ui/display'; @@ -48,12 +49,18 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => { settingsRolesIsLoadingStateV2, ); - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); - const settingsPersistedRole = useRecoilValue( - settingsPersistedRoleFamilyState(roleId), + const settingsPersistedRole = useFamilyRecoilValueV2( + settingsPersistedRoleFamilyState, + roleId, ); const { loadCurrentUser } = useLoadCurrentUser(); diff --git a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleCreateEffect.tsx b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleCreateEffect.tsx index 106df004ab..846f242fcf 100644 --- a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleCreateEffect.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleCreateEffect.tsx @@ -2,10 +2,10 @@ import { SETTINGS_ROLE_DETAIL_TABS } from '@/settings/roles/role/constants/Setti import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { t } from '@lingui/core/macro'; import { useEffect, useState } from 'react'; -import { useSetRecoilState } from 'recoil'; type SettingsRoleCreateEffectProps = { roleId: string; @@ -14,12 +14,14 @@ type SettingsRoleCreateEffectProps = { export const SettingsRoleCreateEffect = ({ roleId, }: SettingsRoleCreateEffectProps) => { - const setSettingsDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(roleId), + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); - const setSettingsPersistedRole = useSetRecoilState( - settingsPersistedRoleFamilyState(roleId), + const setSettingsPersistedRole = useSetFamilyRecoilStateV2( + settingsPersistedRoleFamilyState, + roleId, ); const setActiveTabId = useSetRecoilComponentStateV2( diff --git a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleEditEffect.tsx b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleEditEffect.tsx index c77a0c4bb3..f0ca58b2ff 100644 --- a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleEditEffect.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleEditEffect.tsx @@ -3,10 +3,10 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDr import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState'; import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useEffect, useState } from 'react'; -import { useRecoilCallback, useRecoilValue } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -19,25 +19,25 @@ export const SettingsRoleEditEffect = ({ }: SettingsRoleEditEffectProps) => { const [isInitialized, setIsInitialized] = useState(false); - const role = useRecoilValue(settingsPersistedRoleFamilyState(roleId)); + const role = useFamilyRecoilValueV2(settingsPersistedRoleFamilyState, roleId); const setActiveTabId = useSetRecoilComponentStateV2( activeTabIdComponentState, SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId, ); - const updateDraftRoleIfNeeded = useRecoilCallback( - ({ set, snapshot }) => - (newRole: RoleWithPartialMembers) => { - const currentPersistedRole = getSnapshotValue( - snapshot, - settingsPersistedRoleFamilyState(newRole.id), - ); + const store = useStore(); - if (!isDeeplyEqual(newRole, currentPersistedRole)) { - set(settingsDraftRoleFamilyState(newRole.id), newRole); - } - }, - [], + const updateDraftRoleIfNeeded = useCallback( + (newRole: RoleWithPartialMembers) => { + const currentPersistedRole = store.get( + settingsPersistedRoleFamilyState.atomFamily(newRole.id), + ); + + if (!isDeeplyEqual(newRole, currentPersistedRole)) { + store.set(settingsDraftRoleFamilyState.atomFamily(newRole.id), newRole); + } + }, + [store], ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleLabelContainer.tsx b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleLabelContainer.tsx index 69667a1a01..079c0628f9 100644 --- a/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleLabelContainer.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role/components/SettingsRoleLabelContainer.tsx @@ -1,6 +1,6 @@ -import { useRecoilState } from 'recoil'; - import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { TitleInput } from '@/ui/input/components/TitleInput'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -23,8 +23,13 @@ type SettingsRoleLabelContainerProps = { export const SettingsRoleLabelContainer = ({ roleId, }: SettingsRoleLabelContainerProps) => { - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, + ); + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + roleId, ); const handleChange = (newValue: string) => { diff --git a/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts b/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts index ff7184c9ef..aa5dad7691 100644 --- a/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts +++ b/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts @@ -7,8 +7,8 @@ import { useRemoveFieldPermissionInDraftRole } from '@/settings/roles/role-permi import { newFieldPermissionsFilter } from '@/settings/roles/role/hooks/utils/newFieldPermissionsFilter.util'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { getOperationName } from '@apollo/client/utilities'; -import { useRecoilValue } from 'recoil'; import { isDefined, isNonEmptyArray } from 'twenty-shared/utils'; import { type RowLevelPermissionPredicateGroupLogicalOperator, @@ -57,12 +57,14 @@ export const useSaveDraftRoleToDB = ({ const { addAgentsToRole } = useUpdateAgentRole(roleId); const { addApiKeysToRole } = useUpdateApiKeyRole(roleId); - const settingsPersistedRole = useRecoilValue( - settingsPersistedRoleFamilyState(roleId), + const settingsPersistedRole = useFamilyRecoilValueV2( + settingsPersistedRoleFamilyState, + roleId, ); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId, ); const dirtyFields = getDirtyFields(settingsDraftRole, settingsPersistedRole); diff --git a/packages/twenty-front/src/modules/settings/roles/states/settingsAllRolesSelector.ts b/packages/twenty-front/src/modules/settings/roles/states/settingsAllRolesSelector.ts deleted file mode 100644 index e2483f55ee..0000000000 --- a/packages/twenty-front/src/modules/settings/roles/states/settingsAllRolesSelector.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { selector } from 'recoil'; -import { isDefined } from 'twenty-shared/utils'; -import { settingsPersistedRoleFamilyState } from './settingsPersistedRoleFamilyState'; -import { settingsRoleIdsState } from './settingsRoleIdsState'; - -export const settingsAllRolesSelector = selector({ - key: 'settingsAllRolesSelector', - get: ({ get }) => { - const roleIds = get(settingsRoleIdsState); - return roleIds - .map((roleId) => get(settingsPersistedRoleFamilyState(roleId))) - .filter(isDefined); - }, -}); diff --git a/packages/twenty-front/src/modules/settings/roles/states/settingsDraftRoleFamilyState.ts b/packages/twenty-front/src/modules/settings/roles/states/settingsDraftRoleFamilyState.ts index 6ce0e33846..298815a085 100644 --- a/packages/twenty-front/src/modules/settings/roles/states/settingsDraftRoleFamilyState.ts +++ b/packages/twenty-front/src/modules/settings/roles/states/settingsDraftRoleFamilyState.ts @@ -1,7 +1,7 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers'; -export const settingsDraftRoleFamilyState = createFamilyState< +export const settingsDraftRoleFamilyState = createFamilyStateV2< RoleWithPartialMembers, string >({ diff --git a/packages/twenty-front/src/modules/settings/roles/states/settingsPersistedRoleFamilyState.ts b/packages/twenty-front/src/modules/settings/roles/states/settingsPersistedRoleFamilyState.ts index 0d53d23f44..033fb75cb0 100644 --- a/packages/twenty-front/src/modules/settings/roles/states/settingsPersistedRoleFamilyState.ts +++ b/packages/twenty-front/src/modules/settings/roles/states/settingsPersistedRoleFamilyState.ts @@ -1,7 +1,7 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers'; -export const settingsPersistedRoleFamilyState = createFamilyState< +export const settingsPersistedRoleFamilyState = createFamilyStateV2< RoleWithPartialMembers | undefined, string >({ diff --git a/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsState.ts b/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsState.ts index 95c52d2733..c95a8e9933 100644 --- a/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsState.ts +++ b/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsState.ts @@ -1,6 +1,6 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const settingsRoleIdsState = atom({ +export const settingsRoleIdsState = createStateV2({ key: 'settingsRoleIdsState', - default: [], + defaultValue: [], }); diff --git a/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsStateV2.ts b/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsStateV2.ts deleted file mode 100644 index 92e2360250..0000000000 --- a/packages/twenty-front/src/modules/settings/roles/states/settingsRoleIdsStateV2.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; - -export const settingsRoleIdsStateV2 = createStateV2({ - key: 'settingsRoleIdsStateV2', - defaultValue: [], -}); diff --git a/packages/twenty-front/src/modules/settings/roles/states/settingsValidateRoleFamilyState.ts b/packages/twenty-front/src/modules/settings/roles/states/settingsValidateRoleFamilyState.ts index 1bd3391b34..072d5b6c84 100644 --- a/packages/twenty-front/src/modules/settings/roles/states/settingsValidateRoleFamilyState.ts +++ b/packages/twenty-front/src/modules/settings/roles/states/settingsValidateRoleFamilyState.ts @@ -1,7 +1,7 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { type Role } from '~/generated-metadata/graphql'; -export const settingsValidateRoleFamilyState = createFamilyState< +export const settingsValidateRoleFamilyState = createFamilyStateV2< Record, boolean>, string >({ diff --git a/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCard.tsx b/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCard.tsx index c565971537..8dcd05d040 100644 --- a/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCard.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCard.tsx @@ -13,7 +13,7 @@ import { type ApolloError } from '@apollo/client'; import isPropValid from '@emotion/is-prop-valid'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilState } from 'recoil'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { getSettingsPath } from 'twenty-shared/utils'; import { IconKey } from 'twenty-ui/display'; @@ -33,7 +33,7 @@ export const SettingsSSOIdentitiesProvidersListCard = () => { const { t } = useLingui(); - const [SSOIdentitiesProviders, setSSOIdentitiesProviders] = useRecoilState( + const [SSOIdentitiesProviders, setSSOIdentitiesProviders] = useRecoilStateV2( SSOIdentitiesProvidersState, ); diff --git a/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCardWrapper.tsx b/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCardWrapper.tsx index 46f924483d..01d41693e6 100644 --- a/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCardWrapper.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSSOIdentitiesProvidersListCardWrapper.tsx @@ -5,14 +5,14 @@ import { SettingsListCard } from '@/settings/components/SettingsListCard'; import { SettingsSSOIdentityProviderRowRightContainer } from '@/settings/security/components/SSO/SettingsSSOIdentityProviderRowRightContainer'; import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState'; import { guessSSOIdentityProviderIconByUrl } from '@/settings/security/utils/guessSSOIdentityProviderIconByUrl'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { SettingsPath } from 'twenty-shared/types'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; export const SettingsSSOIdentitiesProvidersListCardWrapper = () => { const navigate = useNavigateSettings(); - const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState); + const SSOIdentitiesProviders = useRecoilValueV2(SSOIdentitiesProvidersState); return ( [0]; + SSOIdp: Omit; }) => { return ( diff --git a/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSecuritySSORowDropdownMenu.tsx b/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSecuritySSORowDropdownMenu.tsx index d750cd1344..53e5d6da07 100644 --- a/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSecuritySSORowDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/SSO/SettingsSecuritySSORowDropdownMenu.tsx @@ -1,13 +1,12 @@ import { useDeleteSSOIdentityProvider } from '@/settings/security/hooks/useDeleteSSOIdentityProvider'; import { useUpdateSSOIdentityProvider } from '@/settings/security/hooks/useUpdateSSOIdentityProvider'; -import { type SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState'; +import { type SSOIdentityProvider } from '@/settings/security/types/SSOIdentityProvider'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useLingui } from '@lingui/react/macro'; -import { type UnwrapRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { IconArchive, IconDotsVertical, IconTrash } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; @@ -15,7 +14,7 @@ import { MenuItem } from 'twenty-ui/navigation'; import { SsoIdentityProviderStatus } from '~/generated-metadata/graphql'; type SettingsSecuritySSORowDropdownMenuProps = { - SSOIdp: UnwrapRecoilValue[0]; + SSOIdp: Omit; }; export const SettingsSecuritySSORowDropdownMenu = ({ diff --git a/packages/twenty-front/src/modules/settings/security/components/SettingsSecurityAuthProvidersOptionsList.tsx b/packages/twenty-front/src/modules/settings/security/components/SettingsSecurityAuthProvidersOptionsList.tsx index cffa968126..380d6ea6ae 100644 --- a/packages/twenty-front/src/modules/settings/security/components/SettingsSecurityAuthProvidersOptionsList.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/SettingsSecurityAuthProvidersOptionsList.tsx @@ -6,7 +6,6 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { ApolloError } from '@apollo/client'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { ConnectedAccountProvider } from 'twenty-shared/types'; import { capitalize } from 'twenty-shared/utils'; @@ -35,7 +34,7 @@ export const SettingsSecurityAuthProvidersOptionsList = () => { const { t } = useLingui(); const { enqueueErrorSnackBar } = useSnackBar(); - const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState); + const SSOIdentitiesProviders = useRecoilValueV2(SSOIdentitiesProvidersState); const authProviders = useRecoilValueV2(authProvidersState); const [currentWorkspace, setCurrentWorkspace] = useRecoilStateV2( diff --git a/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsApprovedAccessDomainsListCard.tsx b/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsApprovedAccessDomainsListCard.tsx index aca24866e0..ee8f51b6d0 100644 --- a/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsApprovedAccessDomainsListCard.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsApprovedAccessDomainsListCard.tsx @@ -11,11 +11,12 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { ApolloError } from '@apollo/client'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { getSettingsPath } from 'twenty-shared/utils'; import { IconAt, IconMailCog, Status } from 'twenty-ui/display'; import { useGetApprovedAccessDomainsQuery } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; const StyledLink = styled(Link)` @@ -26,9 +27,9 @@ export const SettingsApprovedAccessDomainsListCard = () => { const { enqueueErrorSnackBar } = useSnackBar(); const navigate = useNavigate(); const { t } = useLingui(); - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); - const [approvedAccessDomains, setApprovedAccessDomains] = useRecoilState( + const [approvedAccessDomains, setApprovedAccessDomains] = useRecoilStateV2( approvedAccessDomainsState, ); diff --git a/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainRowDropdownMenu.tsx b/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainRowDropdownMenu.tsx index b8359cc1d1..7e0c18f1c2 100644 --- a/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainRowDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainRowDropdownMenu.tsx @@ -4,16 +4,19 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { t } from '@lingui/core/macro'; -import { type UnwrapRecoilValue, useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { IconDotsVertical, IconTrash } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; import { MenuItem } from 'twenty-ui/navigation'; -import { useDeleteApprovedAccessDomainMutation } from '~/generated-metadata/graphql'; +import { + type ApprovedAccessDomain, + useDeleteApprovedAccessDomainMutation, +} from '~/generated-metadata/graphql'; type SettingsSecurityApprovedAccessDomainRowDropdownMenuProps = { - approvedAccessDomain: UnwrapRecoilValue[0]; + approvedAccessDomain: Omit; }; export const SettingsSecurityApprovedAccessDomainRowDropdownMenu = ({ @@ -21,7 +24,7 @@ export const SettingsSecurityApprovedAccessDomainRowDropdownMenu = ({ }: SettingsSecurityApprovedAccessDomainRowDropdownMenuProps) => { const dropdownId = `settings-approved-access-domain-row-${approvedAccessDomain.id}`; - const setApprovedAccessDomains = useSetRecoilState( + const setApprovedAccessDomains = useSetRecoilStateV2( approvedAccessDomainsState, ); diff --git a/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainValidationEffect.tsx b/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainValidationEffect.tsx index 03af50ab97..53d8898179 100644 --- a/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainValidationEffect.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/approvedAccessDomains/SettingsSecurityApprovedAccessDomainValidationEffect.tsx @@ -3,7 +3,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { t } from '@lingui/core/macro'; import { useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { isDefined } from 'twenty-shared/utils'; import { useValidateApprovedAccessDomainMutation } from '~/generated-metadata/graphql'; @@ -14,7 +14,7 @@ export const SettingsSecurityApprovedAccessDomainValidationEffect = () => { const [searchParams] = useSearchParams(); const approvedAccessDomainId = searchParams.get('wtdId'); const validationToken = searchParams.get('validationToken'); - const setApprovedAccessDomains = useSetRecoilState( + const setApprovedAccessDomains = useSetRecoilStateV2( approvedAccessDomainsState, ); diff --git a/packages/twenty-front/src/modules/settings/security/hooks/useCreateSSOIdentityProvider.ts b/packages/twenty-front/src/modules/settings/security/hooks/useCreateSSOIdentityProvider.ts index 2001337ed6..54f8bca7b7 100644 --- a/packages/twenty-front/src/modules/settings/security/hooks/useCreateSSOIdentityProvider.ts +++ b/packages/twenty-front/src/modules/settings/security/hooks/useCreateSSOIdentityProvider.ts @@ -1,7 +1,7 @@ /* @license Enterprise */ import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type CreateOidcIdentityProviderMutationVariables, type CreateSamlIdentityProviderMutationVariables, @@ -15,7 +15,7 @@ export const useCreateSSOIdentityProvider = () => { const [createSamlIdentityProviderMutation] = useCreateSamlIdentityProviderMutation(); - const setSSOIdentitiesProviders = useSetRecoilState( + const setSSOIdentitiesProviders = useSetRecoilStateV2( SSOIdentitiesProvidersState, ); diff --git a/packages/twenty-front/src/modules/settings/security/hooks/useDeleteSSOIdentityProvider.ts b/packages/twenty-front/src/modules/settings/security/hooks/useDeleteSSOIdentityProvider.ts index 681374fc0f..725022c3fe 100644 --- a/packages/twenty-front/src/modules/settings/security/hooks/useDeleteSSOIdentityProvider.ts +++ b/packages/twenty-front/src/modules/settings/security/hooks/useDeleteSSOIdentityProvider.ts @@ -1,7 +1,7 @@ /* @license Enterprise */ import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type DeleteSsoIdentityProviderMutationVariables, useDeleteSsoIdentityProviderMutation, @@ -11,7 +11,7 @@ export const useDeleteSSOIdentityProvider = () => { const [deleteSsoIdentityProviderMutation] = useDeleteSsoIdentityProviderMutation(); - const setSSOIdentitiesProviders = useSetRecoilState( + const setSSOIdentitiesProviders = useSetRecoilStateV2( SSOIdentitiesProvidersState, ); diff --git a/packages/twenty-front/src/modules/settings/security/hooks/useUpdateSSOIdentityProvider.ts b/packages/twenty-front/src/modules/settings/security/hooks/useUpdateSSOIdentityProvider.ts index 22fd4840e1..964c4ba0a3 100644 --- a/packages/twenty-front/src/modules/settings/security/hooks/useUpdateSSOIdentityProvider.ts +++ b/packages/twenty-front/src/modules/settings/security/hooks/useUpdateSSOIdentityProvider.ts @@ -1,7 +1,7 @@ /* @license Enterprise */ import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProvidersState'; -import { useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { type EditSsoIdentityProviderMutationVariables, useEditSsoIdentityProviderMutation, @@ -11,7 +11,7 @@ export const useUpdateSSOIdentityProvider = () => { const [editSsoIdentityProviderMutation] = useEditSsoIdentityProviderMutation(); - const setSSOIdentitiesProviders = useSetRecoilState( + const setSSOIdentitiesProviders = useSetRecoilStateV2( SSOIdentitiesProvidersState, ); diff --git a/packages/twenty-front/src/modules/settings/security/states/ApprovedAccessDomainsState.ts b/packages/twenty-front/src/modules/settings/security/states/ApprovedAccessDomainsState.ts index 8368fad94b..6710a65f02 100644 --- a/packages/twenty-front/src/modules/settings/security/states/ApprovedAccessDomainsState.ts +++ b/packages/twenty-front/src/modules/settings/security/states/ApprovedAccessDomainsState.ts @@ -1,7 +1,7 @@ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type ApprovedAccessDomain } from '~/generated-metadata/graphql'; -import { createState } from '@/ui/utilities/state/utils/createState'; -export const approvedAccessDomainsState = createState< +export const approvedAccessDomainsState = createStateV2< Omit[] >({ key: 'ApprovedAccessDomainsState', diff --git a/packages/twenty-front/src/modules/settings/security/states/SSOIdentitiesProvidersState.ts b/packages/twenty-front/src/modules/settings/security/states/SSOIdentitiesProvidersState.ts index 61132c111e..92c2f2b90a 100644 --- a/packages/twenty-front/src/modules/settings/security/states/SSOIdentitiesProvidersState.ts +++ b/packages/twenty-front/src/modules/settings/security/states/SSOIdentitiesProvidersState.ts @@ -1,9 +1,9 @@ /* @license Enterprise */ import { type SSOIdentityProvider } from '@/settings/security/types/SSOIdentityProvider'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const SSOIdentitiesProvidersState = createState< +export const SSOIdentitiesProvidersState = createStateV2< Omit[] >({ key: 'SSOIdentitiesProvidersState', diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx index 9515a4ab4f..93524ec8c9 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx +++ b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx @@ -10,7 +10,7 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewBar } from '@/views/components/ViewBar'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; @@ -31,7 +31,7 @@ export const SignInBackgroundMockContainer = () => { const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); - const objectMetadataItemId = useRecoilComponentValue( + const objectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx index 1b7d763c14..b2fabcf338 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx +++ b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx @@ -8,8 +8,8 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObje import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useInitViewBar } from '@/views/hooks/useInitViewBar'; type SignInBackgroundMockContainerEffectProps = { @@ -26,12 +26,12 @@ export const SignInBackgroundMockContainerEffect = ({ const [ contextStoreCurrentObjectMetadataItemId, setContextStoreCurrentObjectMetadataItemId, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( contextStoreCurrentObjectMetadataItemIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - const setCurrentRecordFields = useSetRecoilComponentState( + const setCurrentRecordFields = useSetRecoilComponentStateV2( currentRecordFieldsComponentState, recordTableId, ); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImport.test.tsx b/packages/twenty-front/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImport.test.tsx index cec4362838..6f8ebe223c 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImport.test.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImport.test.tsx @@ -1,5 +1,6 @@ import { renderHook } from '@testing-library/react'; -import { RecoilRoot, useRecoilState } from 'recoil'; +import { Provider as JotaiProvider } from 'jotai'; +import React, { act } from 'react'; import { useOpenSpreadsheetImportDialog } from '@/spreadsheet-import/hooks/useOpenSpreadsheetImportDialog'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; @@ -8,10 +9,10 @@ import { type ImportedRow, type SpreadsheetImportDialogOptions, } from '@/spreadsheet-import/types'; -import { act } from 'react'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; const Wrapper = ({ children }: { children: React.ReactNode }) => ( - {children} + {children} ); export const mockedSpreadsheetOptions: SpreadsheetImportDialogOptions = { @@ -50,13 +51,12 @@ describe('useSpreadsheetImport', () => { const { result } = renderHook( () => ({ useSpreadsheetImport: useOpenSpreadsheetImportDialog(), - spreadsheetImportState: useRecoilState(spreadsheetImportDialogState)[0], }), { wrapper: Wrapper, }, ); - expect(result.current.spreadsheetImportState).toStrictEqual({ + expect(jotaiStore.get(spreadsheetImportDialogState.atom)).toStrictEqual({ isOpen: false, isStepBarVisible: true, options: null, @@ -66,7 +66,7 @@ describe('useSpreadsheetImport', () => { mockedSpreadsheetOptions, ); }); - expect(result.current.spreadsheetImportState).toStrictEqual({ + expect(jotaiStore.get(spreadsheetImportDialogState.atom)).toStrictEqual({ isOpen: true, isStepBarVisible: true, options: mockedSpreadsheetOptions, diff --git a/packages/twenty-front/src/modules/spreadsheet-import/hooks/useComputeColumnSuggestionsAndAutoMatch.ts b/packages/twenty-front/src/modules/spreadsheet-import/hooks/useComputeColumnSuggestionsAndAutoMatch.ts index 473b39cf6d..ab0ed2301f 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/hooks/useComputeColumnSuggestionsAndAutoMatch.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/hooks/useComputeColumnSuggestionsAndAutoMatch.ts @@ -1,3 +1,5 @@ +import { useCallback } from 'react'; + import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; import { initialComputedColumnsSelector, @@ -6,36 +8,35 @@ import { import { suggestedFieldsByColumnHeaderState } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/states/suggestedFieldsByColumnHeaderState'; import { type ImportedRow } from '@/spreadsheet-import/types'; import { getMatchedColumnsWithFuse } from '@/spreadsheet-import/utils/getMatchedColumnsWithFuse'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; export const useComputeColumnSuggestionsAndAutoMatch = () => { const { spreadsheetImportFields: fields, autoMapHeaders } = useSpreadsheetImportInternal(); - const computeColumnSuggestionsAndAutoMatch = useRecoilCallback( - ({ set, snapshot }) => - async ({ - headerValues, - data, - }: { - headerValues: ImportedRow; - data: ImportedRow[]; - }) => { - if (autoMapHeaders) { - const columns = snapshot - .getLoadable(initialComputedColumnsSelector(headerValues)) - .getValue(); + const computeColumnSuggestionsAndAutoMatch = useCallback( + async ({ + headerValues, + data, + }: { + headerValues: ImportedRow; + data: ImportedRow[]; + }) => { + if (autoMapHeaders) { + const columns = jotaiStore.get( + initialComputedColumnsSelector.selectorFamily(headerValues), + ); - const { matchedColumns, suggestedFieldsByColumnHeader } = - getMatchedColumnsWithFuse({ columns, fields, data }); + const { matchedColumns, suggestedFieldsByColumnHeader } = + getMatchedColumnsWithFuse({ columns, fields, data }); - set(matchColumnsState, matchedColumns); - set( - suggestedFieldsByColumnHeaderState, - suggestedFieldsByColumnHeader, - ); - } - }, + jotaiStore.set(matchColumnsState.atom, matchedColumns); + jotaiStore.set( + suggestedFieldsByColumnHeaderState.atom, + suggestedFieldsByColumnHeader, + ); + } + }, [autoMapHeaders, fields], ); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/hooks/useHideStepBar.ts b/packages/twenty-front/src/modules/spreadsheet-import/hooks/useHideStepBar.ts index 65084458e3..2dce527e11 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/hooks/useHideStepBar.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/hooks/useHideStepBar.ts @@ -1,23 +1,20 @@ import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; export const useHideStepBar = () => { - const hideStepBar = useRecoilCallback( - ({ set, snapshot }) => - () => { - const isStepBarVisible = snapshot - .getLoadable(spreadsheetImportDialogState) - .getValue().isStepBarVisible; + const hideStepBar = useCallback(() => { + const isStepBarVisible = jotaiStore.get( + spreadsheetImportDialogState.atom, + ).isStepBarVisible; - if (isStepBarVisible) { - set(spreadsheetImportDialogState, (state) => ({ - ...state, - isStepBarVisible: false, - })); - } - }, - [], - ); + if (isStepBarVisible) { + jotaiStore.set(spreadsheetImportDialogState.atom, (state) => ({ + ...state, + isStepBarVisible: false, + })); + } + }, []); return hideStepBar; }; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/hooks/useOpenSpreadsheetImportDialog.ts b/packages/twenty-front/src/modules/spreadsheet-import/hooks/useOpenSpreadsheetImportDialog.ts index 19bdb4df11..3d8b118d84 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/hooks/useOpenSpreadsheetImportDialog.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/hooks/useOpenSpreadsheetImportDialog.ts @@ -1,11 +1,13 @@ -import { useSetRecoilState } from 'recoil'; - import { SPREADSHEET_IMPORT_MODAL_ID } from '@/spreadsheet-import/constants/SpreadsheetImportModalId'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; import { type SpreadsheetImportDialogOptions } from '@/spreadsheet-import/types'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; + export const useOpenSpreadsheetImportDialog = () => { - const setSpreadSheetImport = useSetRecoilState(spreadsheetImportDialogState); + const setSpreadSheetImport = useSetRecoilStateV2( + spreadsheetImportDialogState, + ); const { openModal } = useModal(); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx b/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx index 2b204a5577..3c80fa7e34 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx @@ -1,13 +1,14 @@ import { useTheme } from '@emotion/react'; import React from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; -import { useRecoilState, useSetRecoilState } from 'recoil'; import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; import { SPREADSHEET_IMPORT_MODAL_ID } from '@/spreadsheet-import/constants/SpreadsheetImportModalId'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; import { matchColumnsState } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; const SpreadsheetImport = React.lazy(() => import('./SpreadsheetImport').then((module) => ({ @@ -34,11 +35,10 @@ type SpreadsheetImportProviderProps = React.PropsWithChildren; export const SpreadsheetImportProvider = ( props: SpreadsheetImportProviderProps, ) => { - const [spreadsheetImportDialog, setSpreadsheetImportDialog] = useRecoilState( - spreadsheetImportDialogState, - ); + const [spreadsheetImportDialog, setSpreadsheetImportDialog] = + useRecoilStateV2(spreadsheetImportDialogState); - const setMatchColumnsState = useSetRecoilState(matchColumnsState); + const setMatchColumnsState = useSetRecoilStateV2(matchColumnsState); const { closeModal } = useModal(); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportCreatedRecordsProgressState.ts b/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportCreatedRecordsProgressState.ts index 22f8dccae3..a84f6e4854 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportCreatedRecordsProgressState.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportCreatedRecordsProgressState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const spreadsheetImportCreatedRecordsProgressState = createState({ +export const spreadsheetImportCreatedRecordsProgressState = createStateV2({ key: 'spreadsheetImportCreatedRecordsProgressState', defaultValue: 0, }); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportDialogState.ts b/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportDialogState.ts index 33d931ebea..833355f9f0 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportDialogState.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/states/spreadsheetImportDialogState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; import { type SpreadsheetImportDialogOptions } from '@/spreadsheet-import/types'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; export type SpreadsheetImportDialogState = { isOpen: boolean; @@ -8,7 +8,7 @@ export type SpreadsheetImportDialogState = { }; export const spreadsheetImportDialogState = - createState({ + createStateV2({ key: 'spreadsheetImportDialogState', defaultValue: { isOpen: false, diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ImportDataStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ImportDataStep.tsx index d66e628a8a..35e024df5d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ImportDataStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ImportDataStep.tsx @@ -1,9 +1,8 @@ -import { useRecoilValue } from 'recoil'; - import { useNumberFormat } from '@/localization/hooks/useNumberFormat'; import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton'; import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; import { spreadsheetImportCreatedRecordsProgressState } from '@/spreadsheet-import/states/spreadsheetImportCreatedRecordsProgressState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { Modal } from '@/ui/layout/modal/components/Modal'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; @@ -38,7 +37,7 @@ export const ImportDataStep = ({ recordsToImportCount, }: ImportDataStepProps) => { const { onClose } = useSpreadsheetImportInternal(); - const spreadsheetImportCreatedRecordsProgress = useRecoilValue( + const spreadsheetImportCreatedRecordsProgress = useRecoilValueV2( spreadsheetImportCreatedRecordsProgressState, ); const { formatNumber } = useNumberFormat(); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx index e33cd1d7c0..4a530de0d5 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx @@ -28,9 +28,9 @@ import { type SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetCo import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType'; import { type SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns'; import { type SpreadsheetImportField } from '@/spreadsheet-import/types/SpreadsheetImportField'; +import { useFamilySelectorStateV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorStateV2'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { Trans, useLingui } from '@lingui/react/macro'; -import { useRecoilState } from 'recoil'; const StyledContent = styled(Modal.Content)` align-items: center; @@ -81,8 +81,9 @@ export const MatchColumnsStep = ({ const dataExample = data.slice(0, 2); const { spreadsheetImportFields: fields } = useSpreadsheetImportInternal(); const [isLoading, setIsLoading] = useState(false); - const [columns, setColumns] = useRecoilState( - initialComputedColumnsSelector(headerValues), + const [columns, setColumns] = useFamilySelectorStateV2( + initialComputedColumnsSelector, + headerValues, ); const { matchColumnsStepHook } = useSpreadsheetImportInternal(); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx index b05b8769c9..a64ff874e2 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx @@ -7,8 +7,8 @@ import { suggestedFieldsByColumnHeaderState } from '@/spreadsheet-import/steps/c import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType'; import { type SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns'; import { spreadsheetImportBuildFieldOptions } from '@/spreadsheet-import/utils/spreadsheetImportBuildFieldOptions'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { IconForbid } from 'twenty-ui/display'; const StyledContainer = styled.div` @@ -37,7 +37,7 @@ export const TemplateColumn = ({ onChange, }: TemplateColumnProps) => { const { spreadsheetImportFields: fields } = useSpreadsheetImportInternal(); - const suggestedFieldsByColumnHeader = useRecoilValue( + const suggestedFieldsByColumnHeader = useRecoilValueV2( suggestedFieldsByColumnHeaderState, ); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts index 3fb16427ac..65a0e5b01d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts @@ -1,14 +1,15 @@ import { type ImportedRow } from '@/spreadsheet-import/types'; import { type SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns'; import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType'; -import { atom, selectorFamily } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +import { createWritableFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createWritableFamilySelectorV2'; -export const matchColumnsState = atom({ +export const matchColumnsState = createStateV2({ key: 'MatchColumnsState', - default: [] as SpreadsheetColumns, + defaultValue: [] as SpreadsheetColumns, }); -export const initialComputedColumnsSelector = selectorFamily< +export const initialComputedColumnsSelector = createWritableFamilySelectorV2< SpreadsheetColumns, ImportedRow >({ diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/suggestedFieldsByColumnHeaderState.ts b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/suggestedFieldsByColumnHeaderState.ts index 8d9a73beee..a3a6414b0f 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/suggestedFieldsByColumnHeaderState.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/suggestedFieldsByColumnHeaderState.ts @@ -1,7 +1,7 @@ import { type SpreadsheetImportField } from '@/spreadsheet-import/types'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const suggestedFieldsByColumnHeaderState = createState({ +export const suggestedFieldsByColumnHeaderState = createStateV2({ key: 'suggestedFieldsByColumnHeaderState', defaultValue: {} as Record, }); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepperContainer.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepperContainer.tsx index 76c54284e1..66ab86fb6d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepperContainer.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepperContainer.tsx @@ -8,8 +8,8 @@ import { useStepBar } from '@/ui/navigation/step-bar/hooks/useStepBar'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; import { Modal } from '@/ui/layout/modal/components/Modal'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; import { SpreadsheetImportStepper } from './SpreadsheetImportStepper'; @@ -28,7 +28,9 @@ const StyledHeader = styled(Modal.Header)` export const SpreadsheetImportStepperContainer = () => { const { t } = useLingui(); - const spreadsheetImportDialog = useRecoilValue(spreadsheetImportDialogState); + const spreadsheetImportDialog = useRecoilValueV2( + spreadsheetImportDialogState, + ); const stepTitles = { uploadStep: t`Upload File`, diff --git a/packages/twenty-front/src/modules/sse-db-event/components/SSEClientEffect.tsx b/packages/twenty-front/src/modules/sse-db-event/components/SSEClientEffect.tsx index f08000c6bd..2cd892447b 100644 --- a/packages/twenty-front/src/modules/sse-db-event/components/SSEClientEffect.tsx +++ b/packages/twenty-front/src/modules/sse-db-event/components/SSEClientEffect.tsx @@ -3,34 +3,29 @@ import { tokenPairState } from '@/auth/states/tokenPairState'; import { useHandleSseClientConnectionRetry } from '@/sse-db-event/hooks/useHandleSseClientConnectionRetry'; import { activeQueryListenersState } from '@/sse-db-event/states/activeQueryListenersState'; import { sseClientState } from '@/sse-db-event/states/sseClientState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { isNonEmptyArray } from '@sniptt/guards'; import { createClient } from 'graphql-sse'; -import { useEffect } from 'react'; -import { useRecoilCallback, useRecoilState } from 'recoil'; +import { useCallback, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; export const SSEClientEffect = () => { const isLoggedIn = useIsLogged(); - const [sseClient, setSseClient] = useRecoilState(sseClientState); + const [sseClient, setSseClient] = useRecoilStateV2(sseClientState); const tokenPair = useRecoilValueV2(tokenPairState); - const handleSSEClientConnected = useRecoilCallback( - ({ snapshot, set }) => - () => { - const currentActiveQueryListeners = getSnapshotValue( - snapshot, - activeQueryListenersState, - ); + const handleSSEClientConnected = useCallback(() => { + const currentActiveQueryListeners = jotaiStore.get( + activeQueryListenersState.atom, + ); - if (isNonEmptyArray(currentActiveQueryListeners)) { - set(activeQueryListenersState, []); - } - }, - [], - ); + if (isNonEmptyArray(currentActiveQueryListeners)) { + jotaiStore.set(activeQueryListenersState.atom, []); + } + }, []); const { handleSseClientConnectionRetry } = useHandleSseClientConnectionRetry(); diff --git a/packages/twenty-front/src/modules/sse-db-event/components/SSEEventStreamEffect.tsx b/packages/twenty-front/src/modules/sse-db-event/components/SSEEventStreamEffect.tsx index ce8995ccb1..f3722a2cb5 100644 --- a/packages/twenty-front/src/modules/sse-db-event/components/SSEEventStreamEffect.tsx +++ b/packages/twenty-front/src/modules/sse-db-event/components/SSEEventStreamEffect.tsx @@ -11,21 +11,22 @@ import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValu import { isNonEmptyArray } from '@apollo/client/utilities'; import { isNonEmptyString } from '@sniptt/guards'; import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { OnboardingStatus } from '~/generated-metadata/graphql'; export const SSEEventStreamEffect = () => { const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); - const sseEventStreamId = useRecoilValue(sseEventStreamIdState); - const isCreatingSseEventStream = useRecoilValue( + const sseEventStreamId = useRecoilValueV2(sseEventStreamIdState); + const isCreatingSseEventStream = useRecoilValueV2( isCreatingSseEventStreamState, ); - const shouldDestroyEventStream = useRecoilValue( + const shouldDestroyEventStream = useRecoilValueV2( shouldDestroyEventStreamState, ); - const isDestroyingEventStream = useRecoilValue(isDestroyingEventStreamState); + const isDestroyingEventStream = useRecoilValueV2( + isDestroyingEventStreamState, + ); const isLoggedIn = useIsLogged(); const currentUser = useRecoilValueV2(currentUserState); diff --git a/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx b/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx index 505fb3d42c..e460aa142d 100644 --- a/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx +++ b/packages/twenty-front/src/modules/sse-db-event/components/SSEQuerySubscribeEffect.tsx @@ -5,11 +5,11 @@ import { requiredQueryListenersState } from '@/sse-db-event/states/requiredQuery import { shouldDestroyEventStreamState } from '@/sse-db-event/states/shouldDestroyEventStreamState'; import { sseEventStreamIdState } from '@/sse-db-event/states/sseEventStreamIdState'; import { sseEventStreamReadyState } from '@/sse-db-event/states/sseEventStreamReadyState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { ApolloError, useMutation } from '@apollo/client'; import { isNonEmptyString } from '@sniptt/guards'; -import { useEffect } from 'react'; -import { useRecoilCallback, useRecoilValue } from 'recoil'; +import { useCallback, useEffect } from 'react'; import { compareArraysOfObjectsByProperty, isDefined, @@ -21,8 +21,8 @@ import { } from '~/generated-metadata/graphql'; export const SSEQuerySubscribeEffect = () => { - const sseEventStreamId = useRecoilValue(sseEventStreamIdState); - const sseEventStreamReady = useRecoilValue(sseEventStreamReadyState); + const sseEventStreamId = useRecoilValueV2(sseEventStreamIdState); + const sseEventStreamReady = useRecoilValueV2(sseEventStreamReadyState); const [addQueryToEventStream] = useMutation< boolean, @@ -34,88 +34,79 @@ export const SSEQuerySubscribeEffect = () => { { input: RemoveQueryFromEventStreamInput } >(REMOVE_QUERY_FROM_EVENT_STREAM_MUTATION); - const requiredQueryListeners = useRecoilValue(requiredQueryListenersState); - const activeQueryListeners = useRecoilValue(activeQueryListenersState); + const requiredQueryListeners = useRecoilValueV2(requiredQueryListenersState); + const activeQueryListeners = useRecoilValueV2(activeQueryListenersState); - const updateQueryListeners = useRecoilCallback( - ({ set, snapshot }) => - async () => { - if (!isDefined(sseEventStreamId)) { - return; - } + const updateQueryListeners = useCallback(async () => { + if (!isDefined(sseEventStreamId)) { + return; + } - const requiredQueryListeners = getSnapshotValue( - snapshot, - requiredQueryListenersState, - ); + const requiredQueryListeners = jotaiStore.get( + requiredQueryListenersState.atom, + ); - const activeQueryListeners = getSnapshotValue( - snapshot, - activeQueryListenersState, - ); + const activeQueryListeners = jotaiStore.get(activeQueryListenersState.atom); - const queryListenersToAdd = requiredQueryListeners.filter( - (listener) => - !activeQueryListeners.some( - (activeListener) => activeListener.queryId === listener.queryId, - ), - ); + const queryListenersToAdd = requiredQueryListeners.filter( + (listener) => + !activeQueryListeners.some( + (activeListener) => activeListener.queryId === listener.queryId, + ), + ); - const queryListenersToRemove = activeQueryListeners.filter( - (listener) => - !requiredQueryListeners.some( - (requiredListener) => - requiredListener.queryId === listener.queryId, - ), - ); + const queryListenersToRemove = activeQueryListeners.filter( + (listener) => + !requiredQueryListeners.some( + (requiredListener) => requiredListener.queryId === listener.queryId, + ), + ); - try { - for (const queryListenerToAdd of queryListenersToAdd) { - await addQueryToEventStream({ - variables: { - input: { - eventStreamId: sseEventStreamId, - queryId: queryListenerToAdd.queryId, - operationSignature: queryListenerToAdd.operationSignature, - }, - }, - }); + try { + for (const queryListenerToAdd of queryListenersToAdd) { + await addQueryToEventStream({ + variables: { + input: { + eventStreamId: sseEventStreamId, + queryId: queryListenerToAdd.queryId, + operationSignature: queryListenerToAdd.operationSignature, + }, + }, + }); + } + + for (const queryListenerToRemove of queryListenersToRemove) { + await removeQueryFromEventStream({ + variables: { + input: { + eventStreamId: sseEventStreamId, + queryId: queryListenerToRemove.queryId, + }, + }, + }); + } + } catch (error) { + if (error instanceof ApolloError) { + const subCode = error.graphQLErrors[0]?.extensions?.subCode; + + switch (subCode) { + case 'EVENT_STREAM_DOES_NOT_EXIST': + case 'EVENT_STREAM_ALREADY_EXISTS': { + jotaiStore.set(activeQueryListenersState.atom, []); + jotaiStore.set(shouldDestroyEventStreamState.atom, true); + return; } - - for (const queryListenerToRemove of queryListenersToRemove) { - await removeQueryFromEventStream({ - variables: { - input: { - eventStreamId: sseEventStreamId, - queryId: queryListenerToRemove.queryId, - }, - }, - }); - } - } catch (error) { - if (error instanceof ApolloError) { - const subCode = error.graphQLErrors[0]?.extensions?.subCode; - - switch (subCode) { - case 'EVENT_STREAM_DOES_NOT_EXIST': - case 'EVENT_STREAM_ALREADY_EXISTS': { - set(activeQueryListenersState, []); - set(shouldDestroyEventStreamState, true); - return; - } - default: { - throw new Error( - `Unhandled error for event stream: ${error.message}`, - ); - } - } + default: { + throw new Error( + `Unhandled error for event stream: ${error.message}`, + ); } } + } + } - set(activeQueryListenersState, requiredQueryListeners); - }, - [addQueryToEventStream, removeQueryFromEventStream, sseEventStreamId], - ); + jotaiStore.set(activeQueryListenersState.atom, requiredQueryListeners); + }, [addQueryToEventStream, removeQueryFromEventStream, sseEventStreamId]); const debouncedUpdateQueryListeners = useDebouncedCallback( updateQueryListeners, diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useHandleSseClientConnectionRetry.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useHandleSseClientConnectionRetry.ts index 8ab10614ea..7103966645 100644 --- a/packages/twenty-front/src/modules/sse-db-event/hooks/useHandleSseClientConnectionRetry.ts +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useHandleSseClientConnectionRetry.ts @@ -4,62 +4,57 @@ import { SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_FOR_DEV_MODE } from '@/sse-db-even import { SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_TO_AVOID_RACE_CONDITIONS } from '@/sse-db-event/constants/SseConnectionRetryWaitTimeInMsToAvoidRaceConditions'; import { shouldDestroyEventStreamState } from '@/sse-db-event/states/shouldDestroyEventStreamState'; import { sseClientState } from '@/sse-db-event/states/sseClientState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useRecoilCallback } from 'recoil'; -import { useStore } from 'jotai'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { getIsDevelopmentEnvironment } from '~/utils/getIsDevelopmentEnvironment'; import { sleep } from '~/utils/sleep'; export const useHandleSseClientConnectionRetry = () => { - const jotaiStore = useStore(); + const handleSseClientConnectionRetry = useCallback( + async (retryCount: number, initialTokenForSseClient: string) => { + const sseClient = jotaiStore.get(sseClientState.atom); - const handleSseClientConnectionRetry = useRecoilCallback( - ({ snapshot, set }) => - async (retryCount: number, initialTokenForSseClient: string) => { - const sseClient = getSnapshotValue(snapshot, sseClientState); - - if (!isDefined(sseClient)) { - await sleep( - SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_TO_AVOID_RACE_CONDITIONS, - ); - - return; - } - - const tokenPair = jotaiStore.get(tokenPairState.atom); - const currentAppToken = - tokenPair?.accessOrWorkspaceAgnosticToken?.token; - - const shouldResetSseClient = - !isDefined(currentAppToken) || - currentAppToken !== initialTokenForSseClient || - retryCount > 10; - - if (shouldResetSseClient) { - await sleep( - SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_TO_AVOID_RACE_CONDITIONS, - ); - - sseClient.dispose(); - set(shouldDestroyEventStreamState, true); - set(sseClientState, null); - return; - } - - const randomWaitTimeInMsToSpaceAllClientsReconnection = Math.round( - Math.random() * SSE_CONNECTION_RETRY_MAX_WAIT_TIME_IN_MS, + if (!isDefined(sseClient)) { + await sleep( + SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_TO_AVOID_RACE_CONDITIONS, ); - const isDevelopmentEnvironment = getIsDevelopmentEnvironment(); + return; + } - const waitTimeInMs = isDevelopmentEnvironment - ? SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_FOR_DEV_MODE - : randomWaitTimeInMsToSpaceAllClientsReconnection; + const tokenPair = jotaiStore.get(tokenPairState.atom); + const currentAppToken = tokenPair?.accessOrWorkspaceAgnosticToken?.token; - await sleep(waitTimeInMs); - }, - [jotaiStore], + const shouldResetSseClient = + !isDefined(currentAppToken) || + currentAppToken !== initialTokenForSseClient || + retryCount > 10; + + if (shouldResetSseClient) { + await sleep( + SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_TO_AVOID_RACE_CONDITIONS, + ); + + sseClient.dispose(); + jotaiStore.set(shouldDestroyEventStreamState.atom, true); + jotaiStore.set(sseClientState.atom, null); + return; + } + + const randomWaitTimeInMsToSpaceAllClientsReconnection = Math.round( + Math.random() * SSE_CONNECTION_RETRY_MAX_WAIT_TIME_IN_MS, + ); + + const isDevelopmentEnvironment = getIsDevelopmentEnvironment(); + + const waitTimeInMs = isDevelopmentEnvironment + ? SSE_CONNECTION_RETRY_WAIT_TIME_IN_MS_FOR_DEV_MODE + : randomWaitTimeInMsToSpaceAllClientsReconnection; + + await sleep(waitTimeInMs); + }, + [], ); return { handleSseClientConnectionRetry }; diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useListenToEventsForQuery.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useListenToEventsForQuery.ts index c8f5d74ebf..41f3d0ec72 100644 --- a/packages/twenty-front/src/modules/sse-db-event/hooks/useListenToEventsForQuery.ts +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useListenToEventsForQuery.ts @@ -1,7 +1,6 @@ import { requiredQueryListenersState } from '@/sse-db-event/states/requiredQueryListenersState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useCallback, useEffect } from 'react'; import { type MetadataGqlOperationSignature, type RecordGqlOperationSignature, @@ -16,46 +15,43 @@ export const useListenToEventsForQuery = ({ | RecordGqlOperationSignature | MetadataGqlOperationSignature; }) => { - const changeQueryIdListenState = useRecoilCallback( - ({ set, snapshot }) => - ( - shouldListen: boolean, - targetQueryId: string, - targetOperationSignature: - | RecordGqlOperationSignature - | MetadataGqlOperationSignature, - ) => { - const currentRequiredQueryListeners = getSnapshotValue( - snapshot, - requiredQueryListenersState, + const changeQueryIdListenState = useCallback( + ( + shouldListen: boolean, + targetQueryId: string, + targetOperationSignature: + | RecordGqlOperationSignature + | MetadataGqlOperationSignature, + ) => { + const currentRequiredQueryListeners = jotaiStore.get( + requiredQueryListenersState.atom, + ); + + const listeningForThisQueryIsActive = currentRequiredQueryListeners.some( + (listener) => listener.queryId === targetQueryId, + ); + + if (shouldListen === listeningForThisQueryIsActive) { + return; + } + + if (shouldListen) { + jotaiStore.set(requiredQueryListenersState.atom, [ + ...currentRequiredQueryListeners, + { + queryId: targetQueryId, + operationSignature: targetOperationSignature, + }, + ]); + } else { + jotaiStore.set( + requiredQueryListenersState.atom, + currentRequiredQueryListeners.filter( + (listener) => listener.queryId !== targetQueryId, + ), ); - - const listeningForThisQueryIsActive = - currentRequiredQueryListeners.some( - (listener) => listener.queryId === targetQueryId, - ); - - if (shouldListen === listeningForThisQueryIsActive) { - return; - } - - if (shouldListen) { - set(requiredQueryListenersState, [ - ...currentRequiredQueryListeners, - { - queryId: targetQueryId, - operationSignature: targetOperationSignature, - }, - ]); - } else { - set( - requiredQueryListenersState, - currentRequiredQueryListeners.filter( - (listener) => listener.queryId !== targetQueryId, - ), - ); - } - }, + } + }, [], ); diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts index 9e6986343a..fe1c97a87b 100644 --- a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamCreation.ts @@ -9,18 +9,19 @@ import { shouldDestroyEventStreamState } from '@/sse-db-event/states/shouldDestr import { sseClientState } from '@/sse-db-event/states/sseClientState'; import { sseEventStreamIdState } from '@/sse-db-event/states/sseEventStreamIdState'; import { sseEventStreamReadyState } from '@/sse-db-event/states/sseEventStreamReadyState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { captureException } from '@sentry/react'; import { isNonEmptyString } from '@sniptt/guards'; import { print, type ExecutionResult } from 'graphql'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { type EventSubscription } from '~/generated-metadata/graphql'; export const useTriggerEventStreamCreation = () => { - const setIsCreatingSseEventStream = useSetRecoilState( + const setIsCreatingSseEventStream = useSetRecoilStateV2( isCreatingSseEventStreamState, ); @@ -33,173 +34,163 @@ export const useTriggerEventStreamCreation = () => { const { triggerOptimisticEffectFromSseEvents } = useTriggerOptimisticEffectFromSseEvents(); - const triggerEventStreamCreation = useRecoilCallback( - ({ snapshot, set }) => - () => { - const sseClient = snapshot.getLoadable(sseClientState).getValue(); + const triggerEventStreamCreation = useCallback(() => { + const sseClient = jotaiStore.get(sseClientState.atom); - const isCreatingSseEventStream = snapshot - .getLoadable(isCreatingSseEventStreamState) - .getValue(); + const isCreatingSseEventStream = jotaiStore.get( + isCreatingSseEventStreamState.atom, + ); - const isDestroyingEventStream = snapshot - .getLoadable(isDestroyingEventStreamState) - .getValue(); + const isDestroyingEventStream = jotaiStore.get( + isDestroyingEventStreamState.atom, + ); - const currentSseEventStreamId = getSnapshotValue( - snapshot, - sseEventStreamIdState, - ); + const currentSseEventStreamId = jotaiStore.get(sseEventStreamIdState.atom); - if ( - isCreatingSseEventStream || - isDestroyingEventStream || - !isDefined(sseClient) || - isNonEmptyString(currentSseEventStreamId) - ) { - return; - } + if ( + isCreatingSseEventStream || + isDestroyingEventStream || + !isDefined(sseClient) || + isNonEmptyString(currentSseEventStreamId) + ) { + return; + } - setIsCreatingSseEventStream(true); + setIsCreatingSseEventStream(true); - const newSseEventStreamId = v4(); + const newSseEventStreamId = v4(); - set(sseEventStreamIdState, newSseEventStreamId); - set(sseEventStreamReadyState, false); + jotaiStore.set(sseEventStreamIdState.atom, newSseEventStreamId); + jotaiStore.set(sseEventStreamReadyState.atom, false); - let hasReceivedFirstEvent = false; + let hasReceivedFirstEvent = false; - const dispose = sseClient.subscribe( - { - query: print(ON_EVENT_SUBSCRIPTION), - variables: { - eventStreamId: newSseEventStreamId, - }, - }, - { - next: ( - value: ExecutionResult<{ - onEventSubscription: EventSubscription; - }>, - ) => { - if (isDefined(value?.errors)) { - captureException( - new Error( - `SSE subscription error: ${value.errors[0]?.message}`, - ), - ); - set(shouldDestroyEventStreamState, true); + const dispose = sseClient.subscribe( + { + query: print(ON_EVENT_SUBSCRIPTION), + variables: { + eventStreamId: newSseEventStreamId, + }, + }, + { + next: ( + value: ExecutionResult<{ + onEventSubscription: EventSubscription; + }>, + ) => { + if (isDefined(value?.errors)) { + captureException( + new Error(`SSE subscription error: ${value.errors[0]?.message}`), + ); + jotaiStore.set(shouldDestroyEventStreamState.atom, true); - return; - } + return; + } - if (!hasReceivedFirstEvent) { - hasReceivedFirstEvent = true; - set(sseEventStreamReadyState, true); - } + if (!hasReceivedFirstEvent) { + hasReceivedFirstEvent = true; + jotaiStore.set(sseEventStreamReadyState.atom, true); + } - const eventSubscription = value?.data?.onEventSubscription; + const eventSubscription = value?.data?.onEventSubscription; - const objectRecordEventsWithQueryIds = - eventSubscription?.objectRecordEventsWithQueryIds ?? []; + const objectRecordEventsWithQueryIds = + eventSubscription?.objectRecordEventsWithQueryIds ?? []; - const metadataEventsWithQueryIds = - eventSubscription?.metadataEventsWithQueryIds ?? []; + const metadataEventsWithQueryIds = + eventSubscription?.metadataEventsWithQueryIds ?? []; - const objectRecordEvents = objectRecordEventsWithQueryIds.map( - (item) => item.objectRecordEvent, - ); + const objectRecordEvents = objectRecordEventsWithQueryIds.map( + (item) => item.objectRecordEvent, + ); - triggerOptimisticEffectFromSseEvents({ - objectRecordEvents, - }); + triggerOptimisticEffectFromSseEvents({ + objectRecordEvents, + }); - dispatchObjectRecordEventsFromSseToBrowserEvents( - objectRecordEventsWithQueryIds, - ); + dispatchObjectRecordEventsFromSseToBrowserEvents( + objectRecordEventsWithQueryIds, + ); - dispatchMetadataEventsFromSseToBrowserEvents( - metadataEventsWithQueryIds, - ); - }, - error: (error) => { - captureException(error); - }, - complete: () => {}, - }, - { - message: ({ data, event }) => { - const result = data as ExecutionResult<{ - onEventSubscription: EventSubscription; - }>; + dispatchMetadataEventsFromSseToBrowserEvents( + metadataEventsWithQueryIds, + ); + }, + error: (error) => { + captureException(error); + }, + complete: () => {}, + }, + { + message: ({ data, event }) => { + const result = data as ExecutionResult<{ + onEventSubscription: EventSubscription; + }>; - try { - if (event === 'next') { - if (isDefined(result?.errors)) { - const subCode = result.errors[0]?.extensions?.subCode; + try { + if (event === 'next') { + if (isDefined(result?.errors)) { + const subCode = result.errors[0]?.extensions?.subCode; - switch (subCode) { - case 'EVENT_STREAM_ALREADY_EXISTS': { - set(shouldDestroyEventStreamState, true); - break; - } - default: { - for (const error of result.errors) { - captureException(error); - } - } + switch (subCode) { + case 'EVENT_STREAM_ALREADY_EXISTS': { + jotaiStore.set(shouldDestroyEventStreamState.atom, true); + break; + } + default: { + for (const error of result.errors) { + captureException(error); } - - set(shouldDestroyEventStreamState, true); - } else { - if (!hasReceivedFirstEvent) { - hasReceivedFirstEvent = true; - set(sseEventStreamReadyState, true); - } - - const objectRecordEventsWithQueryIds = - result?.data?.onEventSubscription - ?.objectRecordEventsWithQueryIds ?? []; - - const objectRecordEvents = - objectRecordEventsWithQueryIds.map( - (objectRecordEventWithQueryIds) => { - return objectRecordEventWithQueryIds.objectRecordEvent; - }, - ); - - triggerOptimisticEffectFromSseEvents({ - objectRecordEvents, - }); - - dispatchObjectRecordEventsFromSseToBrowserEvents( - objectRecordEventsWithQueryIds, - ); } } - } catch (error) { - const errorProcessingSSEMessage = new Error( - 'Error while processing SSE message', - { cause: error instanceof Error ? error : undefined }, + + jotaiStore.set(shouldDestroyEventStreamState.atom, true); + } else { + if (!hasReceivedFirstEvent) { + hasReceivedFirstEvent = true; + jotaiStore.set(sseEventStreamReadyState.atom, true); + } + + const objectRecordEventsWithQueryIds = + result?.data?.onEventSubscription + ?.objectRecordEventsWithQueryIds ?? []; + + const objectRecordEvents = objectRecordEventsWithQueryIds.map( + (objectRecordEventWithQueryIds) => { + return objectRecordEventWithQueryIds.objectRecordEvent; + }, ); - captureException(errorProcessingSSEMessage); + triggerOptimisticEffectFromSseEvents({ + objectRecordEvents, + }); + + dispatchObjectRecordEventsFromSseToBrowserEvents( + objectRecordEventsWithQueryIds, + ); } - }, - }, - ); + } + } catch (error) { + const errorProcessingSSEMessage = new Error( + 'Error while processing SSE message', + { cause: error instanceof Error ? error : undefined }, + ); - set(disposeFunctionForEventStreamState, { dispose }); - - setIsCreatingSseEventStream(false); + captureException(errorProcessingSSEMessage); + } + }, }, - [ - dispatchMetadataEventsFromSseToBrowserEvents, - dispatchObjectRecordEventsFromSseToBrowserEvents, - setIsCreatingSseEventStream, - triggerOptimisticEffectFromSseEvents, - ], - ); + ); + + jotaiStore.set(disposeFunctionForEventStreamState.atom, { dispose }); + + setIsCreatingSseEventStream(false); + }, [ + dispatchMetadataEventsFromSseToBrowserEvents, + dispatchObjectRecordEventsFromSseToBrowserEvents, + setIsCreatingSseEventStream, + triggerOptimisticEffectFromSseEvents, + ]); return { triggerEventStreamCreation, diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamDestroy.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamDestroy.ts index d2552d3cce..c0a1807ab6 100644 --- a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamDestroy.ts +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerEventStreamDestroy.ts @@ -4,52 +4,48 @@ import { isDestroyingEventStreamState } from '@/sse-db-event/states/isDestroying import { shouldDestroyEventStreamState } from '@/sse-db-event/states/shouldDestroyEventStreamState'; import { sseEventStreamIdState } from '@/sse-db-event/states/sseEventStreamIdState'; import { sseEventStreamReadyState } from '@/sse-db-event/states/sseEventStreamReadyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { isNonEmptyString } from '@sniptt/guards'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useCallback } from 'react'; export const useTriggerEventStreamDestroy = () => { - const setIsDestroyingEventStream = useSetRecoilState( + const setIsDestroyingEventStream = useSetRecoilStateV2( isDestroyingEventStreamState, ); - const triggerEventStreamDestroy = useRecoilCallback( - ({ snapshot, set }) => - () => { - const isDestroyingEventStream = snapshot - .getLoadable(isDestroyingEventStreamState) - .getValue(); + const triggerEventStreamDestroy = useCallback(() => { + const isDestroyingEventStream = jotaiStore.get( + isDestroyingEventStreamState.atom, + ); - const isCreatingSseEventStream = snapshot - .getLoadable(isCreatingSseEventStreamState) - .getValue(); + const isCreatingSseEventStream = jotaiStore.get( + isCreatingSseEventStreamState.atom, + ); - if (isDestroyingEventStream || isCreatingSseEventStream) { - return; - } + if (isDestroyingEventStream || isCreatingSseEventStream) { + return; + } - setIsDestroyingEventStream(true); + setIsDestroyingEventStream(true); - const eventStreamId = snapshot - .getLoadable(sseEventStreamIdState) - .getValue(); + const eventStreamId = jotaiStore.get(sseEventStreamIdState.atom); - const disposeFunctionForEventStream = snapshot - .getLoadable(disposeFunctionForEventStreamState) - .getValue(); + const disposeFunctionForEventStream = jotaiStore.get( + disposeFunctionForEventStreamState.atom, + ); - if (isNonEmptyString(eventStreamId)) { - disposeFunctionForEventStream?.dispose(); + if (isNonEmptyString(eventStreamId)) { + disposeFunctionForEventStream?.dispose(); - set(sseEventStreamIdState, null); - set(sseEventStreamReadyState, false); - set(disposeFunctionForEventStreamState, null); - set(shouldDestroyEventStreamState, false); - } + jotaiStore.set(sseEventStreamIdState.atom, null); + jotaiStore.set(sseEventStreamReadyState.atom, false); + jotaiStore.set(disposeFunctionForEventStreamState.atom, null); + jotaiStore.set(shouldDestroyEventStreamState.atom, false); + } - setIsDestroyingEventStream(false); - }, - [setIsDestroyingEventStream], - ); + setIsDestroyingEventStream(false); + }, [setIsDestroyingEventStream]); return { triggerEventStreamDestroy, diff --git a/packages/twenty-front/src/modules/sse-db-event/states/activeQueryListenersState.ts b/packages/twenty-front/src/modules/sse-db-event/states/activeQueryListenersState.ts index d215b474d4..044cd85121 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/activeQueryListenersState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/activeQueryListenersState.ts @@ -1,10 +1,10 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type MetadataGqlOperationSignature, type RecordGqlOperationSignature, } from 'twenty-shared/types'; -export const activeQueryListenersState = createState< +export const activeQueryListenersState = createStateV2< { queryId: string; operationSignature: diff --git a/packages/twenty-front/src/modules/sse-db-event/states/disposeFunctionByEventStreamMapState.ts b/packages/twenty-front/src/modules/sse-db-event/states/disposeFunctionByEventStreamMapState.ts index 0b748e0f21..45f4f7f3de 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/disposeFunctionByEventStreamMapState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/disposeFunctionByEventStreamMapState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const disposeFunctionForEventStreamState = createState<{ +export const disposeFunctionForEventStreamState = createStateV2<{ dispose: () => void; } | null>({ key: 'disposeFunctionForEventStreamState', diff --git a/packages/twenty-front/src/modules/sse-db-event/states/isCreatingSseEventStreamState.ts b/packages/twenty-front/src/modules/sse-db-event/states/isCreatingSseEventStreamState.ts index c7ed4b1427..66b8299bdb 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/isCreatingSseEventStreamState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/isCreatingSseEventStreamState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const isCreatingSseEventStreamState = createState({ +export const isCreatingSseEventStreamState = createStateV2({ key: 'isCreatingSseEventStreamState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/sse-db-event/states/isDestroyingEventStreamState.ts b/packages/twenty-front/src/modules/sse-db-event/states/isDestroyingEventStreamState.ts index 6ec3e082f7..92ade571d5 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/isDestroyingEventStreamState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/isDestroyingEventStreamState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const isDestroyingEventStreamState = createState({ +export const isDestroyingEventStreamState = createStateV2({ key: 'isDestroyingEventStreamState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/sse-db-event/states/requiredQueryListenersState.ts b/packages/twenty-front/src/modules/sse-db-event/states/requiredQueryListenersState.ts index e788ede15b..9969bd5ac8 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/requiredQueryListenersState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/requiredQueryListenersState.ts @@ -1,10 +1,10 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type MetadataGqlOperationSignature, type RecordGqlOperationSignature, } from 'twenty-shared/types'; -export const requiredQueryListenersState = createState< +export const requiredQueryListenersState = createStateV2< { queryId: string; operationSignature: diff --git a/packages/twenty-front/src/modules/sse-db-event/states/shouldDestroyEventStreamState.ts b/packages/twenty-front/src/modules/sse-db-event/states/shouldDestroyEventStreamState.ts index 4459c19497..9f5eb4efbc 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/shouldDestroyEventStreamState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/shouldDestroyEventStreamState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const shouldDestroyEventStreamState = createState({ +export const shouldDestroyEventStreamState = createStateV2({ key: 'shouldDestroyEventStreamState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/sse-db-event/states/sseClientState.ts b/packages/twenty-front/src/modules/sse-db-event/states/sseClientState.ts index 32e9c35e30..d575add50c 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/sseClientState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/sseClientState.ts @@ -1,7 +1,7 @@ import { type Client } from 'graphql-sse'; -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const sseClientState = createState({ +export const sseClientState = createStateV2({ key: 'sseClientState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamIdState.ts b/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamIdState.ts index 77c66ec72a..0c4b2cab57 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamIdState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamIdState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const sseEventStreamIdState = createState({ +export const sseEventStreamIdState = createStateV2({ key: 'sseEventStreamIdState', defaultValue: null, }); diff --git a/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamReadyState.ts b/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamReadyState.ts index 2df7ad80a9..c11a70fe34 100644 --- a/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamReadyState.ts +++ b/packages/twenty-front/src/modules/sse-db-event/states/sseEventStreamReadyState.ts @@ -1,6 +1,6 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const sseEventStreamReadyState = createState({ +export const sseEventStreamReadyState = createStateV2({ key: 'sseEventStreamReadyState', defaultValue: false, }); diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/FieldRichTextCard.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/FieldRichTextCard.tsx index 256f943f17..32a4a41c77 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/FieldRichTextCard.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/FieldRichTextCard.tsx @@ -1,13 +1,13 @@ import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; +import { recordStoreFamilySelectorV2 } from '@/object-record/record-store/states/selectors/recordStoreFamilySelectorV2'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { lazy, Suspense } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; -import { useRecoilValue } from 'recoil'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { isDefined } from 'twenty-shared/utils'; const ActivityRichTextEditor = lazy(() => @@ -48,12 +48,10 @@ const LoadingSkeleton = () => { export const FieldRichTextCard = () => { const targetRecord = useTargetRecord(); - const activityBodyV2 = useRecoilValue( - recordStoreFamilySelector({ - recordId: targetRecord.id, - fieldName: 'bodyV2', - }), - ); + const activityBodyV2 = useFamilySelectorValueV2(recordStoreFamilySelectorV2, { + recordId: targetRecord.id, + fieldName: 'bodyV2', + }); const activityObjectNameSingular = targetRecord.targetObjectNameSingular as | CoreObjectNameSingular.Note diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx index 7938343ddc..6a017ef89f 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx @@ -4,7 +4,6 @@ import styled from '@emotion/styled'; import { Trans } from '@lingui/react/macro'; import { type ChangeEvent, type ReactNode, useRef } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { AppTooltip, @@ -12,8 +11,9 @@ import { type AvatarType, type IconComponent, } from 'twenty-ui/display'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { v4 as uuidV4 } from 'uuid'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { beautifyExactDateTime, beautifyPastDateRelativeToNow, @@ -123,7 +123,7 @@ export const ShowPageSummaryCard = ({ loading, isMobile = false, }: ShowPageSummaryCardProps) => { - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const beautifiedCreatedAt = date !== '' ? beautifyPastDateRelativeToNow(date, localeCatalog) : ''; const exactCreatedAt = date !== '' ? beautifyExactDateTime(date) : ''; 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 65d27ee54f..a600e1e024 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,10 +1,10 @@ import styled from '@emotion/styled'; import { type ReactNode, useState } from 'react'; -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 { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; 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'; @@ -82,7 +82,7 @@ export const NavigationDrawer = ({ const [navigationDrawerWidth, setNavigationDrawerWidth] = useRecoilStateV2( navigationDrawerWidthState, ); - const setTableWidthResizeIsActive = useSetRecoilState( + const setTableWidthResizeIsActive = useSetRecoilStateV2( tableWidthResizeIsActiveState, ); diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md b/packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md index 926afb6803..57389dbaf0 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md @@ -241,14 +241,13 @@ object-record/states/recordStoreFamilyState.ts (raw atomFamily) object-record/record-store/states/recordStoreFamilyState.ts ``` -### Selectors (6 files) +### Selectors (1 file remaining) ``` -object-record/record-store/states/selectors/recordStoreFamilySelector.ts -object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts -object-record/record-store/states/selectors/recordStoreIdentifierSelector.ts -object-record/record-store/states/selectors/recordStoreIdentifiersSelector.ts -object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector.ts -object-record/record-store/states/selectors/recordStoreRecordsSelector.ts +object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts ✅ MIGRATED (useRecordFieldValue uses V2) +object-record/record-store/states/selectors/recordStoreIdentifierSelector.ts ✅ MIGRATED (recordStoreIdentifierFamilySelectorV2) +object-record/record-store/states/selectors/recordStoreIdentifiersSelector.ts ✅ MIGRATED (already V2, now uses recordStoreFamilyState) +object-record/record-store/states/selectors/recordStoreMorphOneToManyValueWithObjectNameFamilySelector.ts ✅ MIGRATED +object-record/record-store/states/selectors/recordStoreRecordsSelector.ts ✅ MIGRATED (recordStoreRecordsSelectorV2) ``` --- @@ -264,7 +263,7 @@ object-record/record-filter-group/states/ (1 file) object-record/record-sort/states/ (1 file) object-record/record-group/states/ (3 files) object-record/record-drag/states/ (7 files) -object-record/record-field/states/ (7 files) +object-record/record-field/states/ (6 files) — filesFieldUploadState ✅ MIGRATED (deleted, use filesFieldUploadStateV2) object-record/record-field-list/states/ (2 files) object-record/record-calendar/states/ (6 files) object-record/record-board/states/ (18 files) diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2.ts new file mode 100644 index 0000000000..c947f69ea3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorCallbackStateV2.ts @@ -0,0 +1,38 @@ +import { useCallback } from 'react'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentFamilySelectorV2'; + +export const useRecoilComponentFamilySelectorCallbackStateV2 = < + StateType, + FamilyKey, +>( + componentFamilySelector: ComponentFamilySelectorV2, + instanceIdFromProps?: string, +): (( + familyKey: FamilyKey, +) => ReturnType< + ComponentFamilySelectorV2['selectorFamily'] +>) => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentFamilySelector.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentFamilySelector.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useCallback( + (familyKey: FamilyKey) => + componentFamilySelector.selectorFamily({ instanceId, familyKey }), + [componentFamilySelector, instanceId], + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2.ts new file mode 100644 index 0000000000..f5aaf8c184 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilySelectorValueV2.ts @@ -0,0 +1,30 @@ +import { useAtomValue } from 'jotai'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentFamilySelectorV2'; + +export const useRecoilComponentFamilySelectorValueV2 = ( + componentFamilySelector: ComponentFamilySelectorV2, + familyKey: FamilyKey, + instanceIdFromProps?: string, +): StateType => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentFamilySelector.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentFamilySelector.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useAtomValue( + componentFamilySelector.selectorFamily({ instanceId, familyKey }), + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2.ts new file mode 100644 index 0000000000..8a3899cf3c --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2.ts @@ -0,0 +1,38 @@ +import { useCallback } from 'react'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/types/ComponentFamilyStateV2'; + +export const useRecoilComponentFamilyStateCallbackStateV2 = < + StateType, + FamilyKey, +>( + componentFamilyState: ComponentFamilyStateV2, + instanceIdFromProps?: string, +): (( + familyKey: FamilyKey, +) => ReturnType< + ComponentFamilyStateV2['atomFamily'] +>) => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentFamilyState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentFamilyState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useCallback( + (familyKey: FamilyKey) => + componentFamilyState.atomFamily({ instanceId, familyKey }), + [componentFamilyState, instanceId], + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2.ts new file mode 100644 index 0000000000..0c8315bc0e --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2.ts @@ -0,0 +1,30 @@ +import { useMemo } from 'react'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentSelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentSelectorV2'; + +export const useRecoilComponentSelectorCallbackStateV2 = ( + componentSelector: ComponentSelectorV2, + instanceIdFromProps?: string, +): ReturnType['selectorFamily']> => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentSelector.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentSelector.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useMemo( + () => componentSelector.selectorFamily({ instanceId }), + [componentSelector, instanceId], + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2.ts new file mode 100644 index 0000000000..cecdf258e3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2.ts @@ -0,0 +1,27 @@ +import { useAtomValue } from 'jotai'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentSelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentSelectorV2'; + +export const useRecoilComponentSelectorValueV2 = ( + componentSelector: ComponentSelectorV2, + instanceIdFromProps?: string, +): StateType => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentSelector.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentSelector.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useAtomValue(componentSelector.selectorFamily({ instanceId })); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2.ts new file mode 100644 index 0000000000..c6ba0d8842 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2.ts @@ -0,0 +1,30 @@ +import { useMemo } from 'react'; + +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; + +export const useRecoilComponentStateCallbackStateV2 = ( + componentState: ComponentStateV2, + instanceIdFromProps?: string, +): ReturnType['atomFamily']> => { + const componentInstanceContext = globalComponentInstanceContextMap.get( + componentState.key, + ); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentState.key}" is not defined`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useMemo( + () => componentState.atomFamily({ instanceId }), + [componentState, instanceId], + ); +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentFamilySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentFamilySelectorV2.ts new file mode 100644 index 0000000000..d60e8d5f72 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentFamilySelectorV2.ts @@ -0,0 +1,9 @@ +import { type Atom } from 'jotai'; + +import { type ComponentFamilyStateKey } from '@/ui/utilities/state/jotai/types/ComponentFamilyStateV2'; + +export type ComponentFamilySelectorV2 = { + type: 'ComponentFamilySelectorV2'; + key: string; + selectorFamily: (key: ComponentFamilyStateKey) => Atom; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentSelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentSelectorV2.ts new file mode 100644 index 0000000000..6e31fbf1aa --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/ComponentSelectorV2.ts @@ -0,0 +1,9 @@ +import { type Atom } from 'jotai'; + +import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; + +export type ComponentSelectorV2 = { + type: 'ComponentSelectorV2'; + key: string; + selectorFamily: (key: ComponentStateKey) => Atom; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/FamilyStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/FamilyStateV2.ts index a5600dfd67..9d64912cb1 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/FamilyStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/FamilyStateV2.ts @@ -10,4 +10,4 @@ export type FamilyStateV2 = { type: 'FamilyStateV2'; key: string; atomFamily: (key: FamilyKey) => JotaiWritableAtom; -}; +} & ((key: FamilyKey) => JotaiWritableAtom); diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/SelectorCallbacksV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/SelectorCallbacksV2.ts index 72703c741d..385cfd4ec0 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/SelectorCallbacksV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/types/SelectorCallbacksV2.ts @@ -1,3 +1,11 @@ +import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { type ComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentFamilySelectorV2'; +import { + type ComponentFamilyStateKey, + type ComponentFamilyStateV2, +} from '@/ui/utilities/state/jotai/types/ComponentFamilyStateV2'; +import { type ComponentSelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentSelectorV2'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; import { type FamilySelectorV2 } from '@/ui/utilities/state/jotai/types/FamilySelectorV2'; import { type FamilyStateV2 } from '@/ui/utilities/state/jotai/types/FamilyStateV2'; import { type SelectorV2 } from '@/ui/utilities/state/jotai/types/SelectorV2'; @@ -12,6 +20,22 @@ export type SelectorGetterV2 = { | FamilySelectorV2, familyKey: FamilyKey, ): ValueType; + ( + componentState: ComponentStateV2, + key: ComponentStateKey, + ): ValueType; + ( + componentFamilyState: ComponentFamilyStateV2, + key: ComponentFamilyStateKey, + ): ValueType; + ( + componentSelector: ComponentSelectorV2, + key: ComponentStateKey, + ): ValueType; + ( + componentFamilySelector: ComponentFamilySelectorV2, + key: ComponentFamilyStateKey, + ): ValueType; }; }; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/buildGetHelper.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/buildGetHelper.ts index 446c9684a8..679f6a217f 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/buildGetHelper.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/buildGetHelper.ts @@ -1,5 +1,13 @@ import { type Getter } from 'jotai'; +import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { + type ComponentFamilyStateKey, + type ComponentFamilyStateV2, +} from '@/ui/utilities/state/jotai/types/ComponentFamilyStateV2'; +import { type ComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentFamilySelectorV2'; +import { type ComponentSelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentSelectorV2'; +import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2'; import { type FamilySelectorV2 } from '@/ui/utilities/state/jotai/types/FamilySelectorV2'; import { type FamilyStateV2 } from '@/ui/utilities/state/jotai/types/FamilyStateV2'; import { type SelectorV2 } from '@/ui/utilities/state/jotai/types/SelectorV2'; @@ -12,13 +20,52 @@ export const buildGetHelper = | StateV2 | SelectorV2 | FamilyStateV2 - | FamilySelectorV2, - familyKey?: FamilyKey, + | FamilySelectorV2 + | ComponentStateV2 + | ComponentFamilyStateV2 + | ComponentSelectorV2 + | ComponentFamilySelectorV2, + keyOrFamilyKey?: + | FamilyKey + | ComponentStateKey + | ComponentFamilyStateKey, ): ValueType => { + if (stateOrFamily.type === 'ComponentStateV2') { + return jotaiGet( + (stateOrFamily as ComponentStateV2).atomFamily( + keyOrFamilyKey as ComponentStateKey, + ), + ); + } + + if (stateOrFamily.type === 'ComponentFamilyStateV2') { + return jotaiGet( + ( + stateOrFamily as ComponentFamilyStateV2 + ).atomFamily(keyOrFamilyKey as ComponentFamilyStateKey), + ); + } + + if (stateOrFamily.type === 'ComponentSelectorV2') { + return jotaiGet( + (stateOrFamily as ComponentSelectorV2).selectorFamily( + keyOrFamilyKey as ComponentStateKey, + ), + ); + } + + if (stateOrFamily.type === 'ComponentFamilySelectorV2') { + return jotaiGet( + ( + stateOrFamily as ComponentFamilySelectorV2 + ).selectorFamily(keyOrFamilyKey as ComponentFamilyStateKey), + ); + } + if (stateOrFamily.type === 'FamilyStateV2') { return jotaiGet( (stateOrFamily as FamilyStateV2).atomFamily( - familyKey as FamilyKey, + keyOrFamilyKey as FamilyKey, ), ); } @@ -27,7 +74,7 @@ export const buildGetHelper = return jotaiGet( ( stateOrFamily as FamilySelectorV2 - ).selectorFamily(familyKey as FamilyKey), + ).selectorFamily(keyOrFamilyKey as FamilyKey), ); } diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2.ts new file mode 100644 index 0000000000..df9dcfbba1 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentFamilySelectorV2.ts @@ -0,0 +1,61 @@ +import { atom, type Atom } from 'jotai'; + +import { type ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentFamilySelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentFamilySelectorV2'; +import { type ComponentFamilyStateKey } from '@/ui/utilities/state/jotai/types/ComponentFamilyStateV2'; +import { type SelectorGetterV2 } from '@/ui/utilities/state/jotai/types/SelectorCallbacksV2'; +import { buildGetHelper } from '@/ui/utilities/state/jotai/utils/buildGetHelper'; +import { isDefined } from 'twenty-shared/utils'; + +export const createComponentFamilySelectorV2 = ({ + key, + get, + componentInstanceContext, +}: { + key: string; + get: ( + key: ComponentFamilyStateKey, + ) => (callbacks: SelectorGetterV2) => ValueType; + componentInstanceContext: ComponentInstanceStateContext | null; +}): ComponentFamilySelectorV2 => { + if (isDefined(componentInstanceContext)) { + globalComponentInstanceContextMap.set(key, componentInstanceContext); + } + + const atomCache = new Map>(); + + const selectorFamily = ( + componentFamilyStateKey: ComponentFamilyStateKey, + ): Atom => { + const familyKeyStr = + typeof componentFamilyStateKey.familyKey === 'string' + ? componentFamilyStateKey.familyKey + : JSON.stringify(componentFamilyStateKey.familyKey); + const cacheKey = `${componentFamilyStateKey.instanceId}__${familyKeyStr}`; + const existing = atomCache.get(cacheKey); + + if (existing !== undefined) { + return existing; + } + + const getForKey = get(componentFamilyStateKey); + + const derivedAtom = atom((jotaiGet) => { + const getHelper = buildGetHelper(jotaiGet); + + return getForKey({ get: getHelper }); + }); + + derivedAtom.debugLabel = `${key}__${cacheKey}`; + atomCache.set(cacheKey, derivedAtom); + + return derivedAtom; + }; + + return { + type: 'ComponentFamilySelectorV2', + key, + selectorFamily, + }; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentSelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentSelectorV2.ts new file mode 100644 index 0000000000..669e76b9d0 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/jotai/utils/createComponentSelectorV2.ts @@ -0,0 +1,54 @@ +import { atom, type Atom } from 'jotai'; + +import { type ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext'; +import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { type ComponentSelectorV2 } from '@/ui/utilities/state/jotai/types/ComponentSelectorV2'; +import { type SelectorGetterV2 } from '@/ui/utilities/state/jotai/types/SelectorCallbacksV2'; +import { buildGetHelper } from '@/ui/utilities/state/jotai/utils/buildGetHelper'; +import { isDefined } from 'twenty-shared/utils'; + +export const createComponentSelectorV2 = ({ + key, + get, + componentInstanceContext, +}: { + key: string; + get: (key: ComponentStateKey) => (callbacks: SelectorGetterV2) => ValueType; + componentInstanceContext: ComponentInstanceStateContext | null; +}): ComponentSelectorV2 => { + if (isDefined(componentInstanceContext)) { + globalComponentInstanceContextMap.set(key, componentInstanceContext); + } + + const atomCache = new Map>(); + + const selectorFamily = ( + componentStateKey: ComponentStateKey, + ): Atom => { + const existing = atomCache.get(componentStateKey.instanceId); + + if (existing !== undefined) { + return existing; + } + + const getForKey = get(componentStateKey); + + const derivedAtom = atom((jotaiGet) => { + const getHelper = buildGetHelper(jotaiGet); + + return getForKey({ get: getHelper }); + }); + + derivedAtom.debugLabel = `${key}__${componentStateKey.instanceId}`; + atomCache.set(componentStateKey.instanceId, derivedAtom); + + return derivedAtom; + }; + + return { + type: 'ComponentSelectorV2', + key, + selectorFamily, + }; +}; 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 7e43e91a8d..389c62c4f7 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 @@ -39,9 +39,9 @@ export const createFamilyStateV2 = ({ return baseAtom; }; - return { - type: 'FamilyStateV2', + return Object.assign(familyFunction, { + type: 'FamilyStateV2' as const, key, atomFamily: familyFunction, - }; + }); }; diff --git a/packages/twenty-front/src/modules/users/components/LazyMetadataLoadEffect.tsx b/packages/twenty-front/src/modules/users/components/LazyMetadataLoadEffect.tsx index f7e074b840..cac6a85b7f 100644 --- a/packages/twenty-front/src/modules/users/components/LazyMetadataLoadEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/LazyMetadataLoadEffect.tsx @@ -6,10 +6,10 @@ import { transformPageLayout } from '@/page-layout/utils/transformPageLayout'; import { logicFunctionsState } from '@/settings/logic-functions/states/logicFunctionsState'; import { coreViewsState } from '@/views/states/coreViewState'; import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useStore } from 'jotai'; import { useCallback, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { AppPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { @@ -28,7 +28,7 @@ export const LazyMetadataLoadEffect = () => { const isLoggedIn = useIsLogged(); const store = useStore(); - const setLogicFunctions = useSetRecoilState(logicFunctionsState); + const setLogicFunctions = useSetRecoilStateV2(logicFunctionsState); const { updateDraft, applyChanges } = useMetadataStore(); const isOnAuthPath = @@ -66,18 +66,15 @@ export const LazyMetadataLoadEffect = () => { [store], ); - const setRecordPageLayouts = useRecoilCallback( - ({ set, snapshot }) => - (recordPageLayouts: PageLayout[]) => { - const existingRecordPageLayouts = snapshot - .getLoadable(recordPageLayoutsState) - .getValue(); + const setRecordPageLayouts = useCallback( + (recordPageLayouts: PageLayout[]) => { + const existingRecordPageLayouts = store.get(recordPageLayoutsState.atom); - if (!isDeeplyEqual(existingRecordPageLayouts, recordPageLayouts)) { - set(recordPageLayoutsState, recordPageLayouts); - } - }, - [], + if (!isDeeplyEqual(existingRecordPageLayouts, recordPageLayouts)) { + store.set(recordPageLayoutsState.atom, recordPageLayouts); + } + }, + [store], ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterChip.tsx b/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterChip.tsx index 1608521ded..03a1bbfb94 100644 --- a/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterChip.tsx @@ -10,7 +10,8 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRe import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { getAllRecordFilterDescendantsOfRecordFilterGroup } from '@/object-record/record-filter/utils/getAllRecordFilterDescendantsOfRecordFilterGroup'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { plural } from '@lingui/core/macro'; @@ -21,11 +22,11 @@ import { IconFilter } from 'twenty-ui/display'; export const AdvancedFilterChip = () => { const { closeDropdown } = useCloseDropdown(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -39,7 +40,7 @@ export const AdvancedFilterChip = () => { const { removeRootRecordFilterGroupIfEmpty } = useRemoveRootRecordFilterGroupIfEmpty(); - const rootRecordFilterGroup = useRecoilComponentValue( + const rootRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterDropdownButton.tsx b/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterDropdownButton.tsx index 58c48bbf32..4a388045be 100644 --- a/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/views/advanced-filter-chip/components/AdvancedFilterDropdownButton.tsx @@ -3,13 +3,13 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { AdvancedFilterRootRecordFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup'; import { useSetAdvancedFilterDropdownStates } from '@/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates'; import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { AdvancedFilterChip } from '@/views/advanced-filter-chip/components/AdvancedFilterChip'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { isDefined } from 'twenty-shared/utils'; export const AdvancedFilterDropdownButton = () => { - const rootLevelRecordFilterGroup = useRecoilComponentValue( + const rootLevelRecordFilterGroup = useRecoilComponentSelectorValueV2( rootLevelRecordFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/views/components/AnyFieldSearchChip.tsx b/packages/twenty-front/src/modules/views/components/AnyFieldSearchChip.tsx index 8cbeca28a3..3f749b089b 100644 --- a/packages/twenty-front/src/modules/views/components/AnyFieldSearchChip.tsx +++ b/packages/twenty-front/src/modules/views/components/AnyFieldSearchChip.tsx @@ -1,6 +1,6 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { useLingui } from '@lingui/react/macro'; @@ -11,9 +11,8 @@ export const AnyFieldSearchChip = () => { const { closeDropdown } = useCloseDropdown(); - const [anyFieldFilterValue, setAnyFieldFilterValue] = useRecoilComponentState( - anyFieldFilterValueComponentState, - ); + const [anyFieldFilterValue, setAnyFieldFilterValue] = + useRecoilComponentStateV2(anyFieldFilterValueComponentState); const handleRemoveClick = () => { closeDropdown(); diff --git a/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx b/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx index 92c9a8eff3..25598a11d2 100644 --- a/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/QueryParamsFiltersEffect.tsx @@ -6,7 +6,7 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObje import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFiltersFromQueryParams } from '@/views/hooks/internal/useFiltersFromQueryParams'; import { useHasFiltersInQueryParams } from '@/views/hooks/internal/useHasFiltersInQueryParams'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; @@ -31,11 +31,11 @@ export const QueryParamsFiltersEffect = () => { const { mapViewFiltersToRecordFilters } = useMapViewFiltersToFilters(); const { recordIndexId } = useRecordIndexContextOrThrow(); - const setCurrentRecordFilters = useSetRecoilComponentState( + const setCurrentRecordFilters = useSetRecoilComponentStateV2( currentRecordFiltersComponentState, recordIndexId, ); - const setCurrentRecordFilterGroups = useSetRecoilComponentState( + const setCurrentRecordFilterGroups = useSetRecoilComponentStateV2( currentRecordFilterGroupsComponentState, recordIndexId, ); diff --git a/packages/twenty-front/src/modules/views/components/SoftDeleteFilterChip.tsx b/packages/twenty-front/src/modules/views/components/SoftDeleteFilterChip.tsx index a9a0a7a647..e35a42427a 100644 --- a/packages/twenty-front/src/modules/views/components/SoftDeleteFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/components/SoftDeleteFilterChip.tsx @@ -1,7 +1,7 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; import { useIcons } from 'twenty-ui/display'; @@ -14,7 +14,7 @@ export const SoftDeleteFilterChip = ({ recordFilter, viewBarId, }: SoftDeleteFilterChipProps) => { - const setIsSoftDeleteFilterActive = useSetRecoilComponentState( + const setIsSoftDeleteFilterActive = useSetRecoilComponentStateV2( isSoftDeleteFilterActiveComponentState, viewBarId, ); diff --git a/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx b/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx index 01b7136ce2..54809e9ac8 100644 --- a/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx +++ b/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx @@ -7,8 +7,8 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { UPDATE_VIEW_BUTTON_DROPDOWN_ID } from '@/views/constants/UpdateViewButtonDropdownId'; import { useHasFiltersInQueryParams } from '@/views/hooks/internal/useHasFiltersInQueryParams'; import { useAreViewFilterGroupsDifferentFromRecordFilterGroups } from '@/views/hooks/useAreViewFilterGroupsDifferentFromRecordFilterGroups'; @@ -45,7 +45,7 @@ export const UpdateViewButtonGroup = () => { const { setViewPickerMode } = useViewPickerMode(); - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); @@ -53,7 +53,7 @@ export const UpdateViewButtonGroup = () => { const { openDropdown: openViewPickerDropdown } = useOpenDropdown(); const { currentView } = useGetCurrentViewOnly(); - const setViewPickerReferenceViewId = useSetRecoilComponentState( + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarAnyFieldFilterEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarAnyFieldFilterEffect.tsx index e2f4a0ecec..546f99dc85 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarAnyFieldFilterEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarAnyFieldFilterEffect.tsx @@ -1,9 +1,9 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { hasInitializedAnyFieldFilterComponentFamilyState } from '@/views/states/hasInitializedAnyFieldFilterComponentFamilyState'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; @@ -11,11 +11,11 @@ import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const ViewBarAnyFieldFilterEffect = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const { objectMetadataItem } = useRecordIndexContextOrThrow(); + const { objectMetadataItem, recordIndexId } = useRecordIndexContextOrThrow(); const currentView = useFamilySelectorValueV2( coreViewFromViewIdFamilySelector, @@ -23,15 +23,16 @@ export const ViewBarAnyFieldFilterEffect = () => { ); const [hasInitializedAnyFieldFilter, setHasInitializedAnyFieldFilter] = - useRecoilComponentFamilyState( + useRecoilComponentFamilyStateV2( hasInitializedAnyFieldFilterComponentFamilyState, { viewId: currentViewId ?? undefined, }, ); - const setAnyFieldFilterValue = useSetRecoilComponentState( + const setAnyFieldFilterValue = useSetRecoilComponentStateV2( anyFieldFilterValueComponentState, + recordIndexId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index a626d07190..b515adc348 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -4,7 +4,6 @@ import { type ReactNode, useMemo } from 'react'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { AdvancedFilterDropdownButton } from '@/views/advanced-filter-chip/components/AdvancedFilterDropdownButton'; import { ViewBarDetailsAddFilterButton } from '@/views/components/ViewBarDetailsAddFilterButton'; @@ -107,26 +106,30 @@ export const ViewBarDetails = ({ viewBarId, objectNamePlural, }: ViewBarDetailsProps) => { - const isViewBarExpanded = useRecoilComponentValue( + const isViewBarExpanded = useRecoilComponentValueV2( isViewBarExpandedComponentState, ); const { hasFiltersQueryParams } = useHasFiltersInQueryParams(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + viewBarId, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + viewBarId, ); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, + viewBarId, ); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, + viewBarId, ); const { objectNameSingular } = useObjectNameSingularFromPlural({ diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx index cc83249f36..20d9a1c7c6 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx @@ -5,7 +5,7 @@ import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdow import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDropdownContent'; import { isDefined } from 'twenty-shared/utils'; import { ViewBarFilterButton } from './ViewBarFilterButton'; @@ -14,7 +14,7 @@ export const ViewBarFilterDropdown = () => { const { resetFilterDropdown } = useResetFilterDropdown(); const { removeRecordFilter } = useRemoveRecordFilter(); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( + const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2( objectFilterDropdownCurrentRecordFilterComponentState, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx index ef4a261519..7d7a5290b2 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx @@ -13,7 +13,7 @@ import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-reco import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import styled from '@emotion/styled'; @@ -67,7 +67,7 @@ export const ViewBarFilterDropdownAdvancedFilterButton = () => { }, ); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAnyFieldSearchButtonMenuItem.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAnyFieldSearchButtonMenuItem.tsx index eec556f58d..5ed5926be0 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAnyFieldSearchButtonMenuItem.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAnyFieldSearchButtonMenuItem.tsx @@ -1,7 +1,7 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyValueV2'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { IconSearch } from 'twenty-ui/display'; @@ -25,7 +25,7 @@ export const ViewBarFilterDropdownAnyFieldSearchButtonMenuItem = ({ }: ViewBarFilterDropdownAnyFieldSearchButtonMenuItemProps) => { const { t } = useLingui(); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx index f867f8b555..7b83c244df 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx @@ -1,21 +1,22 @@ import { objectFilterDropdownAnyFieldSearchIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewBarFilterDropdownAnyFieldSearchInput } from '@/views/components/ViewBarFilterDropdownAnyFieldSearchInput'; import { ViewBarFilterDropdownFieldSelectMenu } from '@/views/components/ViewBarFilterDropdownFieldSelectMenu'; import { ViewBarFilterDropdownFilterInput } from '@/views/components/ViewBarFilterDropdownFilterInput'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; export const ViewBarFilterDropdownContent = () => { - const [objectFilterDropdownFilterIsSelected] = useRecoilComponentState( + const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2( objectFilterDropdownFilterIsSelectedComponentState, ViewBarFilterDropdownIds.MAIN, ); - const objectFilterDropdownAnyFieldSearchIsSelected = useRecoilComponentValue( - objectFilterDropdownAnyFieldSearchIsSelectedComponentState, - ); + const objectFilterDropdownAnyFieldSearchIsSelected = + useRecoilComponentValueV2( + objectFilterDropdownAnyFieldSearchIsSelectedComponentState, + ); const isAnyFieldSearchFilter = objectFilterDropdownAnyFieldSearchIsSelected; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx index ea24d5f9ec..63476d8879 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx @@ -10,7 +10,7 @@ import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/con import { useFilterDropdownSelectableFieldMetadataItems } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu'; import { ViewBarFilterDropdownFieldSelectMenuItem } from '@/views/components/ViewBarFilterDropdownFieldSelectMenuItem'; @@ -53,7 +53,7 @@ export const StyledInput = styled.input` export const ViewBarFilterDropdownFieldSelectMenu = () => { const [objectFilterDropdownSearchInput, setObjectFilterDropdownSearchInput] = - useRecoilComponentState(objectFilterDropdownSearchInputComponentState); + useRecoilComponentStateV2(objectFilterDropdownSearchInputComponentState); const { selectableHiddenFieldMetadataItems, diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx index 56a6efa158..65b5a71cfc 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx @@ -2,11 +2,11 @@ import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/h import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { IconChevronLeft } from 'twenty-ui/display'; export const ViewBarFilterDropdownFilterInputMenuHeader = () => { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx index 35ac2fdf17..fddd0844c1 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarRecordFieldEffect.tsx @@ -1,9 +1,9 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { hasInitializedCurrentRecordFieldsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; @@ -12,7 +12,7 @@ import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const ViewBarRecordFieldEffect = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); @@ -26,14 +26,14 @@ export const ViewBarRecordFieldEffect = () => { const [ hasInitializedCurrentRecordFields, setHasInitializedCurrentRecordFields, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( hasInitializedCurrentRecordFieldsComponentFamilyState, { viewId: currentViewId ?? undefined, }, ); - const setCurrentRecordFields = useSetRecoilComponentState( + const setCurrentRecordFields = useSetRecoilComponentStateV2( currentRecordFieldsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterEffect.tsx index fa2cf3e406..0ff89fcdd1 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterEffect.tsx @@ -1,9 +1,9 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useMapViewFiltersToFilters } from '@/views/hooks/useMapViewFiltersToFilters'; import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState'; @@ -12,11 +12,11 @@ import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const ViewBarRecordFilterEffect = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const { objectMetadataItem } = useRecordIndexContextOrThrow(); + const { objectMetadataItem, recordIndexId } = useRecordIndexContextOrThrow(); const currentView = useFamilySelectorValueV2( coreViewFromViewIdFamilySelector, @@ -26,15 +26,16 @@ export const ViewBarRecordFilterEffect = () => { const [ hasInitializedCurrentRecordFilters, setHasInitializedCurrentRecordFilters, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( hasInitializedCurrentRecordFiltersComponentFamilyState, { viewId: currentViewId ?? undefined, }, ); - const setCurrentRecordFilters = useSetRecoilComponentState( + const setCurrentRecordFilters = useSetRecoilComponentStateV2( currentRecordFiltersComponentState, + recordIndexId, ); const { mapViewFiltersToRecordFilters } = useMapViewFiltersToFilters(); diff --git a/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterGroupEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterGroupEffect.tsx index 2417248477..58f5f4bbd3 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterGroupEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarRecordFilterGroupEffect.tsx @@ -1,9 +1,9 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { hasInitializedCurrentRecordFilterGroupsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; @@ -12,11 +12,11 @@ import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const ViewBarRecordFilterGroupEffect = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const { objectMetadataItem } = useRecordIndexContextOrThrow(); + const { objectMetadataItem, recordIndexId } = useRecordIndexContextOrThrow(); const currentView = useFamilySelectorValueV2( coreViewFromViewIdFamilySelector, @@ -26,15 +26,16 @@ export const ViewBarRecordFilterGroupEffect = () => { const [ hasInitializedCurrentRecordFilterGroups, setHasInitializedCurrentRecordFilterGroups, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( hasInitializedCurrentRecordFilterGroupsComponentFamilyState, { viewId: currentViewId ?? undefined, }, ); - const setCurrentRecordFilterGroups = useSetRecoilComponentState( + const setCurrentRecordFilterGroups = useSetRecoilComponentStateV2( currentRecordFilterGroupsComponentState, + recordIndexId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/views/components/ViewBarRecordSortEffect.tsx b/packages/twenty-front/src/modules/views/components/ViewBarRecordSortEffect.tsx index 0eed62226e..2c93e284fc 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarRecordSortEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarRecordSortEffect.tsx @@ -1,9 +1,9 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { hasInitializedCurrentRecordSortsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordSortsComponentFamilyState'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; @@ -11,11 +11,11 @@ import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const ViewBarRecordSortEffect = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const { objectMetadataItem } = useRecordIndexContextOrThrow(); + const { objectMetadataItem, recordIndexId } = useRecordIndexContextOrThrow(); const currentView = useFamilySelectorValueV2( coreViewFromViewIdFamilySelector, @@ -25,15 +25,16 @@ export const ViewBarRecordSortEffect = () => { const [ hasInitializedCurrentRecordSorts, setHasInitializedCurrentRecordSorts, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( hasInitializedCurrentRecordSortsComponentFamilyState, { viewId: currentViewId ?? undefined, }, ); - const setCurrentRecordSorts = useSetRecoilComponentState( + const setCurrentRecordSorts = useSetRecoilComponentStateV2( currentRecordSortsComponentState, + recordIndexId, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/views/components/ViewFieldsHiddenDropdownSection.tsx b/packages/twenty-front/src/modules/views/components/ViewFieldsHiddenDropdownSection.tsx index 8447f01d4a..71c301d370 100644 --- a/packages/twenty-front/src/modules/views/components/ViewFieldsHiddenDropdownSection.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewFieldsHiddenDropdownSection.tsx @@ -4,7 +4,7 @@ import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dro import { useChangeRecordFieldVisibility } from '@/object-record/record-field/hooks/useChangeRecordFieldVisibility'; import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; import { useContext } from 'react'; import { IconEye, useIcons } from 'twenty-ui/display'; @@ -29,7 +29,7 @@ export const ViewFieldsHiddenDropdownSection = () => { ? handleBoardFieldVisibilityChange : changeRecordFieldVisibility; - const currentRecordFields = useRecoilComponentValue( + const currentRecordFields = useRecoilComponentValueV2( currentRecordFieldsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx index 92b8f7695c..059a6a7817 100644 --- a/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewFieldsVisibleDropdownSection.tsx @@ -11,7 +11,7 @@ import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableIt import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/internal/dropdownYPositionComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; import { useContext } from 'react'; @@ -60,7 +60,7 @@ export const ViewFieldsVisibleDropdownSection = () => { const fieldMetadataItemLabelIdentifier = getLabelIdentifierFieldMetadataItem(objectMetadataItem); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, ); diff --git a/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx b/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx index a60bbb8638..5f8eb65e1e 100644 --- a/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/views/components/__stories__/ViewBarFilterDropdown.stories.tsx @@ -1,4 +1,5 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; +import { useEffect, useMemo, useState } from 'react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural'; @@ -6,7 +7,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; @@ -37,7 +38,7 @@ const meta: Meta = { )!; const instanceId = companyObjectMetadataItem.id; - const setCurrentRecordFields = useSetRecoilComponentState( + const setCurrentRecordFields = useSetRecoilComponentStateV2( currentRecordFieldsComponentState, instanceId, ); @@ -46,27 +47,40 @@ const meta: Meta = { const mockCoreView = mockedCoreViewsData[0]; - setCoreViews([mockCoreView]); - - const setCurrentViewId = useSetRecoilComponentState( + const setCurrentViewId = useSetRecoilComponentStateV2( contextStoreCurrentViewIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); - setCurrentViewId(mockCoreView.id); - - const columns = companyObjectMetadataItem.fields.map( - (fieldMetadataItem, index) => - ({ - id: fieldMetadataItem.id, - fieldMetadataItemId: fieldMetadataItem.id, - isVisible: true, - position: index, - size: 100, - }) satisfies RecordField, + const columns = useMemo( + () => + companyObjectMetadataItem.fields.map( + (fieldMetadataItem, index) => + ({ + id: fieldMetadataItem.id, + fieldMetadataItemId: fieldMetadataItem.id, + isVisible: true, + position: index, + size: 100, + }) satisfies RecordField, + ), + [companyObjectMetadataItem.fields], ); - setCurrentRecordFields(columns); + const [isLoaded, setIsLoaded] = useState(false); + + useEffect(() => { + setCoreViews([mockCoreView]); + setCurrentViewId(mockCoreView.id); + setCurrentRecordFields(columns); + setIsLoaded(true); + }, [ + setCoreViews, + setCurrentViewId, + setCurrentRecordFields, + mockCoreView, + columns, + ]); const { fieldDefinitionByFieldMetadataItemId, @@ -78,6 +92,10 @@ const meta: Meta = { instanceId, ); + if (!isLoaded) { + return <>; + } + return ( { - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = useRecoilComponentSelectorValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx index 32a8c7a670..10621025f4 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.test.tsx @@ -3,8 +3,11 @@ import { renderHook } from '@testing-library/react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { + jotaiStore, + resetJotaiStore, +} from '@/ui/utilities/state/jotai/jotaiStore'; import { useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups } from '@/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups'; import { coreViewsState } from '@/views/states/coreViewState'; import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; @@ -35,6 +38,10 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { ); } + beforeEach(() => { + resetJotaiStore(); + }); + afterEach(() => { jotaiStore.set(coreViewsState.atom, []); }); @@ -79,8 +86,9 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { const { applyCurrentViewFilterGroupsToCurrentRecordFilterGroups } = useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'recordIndexId', ); return { @@ -129,8 +137,9 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { const { applyCurrentViewFilterGroupsToCurrentRecordFilterGroups } = useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'recordIndexId', ); return { @@ -144,8 +153,8 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { componentInstanceId: 'instanceId', contextStoreCurrentObjectMetadataNameSingular: mockObjectMetadataItemNameSingular, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( + onInitializeJotaiStore: (store) => { + store.set( contextStoreCurrentViewIdComponentState.atomFamily({ instanceId: 'instanceId', }), @@ -173,8 +182,9 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { const { applyCurrentViewFilterGroupsToCurrentRecordFilterGroups } = useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + 'recordIndexId', ); return { @@ -188,8 +198,8 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => { componentInstanceId: 'instanceId', contextStoreCurrentObjectMetadataNameSingular: mockObjectMetadataItemNameSingular, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( + onInitializeJotaiStore: (store) => { + store.set( contextStoreCurrentViewIdComponentState.atomFamily({ instanceId: 'instanceId', }), diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx index 69ca7f7097..2574a8866f 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx @@ -3,8 +3,11 @@ import { renderHook } from '@testing-library/react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { + jotaiStore, + resetJotaiStore, +} from '@/ui/utilities/state/jotai/jotaiStore'; import { coreViewsState } from '@/views/states/coreViewState'; import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; import { type View } from '@/views/types/View'; @@ -37,6 +40,10 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { ); } + beforeEach(() => { + resetJotaiStore(); + }); + afterEach(() => { jotaiStore.set(coreViewsState.atom, []); }); @@ -90,8 +97,9 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { const { applyCurrentViewFiltersToCurrentRecordFilters } = useApplyCurrentViewFiltersToCurrentRecordFilters(); - const currentFilters = useRecoilComponentValue( + const currentFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'recordIndexId', ); return { @@ -138,8 +146,9 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { const { applyCurrentViewFiltersToCurrentRecordFilters } = useApplyCurrentViewFiltersToCurrentRecordFilters(); - const currentFilters = useRecoilComponentValue( + const currentFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'recordIndexId', ); return { @@ -153,8 +162,8 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { componentInstanceId: 'instanceId', contextStoreCurrentObjectMetadataNameSingular: mockObjectMetadataItemNameSingular, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( + onInitializeJotaiStore: (store) => { + store.set( contextStoreCurrentViewIdComponentState.atomFamily({ instanceId: 'instanceId', }), @@ -180,8 +189,9 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { const { applyCurrentViewFiltersToCurrentRecordFilters } = useApplyCurrentViewFiltersToCurrentRecordFilters(); - const currentFilters = useRecoilComponentValue( + const currentFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'recordIndexId', ); return { @@ -195,8 +205,8 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { componentInstanceId: 'instanceId', contextStoreCurrentObjectMetadataNameSingular: mockObjectMetadataItemNameSingular, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( + onInitializeJotaiStore: (store) => { + store.set( contextStoreCurrentViewIdComponentState.atomFamily({ instanceId: 'instanceId', }), diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx index ab7b3d784c..6c6a1d2227 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewSortsToCurrentRecordSorts.test.tsx @@ -2,7 +2,7 @@ import { act, renderHook } from '@testing-library/react'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; @@ -81,8 +81,9 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { const { applyCurrentViewSortsToCurrentRecordSorts } = useApplyCurrentViewSortsToCurrentRecordSorts(); - const currentSorts = useRecoilComponentValue( + const currentSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, + 'recordIndexId', ); return { @@ -122,8 +123,9 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { const { applyCurrentViewSortsToCurrentRecordSorts } = useApplyCurrentViewSortsToCurrentRecordSorts(); - const currentSorts = useRecoilComponentValue( + const currentSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, + 'recordIndexId', ); return { @@ -137,8 +139,8 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { componentInstanceId: 'instanceId', contextStoreCurrentObjectMetadataNameSingular: mockObjectMetadataItemNameSingular, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( + onInitializeJotaiStore: (store) => { + store.set( contextStoreCurrentViewIdComponentState.atomFamily({ instanceId: 'instanceId', }), @@ -169,8 +171,9 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { const { applyCurrentViewSortsToCurrentRecordSorts } = useApplyCurrentViewSortsToCurrentRecordSorts(); - const currentSorts = useRecoilComponentValue( + const currentSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, + 'recordIndexId', ); return { @@ -184,8 +187,8 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => { componentInstanceId: 'instanceId', contextStoreCurrentObjectMetadataNameSingular: mockObjectMetadataItemNameSingular, - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( + onInitializeJotaiStore: (store) => { + store.set( contextStoreCurrentViewIdComponentState.atomFamily({ instanceId: 'instanceId', }), diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx index 13f7b8566a..e804a3b40d 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx @@ -2,7 +2,7 @@ import { act, renderHook } from '@testing-library/react'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { type ViewFilter } from '@/views/types/ViewFilter'; import { ViewFilterOperand } from 'twenty-shared/types'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; @@ -42,7 +42,7 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => { const { applyViewFiltersToCurrentRecordFilters } = useApplyViewFiltersToCurrentRecordFilters(); - const currentFilters = useRecoilComponentValue( + const currentFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -83,7 +83,7 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => { const { applyViewFiltersToCurrentRecordFilters } = useApplyViewFiltersToCurrentRecordFilters(); - const currentFilters = useRecoilComponentValue( + const currentFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewSortsToCurrentRecordSorts.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewSortsToCurrentRecordSorts.test.tsx index ef3bfe416d..5c7d78507d 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewSortsToCurrentRecordSorts.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewSortsToCurrentRecordSorts.test.tsx @@ -1,7 +1,7 @@ import { act, renderHook } from '@testing-library/react'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; @@ -45,7 +45,7 @@ describe('useApplyViewSortsToCurrentRecordSorts', () => { const { applyViewSortsToCurrentRecordSorts } = useApplyViewSortsToCurrentRecordSorts(); - const currentSorts = useRecoilComponentValue( + const currentSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); @@ -80,7 +80,7 @@ describe('useApplyViewSortsToCurrentRecordSorts', () => { const { applyViewSortsToCurrentRecordSorts } = useApplyViewSortsToCurrentRecordSorts(); - const currentSorts = useRecoilComponentValue( + const currentSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx index 6f315f1e3d..e39ebf6dfd 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx @@ -8,7 +8,10 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object- import { useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown } from '@/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; +import { + jotaiStore, + resetJotaiStore, +} from '@/ui/utilities/state/jotai/jotaiStore'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; @@ -17,8 +20,9 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; import { getFilterTypeFromFieldType } from 'twenty-shared/utils'; import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people'; @@ -66,6 +70,7 @@ const wrapper = ({ children }: { children: React.ReactNode }) => { describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () => { beforeEach(() => { + resetJotaiStore(); jest.clearAllMocks(); }); @@ -75,13 +80,14 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () = const { initializeFilterOnFieldMetataItemFromViewBarFilterDropdown } = useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown(); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); - const objectFilterDropdownFilterIsSelected = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + const objectFilterDropdownFilterIsSelected = useRecoilComponentValueV2( objectFilterDropdownFilterIsSelectedComponentState, ); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); @@ -127,13 +133,14 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () = const { initializeFilterOnFieldMetataItemFromViewBarFilterDropdown } = useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown(); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); - const objectFilterDropdownFilterIsSelected = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + const objectFilterDropdownFilterIsSelected = useRecoilComponentValueV2( objectFilterDropdownFilterIsSelectedComponentState, ); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); @@ -188,26 +195,30 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () = const { initializeFilterOnFieldMetataItemFromViewBarFilterDropdown } = useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown(); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); - const objectFilterDropdownFilterIsSelected = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + const objectFilterDropdownFilterIsSelected = useRecoilComponentValueV2( objectFilterDropdownFilterIsSelectedComponentState, ); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( - objectFilterDropdownCurrentRecordFilterComponentState, + const objectFilterDropdownCurrentRecordFilter = + useRecoilComponentValueV2( + objectFilterDropdownCurrentRecordFilterComponentState, + ); + + const setCurrentRecordFilters = useSetRecoilComponentStateV2( + currentRecordFiltersComponentState, + 'test', ); - const setCurrentRecordFilters = useSetRecoilComponentState( - currentRecordFiltersComponentState, - ); - - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'test', ); return { @@ -268,26 +279,30 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () = const { initializeFilterOnFieldMetataItemFromViewBarFilterDropdown } = useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown(); - const fieldMetadataItemUsedInDropdown = useRecoilComponentValue( - fieldMetadataItemUsedInDropdownComponentSelector, - ); - const objectFilterDropdownFilterIsSelected = useRecoilComponentValue( + const fieldMetadataItemUsedInDropdown = + useRecoilComponentSelectorValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + const objectFilterDropdownFilterIsSelected = useRecoilComponentValueV2( objectFilterDropdownFilterIsSelectedComponentState, ); - const selectedOperandInDropdown = useRecoilComponentValue( + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, ); - const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue( - objectFilterDropdownCurrentRecordFilterComponentState, + const objectFilterDropdownCurrentRecordFilter = + useRecoilComponentValueV2( + objectFilterDropdownCurrentRecordFilterComponentState, + ); + + const setCurrentRecordFilters = useSetRecoilComponentStateV2( + currentRecordFiltersComponentState, + 'test', ); - const setCurrentRecordFilters = useSetRecoilComponentState( - currentRecordFiltersComponentState, - ); - - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + 'test', ); return { diff --git a/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts b/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts index 6202092387..570d2e13c6 100644 --- a/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts +++ b/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts @@ -5,7 +5,7 @@ import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetViewGroupsFilters } from '@/views/hooks/useGetViewGroupsFilters'; import { computeRecordGqlOperationFilter, @@ -15,11 +15,11 @@ import { export const useGetRecordIndexTotalCount = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -34,7 +34,7 @@ export const useGetRecordIndexTotalCount = () => { fields: objectMetadataItem.fields, }); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewAnyFieldFilterToAnyFieldFilter.ts b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewAnyFieldFilterToAnyFieldFilter.ts index 89a4ed8da5..872113ee0d 100644 --- a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewAnyFieldFilterToAnyFieldFilter.ts +++ b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewAnyFieldFilterToAnyFieldFilter.ts @@ -1,18 +1,18 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { useStore } from 'jotai'; import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useApplyCurrentViewAnyFieldFilterToAnyFieldFilter = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const setAnyFieldFilterValue = useSetRecoilComponentState( + const setAnyFieldFilterValue = useSetRecoilComponentStateV2( anyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.ts b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.ts index a7f7c574bb..7ef442498b 100644 --- a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.ts +++ b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups.ts @@ -1,64 +1,61 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { mapViewFilterGroupsToRecordFilterGroups } from '@/views/utils/mapViewFilterGroupsToRecordFilterGroups'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const setCurrentRecordFilterGroups = useSetRecoilComponentState( + const setCurrentRecordFilterGroups = useSetRecoilComponentStateV2( currentRecordFilterGroupsComponentState, ); - const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState(currentRecordFilterGroupsComponentState); + const currentRecordFilterGroupsAtom = + useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + ); const store = useStore(); const applyCurrentViewFilterGroupsToCurrentRecordFilterGroups = - useRecoilCallback( - ({ snapshot }) => - () => { - const currentView = store.get( - coreViewFromViewIdFamilySelector.selectorFamily({ - viewId: currentViewId ?? '', - }), - ); + useCallback(() => { + const currentView = store.get( + coreViewFromViewIdFamilySelector.selectorFamily({ + viewId: currentViewId ?? '', + }), + ); - if (isDefined(currentView)) { - const currentRecordFilterGroups = snapshot - .getLoadable(currentRecordFilterGroupsCallbackState) - .getValue(); + if (isDefined(currentView)) { + const currentRecordFilterGroups = store.get( + currentRecordFilterGroupsAtom, + ); - const newRecordFilterGroups = - mapViewFilterGroupsToRecordFilterGroups( - currentView.viewFilterGroups ?? [], - ); + const newRecordFilterGroups = mapViewFilterGroupsToRecordFilterGroups( + currentView.viewFilterGroups ?? [], + ); - if ( - !isDeeplyEqual(currentRecordFilterGroups, newRecordFilterGroups) - ) { - setCurrentRecordFilterGroups(newRecordFilterGroups); - } - } - }, - [ - currentViewId, - setCurrentRecordFilterGroups, - currentRecordFilterGroupsCallbackState, - store, - ], - ); + if ( + !isDeeplyEqual(currentRecordFilterGroups, newRecordFilterGroups) + ) { + setCurrentRecordFilterGroups(newRecordFilterGroups); + } + } + }, [ + currentViewId, + setCurrentRecordFilterGroups, + currentRecordFilterGroupsAtom, + store, + ]); return { applyCurrentViewFilterGroupsToCurrentRecordFilterGroups, diff --git a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters.ts b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters.ts index 03c82e6967..e49dc2e70c 100644 --- a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters.ts @@ -1,7 +1,7 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { useStore } from 'jotai'; import { useCallback } from 'react'; @@ -9,11 +9,11 @@ import { isDefined } from 'twenty-shared/utils'; import { useMapViewFiltersToFilters } from './useMapViewFiltersToFilters'; export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); - const setCurrentRecordFilters = useSetRecoilComponentState( + const setCurrentRecordFilters = useSetRecoilComponentStateV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewSortsToCurrentRecordSorts.ts b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewSortsToCurrentRecordSorts.ts index a9cc847508..dccb231eb7 100644 --- a/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewSortsToCurrentRecordSorts.ts +++ b/packages/twenty-front/src/modules/views/hooks/useApplyCurrentViewSortsToCurrentRecordSorts.ts @@ -1,13 +1,13 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { isDefined } from 'twenty-shared/utils'; export const useApplyCurrentViewSortsToCurrentRecordSorts = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); @@ -16,7 +16,7 @@ export const useApplyCurrentViewSortsToCurrentRecordSorts = () => { { viewId: currentViewId ?? '' }, ); - const setCurrentRecordSorts = useSetRecoilComponentState( + const setCurrentRecordSorts = useSetRecoilComponentStateV2( currentRecordSortsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useApplyViewFiltersToCurrentRecordFilters.ts b/packages/twenty-front/src/modules/views/hooks/useApplyViewFiltersToCurrentRecordFilters.ts index d138069605..ef77243be4 100644 --- a/packages/twenty-front/src/modules/views/hooks/useApplyViewFiltersToCurrentRecordFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useApplyViewFiltersToCurrentRecordFilters.ts @@ -1,10 +1,10 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { type ViewFilter } from '@/views/types/ViewFilter'; import { useMapViewFiltersToFilters } from './useMapViewFiltersToFilters'; export const useApplyViewFiltersToCurrentRecordFilters = () => { - const setCurrentRecordFilters = useSetRecoilComponentState( + const setCurrentRecordFilters = useSetRecoilComponentStateV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useApplyViewSortsToCurrentRecordSorts.ts b/packages/twenty-front/src/modules/views/hooks/useApplyViewSortsToCurrentRecordSorts.ts index 3dbe33946c..56f7597fb0 100644 --- a/packages/twenty-front/src/modules/views/hooks/useApplyViewSortsToCurrentRecordSorts.ts +++ b/packages/twenty-front/src/modules/views/hooks/useApplyViewSortsToCurrentRecordSorts.ts @@ -1,9 +1,9 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential'; export const useApplyViewSortsToCurrentRecordSorts = () => { - const setCurrentRecordSorts = useSetRecoilComponentState( + const setCurrentRecordSorts = useSetRecoilComponentStateV2( currentRecordSortsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useAreViewFilterGroupsDifferentFromRecordFilterGroups.ts b/packages/twenty-front/src/modules/views/hooks/useAreViewFilterGroupsDifferentFromRecordFilterGroups.ts index 032d28b903..01813a2b97 100644 --- a/packages/twenty-front/src/modules/views/hooks/useAreViewFilterGroupsDifferentFromRecordFilterGroups.ts +++ b/packages/twenty-front/src/modules/views/hooks/useAreViewFilterGroupsDifferentFromRecordFilterGroups.ts @@ -1,5 +1,5 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { getViewFilterGroupsToCreate } from '@/views/utils/getViewFilterGroupsToCreate'; import { getViewFilterGroupsToDelete } from '@/views/utils/getViewFilterGroupsToDelete'; @@ -10,7 +10,7 @@ import { isDefined } from 'twenty-shared/utils'; export const useAreViewFilterGroupsDifferentFromRecordFilterGroups = () => { const { currentView } = useGetCurrentViewOnly(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useAreViewFiltersDifferentFromRecordFilters.ts b/packages/twenty-front/src/modules/views/hooks/useAreViewFiltersDifferentFromRecordFilters.ts index d0b9827fd7..a90d6cdee9 100644 --- a/packages/twenty-front/src/modules/views/hooks/useAreViewFiltersDifferentFromRecordFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useAreViewFiltersDifferentFromRecordFilters.ts @@ -1,5 +1,5 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { getViewFiltersToCreate } from '@/views/utils/getViewFiltersToCreate'; import { getViewFiltersToDelete } from '@/views/utils/getViewFiltersToDelete'; @@ -9,7 +9,7 @@ import { useMemo } from 'react'; export const useAreViewFiltersDifferentFromRecordFilters = () => { const { currentView } = useGetCurrentViewOnly(); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts b/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts index 9e5c7d2cae..4ceaf92150 100644 --- a/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts +++ b/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts @@ -1,5 +1,5 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { getViewSortsToCreate } from '@/views/utils/getViewSortsToCreate'; import { getViewSortsToDelete } from '@/views/utils/getViewSortsToDelete'; @@ -10,7 +10,7 @@ import { isDefined } from 'twenty-shared/utils'; export const useAreViewSortsDifferentFromRecordSorts = () => { const { currentView } = useGetCurrentViewOnly(); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts index 4d23d3c39f..51f791a4e3 100644 --- a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts @@ -4,9 +4,8 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { usePerformViewAPIPersist } from '@/views/hooks/internal/usePerformViewAPIPersist'; import { usePerformViewFieldAPIPersist } from '@/views/hooks/internal/usePerformViewFieldAPIPersist'; import { usePerformViewFilterAPIPersist } from '@/views/hooks/internal/usePerformViewFilterAPIPersist'; @@ -23,7 +22,7 @@ import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFi import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter'; import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { ViewCalendarLayout } from '~/generated-metadata/graphql'; @@ -32,13 +31,16 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { const { performViewAPICreate } = usePerformViewAPIPersist(); - const currentViewIdCallbackState = useRecoilComponentCallbackState( + const { objectMetadataItem, recordIndexId } = useRecordIndexContextOrThrow(); + + const currentViewIdAtom = useRecoilComponentStateCallbackStateV2( contextStoreCurrentViewIdComponentState, viewBarComponentId, ); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, + recordIndexId, ); const { performViewFieldAPICreate } = usePerformViewFieldAPIPersist(); @@ -50,196 +52,193 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { const { performViewFilterGroupAPICreate } = usePerformViewFilterGroupAPIPersist(); - const { objectMetadataItem } = useRecordIndexContextOrThrow(); - const store = useStore(); const { refreshCoreViewsByObjectMetadataId } = useRefreshCoreViewsByObjectMetadataId(); - const currentRecordFilterGroups = useRecoilComponentValue( + const currentRecordFilterGroups = useRecoilComponentValueV2( currentRecordFilterGroupsComponentState, + recordIndexId, ); - const currentRecordSorts = useRecoilComponentValue( + const currentRecordSorts = useRecoilComponentValueV2( currentRecordSortsComponentState, + recordIndexId, ); - const currentRecordFilters = useRecoilComponentValue( + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, + recordIndexId, ); - const createViewFromCurrentView = useRecoilCallback( - ({ snapshot }) => - async ( + const createViewFromCurrentView = useCallback( + async ( + { + id, + name, + icon, + mainGroupByFieldMetadataId, + calendarFieldMetadataId, + type, + visibility, + }: Partial< + Pick< + GraphQLView, + | 'id' + | 'name' + | 'icon' + | 'mainGroupByFieldMetadataId' + | 'calendarFieldMetadataId' + | 'type' + | 'visibility' + > + >, + shouldCopyFiltersAndSortsAndAggregate?: boolean, + ): Promise => { + const currentViewId = store.get(currentViewIdAtom); + + if (!isDefined(currentViewId)) { + return undefined; + } + + const sourceView = store.get( + coreViewFromViewIdFamilySelector.selectorFamily({ + viewId: currentViewId, + }), + ); + + if (!isDefined(sourceView)) { + return undefined; + } + + const viewType = type ?? sourceView.type; + + const result = await performViewAPICreate( { - id, - name, - icon, - mainGroupByFieldMetadataId, - calendarFieldMetadataId, - type, - visibility, - }: Partial< - Pick< - GraphQLView, - | 'id' - | 'name' - | 'icon' - | 'mainGroupByFieldMetadataId' - | 'calendarFieldMetadataId' - | 'type' - | 'visibility' - > - >, - shouldCopyFiltersAndSortsAndAggregate?: boolean, - ): Promise => { - const currentViewId = getSnapshotValue( - snapshot, - currentViewIdCallbackState, + input: { + id: id ?? v4(), + name: name ?? sourceView.name, + icon: icon ?? sourceView.icon, + key: null, + kanbanAggregateOperation: shouldCopyFiltersAndSortsAndAggregate + ? sourceView.kanbanAggregateOperation + : undefined, + kanbanAggregateOperationFieldMetadataId: + shouldCopyFiltersAndSortsAndAggregate + ? sourceView.kanbanAggregateOperationFieldMetadataId + : undefined, + mainGroupByFieldMetadataId: shouldCopyFiltersAndSortsAndAggregate + ? sourceView.mainGroupByFieldMetadataId + : mainGroupByFieldMetadataId, + type: convertViewTypeToCore(viewType), + objectMetadataId: sourceView.objectMetadataId, + openRecordIn: convertViewOpenRecordInToCore( + sourceView.openRecordIn, + ), + anyFieldFilterValue: anyFieldFilterValue, + calendarLayout: + viewType === ViewType.Calendar + ? ViewCalendarLayout.MONTH + : undefined, + calendarFieldMetadataId: + viewType === ViewType.Calendar + ? calendarFieldMetadataId + : undefined, + visibility, + }, + }, + objectMetadataItem.id, + ); + + if (result.status === 'failed') { + return undefined; + } + + const newViewId = result.response.data?.createCoreView.id; + + if (isUndefinedOrNull(newViewId)) { + throw new Error('Failed to create view'); + } + + const fieldResult = await performViewFieldAPICreate({ + inputs: sourceView.viewFields.map( + ({ __typename, id: _id, ...viewField }) => ({ + ...viewField, + id: v4(), + viewId: newViewId, + }), + ), + }); + + if (fieldResult.status === 'failed') { + return undefined; + } + + if (shouldCopyFiltersAndSortsAndAggregate === true) { + const viewFilterGroupsToCopy = currentRecordFilterGroups.map( + (recordFilterGroup) => + mapRecordFilterGroupToViewFilterGroup({ + recordFilterGroup, + view: { id: newViewId }, + }), ); - if (!isDefined(currentViewId)) { - return undefined; - } + const viewFiltersToCopy = currentRecordFilters.map( + mapRecordFilterToViewFilter, + ); - const sourceView = store.get( - coreViewFromViewIdFamilySelector.selectorFamily({ - viewId: currentViewId, + const { + duplicatedViewFilterGroups: viewFilterGroupsToCreate, + duplicatedViewFilters: viewFiltersToCreate, + } = duplicateViewFiltersAndViewFilterGroups({ + viewFilterGroupsToDuplicate: viewFilterGroupsToCopy, + viewFiltersToDuplicate: viewFiltersToCopy, + }); + + const viewSortsToCreate = currentRecordSorts + .map((recordSort) => mapRecordSortToViewSort(recordSort, newViewId)) + .map((viewSort) => ({ + ...viewSort, + id: v4(), + })); + + await performViewFilterGroupAPICreate(viewFilterGroupsToCreate, { + id: newViewId, + }); + + const createViewFilterInputs = viewFiltersToCreate.map( + (viewFilter) => ({ + input: { + id: viewFilter.id, + fieldMetadataId: viewFilter.fieldMetadataId, + viewId: newViewId, + value: viewFilter.value, + operand: viewFilter.operand, + viewFilterGroupId: viewFilter.viewFilterGroupId, + positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, + subFieldName: viewFilter.subFieldName ?? null, + }, }), ); - if (!isDefined(sourceView)) { - return undefined; - } - - const viewType = type ?? sourceView.type; - - const result = await performViewAPICreate( - { - input: { - id: id ?? v4(), - name: name ?? sourceView.name, - icon: icon ?? sourceView.icon, - key: null, - kanbanAggregateOperation: shouldCopyFiltersAndSortsAndAggregate - ? sourceView.kanbanAggregateOperation - : undefined, - kanbanAggregateOperationFieldMetadataId: - shouldCopyFiltersAndSortsAndAggregate - ? sourceView.kanbanAggregateOperationFieldMetadataId - : undefined, - mainGroupByFieldMetadataId: shouldCopyFiltersAndSortsAndAggregate - ? sourceView.mainGroupByFieldMetadataId - : mainGroupByFieldMetadataId, - type: convertViewTypeToCore(viewType), - objectMetadataId: sourceView.objectMetadataId, - openRecordIn: convertViewOpenRecordInToCore( - sourceView.openRecordIn, - ), - anyFieldFilterValue: anyFieldFilterValue, - calendarLayout: - viewType === ViewType.Calendar - ? ViewCalendarLayout.MONTH - : undefined, - calendarFieldMetadataId: - viewType === ViewType.Calendar - ? calendarFieldMetadataId - : undefined, - visibility, - }, - }, - objectMetadataItem.id, + const filterResult = await performViewFilterAPICreate( + createViewFilterInputs, ); - if (result.status === 'failed') { + if (filterResult.status === 'failed') { return undefined; } - const newViewId = result.response.data?.createCoreView.id; + await performViewSortAPICreate(viewSortsToCreate, { id: newViewId }); + } - if (isUndefinedOrNull(newViewId)) { - throw new Error('Failed to create view'); - } + await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); - const fieldResult = await performViewFieldAPICreate({ - inputs: sourceView.viewFields.map( - ({ __typename, id: _id, ...viewField }) => ({ - ...viewField, - id: v4(), - viewId: newViewId, - }), - ), - }); - - if (fieldResult.status === 'failed') { - return undefined; - } - - if (shouldCopyFiltersAndSortsAndAggregate === true) { - const viewFilterGroupsToCopy = currentRecordFilterGroups.map( - (recordFilterGroup) => - mapRecordFilterGroupToViewFilterGroup({ - recordFilterGroup, - view: { id: newViewId }, - }), - ); - - const viewFiltersToCopy = currentRecordFilters.map( - mapRecordFilterToViewFilter, - ); - - const { - duplicatedViewFilterGroups: viewFilterGroupsToCreate, - duplicatedViewFilters: viewFiltersToCreate, - } = duplicateViewFiltersAndViewFilterGroups({ - viewFilterGroupsToDuplicate: viewFilterGroupsToCopy, - viewFiltersToDuplicate: viewFiltersToCopy, - }); - - const viewSortsToCreate = currentRecordSorts - .map((recordSort) => mapRecordSortToViewSort(recordSort, newViewId)) - .map((viewSort) => ({ - ...viewSort, - id: v4(), - })); - - await performViewFilterGroupAPICreate(viewFilterGroupsToCreate, { - id: newViewId, - }); - - const createViewFilterInputs = viewFiltersToCreate.map( - (viewFilter) => ({ - input: { - id: viewFilter.id, - fieldMetadataId: viewFilter.fieldMetadataId, - viewId: newViewId, - value: viewFilter.value, - operand: viewFilter.operand, - viewFilterGroupId: viewFilter.viewFilterGroupId, - positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, - subFieldName: viewFilter.subFieldName ?? null, - }, - }), - ); - - const filterResult = await performViewFilterAPICreate( - createViewFilterInputs, - ); - - if (filterResult.status === 'failed') { - return undefined; - } - - await performViewSortAPICreate(viewSortsToCreate, { id: newViewId }); - } - - await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); - - return newViewId; - }, + return newViewId; + }, [ - currentViewIdCallbackState, + currentViewIdAtom, performViewAPICreate, anyFieldFilterValue, objectMetadataItem, diff --git a/packages/twenty-front/src/modules/views/hooks/useGetCurrentViewOnly.ts b/packages/twenty-front/src/modules/views/hooks/useGetCurrentViewOnly.ts index cf7d92d556..f0f62120f8 100644 --- a/packages/twenty-front/src/modules/views/hooks/useGetCurrentViewOnly.ts +++ b/packages/twenty-front/src/modules/views/hooks/useGetCurrentViewOnly.ts @@ -1,10 +1,10 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; export const useGetCurrentViewOnly = () => { - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useInitViewBar.ts b/packages/twenty-front/src/modules/views/hooks/useInitViewBar.ts index 4833e2b89f..c3158ee2c7 100644 --- a/packages/twenty-front/src/modules/views/hooks/useInitViewBar.ts +++ b/packages/twenty-front/src/modules/views/hooks/useInitViewBar.ts @@ -1,14 +1,14 @@ -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { availableFieldDefinitionsComponentState } from '@/views/states/availableFieldDefinitionsComponentState'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; export const useInitViewBar = (viewBarInstanceId?: string) => { - const setAvailableFieldDefinitions = useSetRecoilComponentState( + const setAvailableFieldDefinitions = useSetRecoilComponentStateV2( availableFieldDefinitionsComponentState, viewBarInstanceId, ); - const setViewObjectMetadataId = useSetRecoilComponentState( + const setViewObjectMetadataId = useSetRecoilComponentStateV2( viewObjectMetadataIdComponentState, viewBarInstanceId, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts b/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts index 35725b2313..0f931fb5ef 100644 --- a/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts +++ b/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts @@ -12,34 +12,38 @@ import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-re import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown = () => { const selectedOperandInDropdownCallbackState = - useRecoilComponentCallbackState(selectedOperandInDropdownComponentState); + useRecoilComponentStateCallbackStateV2( + selectedOperandInDropdownComponentState, + ); - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( - currentRecordFiltersComponentState, - ); + const currentRecordFiltersCallbackState = + useRecoilComponentStateCallbackStateV2( + currentRecordFiltersComponentState, + ); const objectFilterDropdownCurrentRecordFilterCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( objectFilterDropdownCurrentRecordFilterComponentState, ); const fieldMetadataItemUsedInDropdownCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( fieldMetadataItemIdUsedInDropdownComponentState, ); const objectFilterDropdownFilterIsSelectedCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( objectFilterDropdownFilterIsSelectedComponentState, ); @@ -49,93 +53,91 @@ export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown = const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack(); const { getInitialFilterValue } = useGetInitialFilterValue(); + const store = useStore(); + const initializeFilterOnFieldMetataItemFromViewBarFilterDropdown = - useRecoilCallback( - ({ set, snapshot }) => - (fieldMetadataItem: FieldMetadataItem) => { - set( - fieldMetadataItemUsedInDropdownCallbackState, - fieldMetadataItem.id, - ); + useCallback( + (fieldMetadataItem: FieldMetadataItem) => { + store.set( + fieldMetadataItemUsedInDropdownCallbackState, + fieldMetadataItem.id, + ); - const currentRecordFilters = snapshot - .getLoadable(currentRecordFiltersCallbackState) - .getValue(); + const currentRecordFilters = store.get( + currentRecordFiltersCallbackState, + ); - const filterType = getFilterTypeFromFieldType( - fieldMetadataItem.type, - ); + const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type); - if (filterType === 'RELATION' || filterType === 'SELECT') { - pushFocusItemToFocusStack({ - focusId: ViewBarFilterDropdownIds.MAIN, - component: { - type: FocusComponentType.DROPDOWN, - instanceId: fieldMetadataItem.id, - }, - globalHotkeysConfig: { - enableGlobalHotkeysConflictingWithKeyboard: false, - }, - }); - } + if (filterType === 'RELATION' || filterType === 'SELECT') { + pushFocusItemToFocusStack({ + focusId: ViewBarFilterDropdownIds.MAIN, + component: { + type: FocusComponentType.DROPDOWN, + instanceId: fieldMetadataItem.id, + }, + globalHotkeysConfig: { + enableGlobalHotkeysConflictingWithKeyboard: false, + }, + }); + } - set(objectFilterDropdownFilterIsSelectedCallbackState, true); + store.set(objectFilterDropdownFilterIsSelectedCallbackState, true); - const defaultOperand = getRecordFilterOperands({ - filterType, - })[0]; + const defaultOperand = getRecordFilterOperands({ + filterType, + })[0]; - const duplicateFilterInCurrentRecordFilters = - findDuplicateRecordFilterInNonAdvancedRecordFilters({ - recordFilters: currentRecordFilters, - fieldMetadataItemId: fieldMetadataItem.id, - }); + const duplicateFilterInCurrentRecordFilters = + findDuplicateRecordFilterInNonAdvancedRecordFilters({ + recordFilters: currentRecordFilters, + fieldMetadataItemId: fieldMetadataItem.id, + }); - const filterIsAlreadyInCurrentRecordFilters = isDefined( + const filterIsAlreadyInCurrentRecordFilters = isDefined( + duplicateFilterInCurrentRecordFilters, + ); + + if (filterIsAlreadyInCurrentRecordFilters) { + store.set( + objectFilterDropdownCurrentRecordFilterCallbackState, duplicateFilterInCurrentRecordFilters, ); - if (filterIsAlreadyInCurrentRecordFilters) { - set( + store.set( + selectedOperandInDropdownCallbackState, + duplicateFilterInCurrentRecordFilters.operand, + ); + } else { + store.set(selectedOperandInDropdownCallbackState, defaultOperand); + + if (filterType === 'DATE' || filterType === 'DATE_TIME') { + const { displayValue, value } = getInitialFilterValue( + filterType, + defaultOperand, + ); + + const initialDateRecordFilter: RecordFilter = { + id: v4(), + fieldMetadataId: fieldMetadataItem.id, + operand: defaultOperand, + displayValue, + label: fieldMetadataItem.label, + type: filterType, + value, + }; + + upsertObjectFilterDropdownCurrentFilter(initialDateRecordFilter); + + store.set( objectFilterDropdownCurrentRecordFilterCallbackState, - duplicateFilterInCurrentRecordFilters, + initialDateRecordFilter, ); - - set( - selectedOperandInDropdownCallbackState, - duplicateFilterInCurrentRecordFilters.operand, - ); - } else { - set(selectedOperandInDropdownCallbackState, defaultOperand); - - if (filterType === 'DATE' || filterType === 'DATE_TIME') { - const { displayValue, value } = getInitialFilterValue( - filterType, - defaultOperand, - ); - - const initialDateRecordFilter: RecordFilter = { - id: v4(), - fieldMetadataId: fieldMetadataItem.id, - operand: defaultOperand, - displayValue, - label: fieldMetadataItem.label, - type: filterType, - value, - }; - - upsertObjectFilterDropdownCurrentFilter( - initialDateRecordFilter, - ); - - set( - objectFilterDropdownCurrentRecordFilterCallbackState, - initialDateRecordFilter, - ); - } } - }, + } + }, [ + store, fieldMetadataItemUsedInDropdownCallbackState, currentRecordFiltersCallbackState, objectFilterDropdownFilterIsSelectedCallbackState, diff --git a/packages/twenty-front/src/modules/views/hooks/useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter.ts b/packages/twenty-front/src/modules/views/hooks/useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter.ts index d71b6c0a5c..8a6545f6d8 100644 --- a/packages/twenty-front/src/modules/views/hooks/useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter.ts +++ b/packages/twenty-front/src/modules/views/hooks/useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter.ts @@ -1,12 +1,12 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { isNonEmptyString } from '@sniptt/guards'; import { compareNonEmptyStrings } from '~/utils/compareNonEmptyStrings'; export const useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter = () => { const { currentView } = useGetCurrentViewOnly(); - const anyFieldFilterValue = useRecoilComponentValue( + const anyFieldFilterValue = useRecoilComponentValueV2( anyFieldFilterValueComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useOpenAnyFieldSearchFilterFromViewBar.ts b/packages/twenty-front/src/modules/views/hooks/useOpenAnyFieldSearchFilterFromViewBar.ts index 02e07b0bce..849b8cb98f 100644 --- a/packages/twenty-front/src/modules/views/hooks/useOpenAnyFieldSearchFilterFromViewBar.ts +++ b/packages/twenty-front/src/modules/views/hooks/useOpenAnyFieldSearchFilterFromViewBar.ts @@ -2,24 +2,24 @@ import { objectFilterDropdownAnyFieldSearchIsSelectedComponentState } from '@/ob import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { t } from '@lingui/core/macro'; import { isNonEmptyString } from '@sniptt/guards'; export const useOpenAnyFieldSearchFilterFromViewBar = () => { - const setAnyFieldFilterValue = useSetRecoilComponentState( + const setAnyFieldFilterValue = useSetRecoilComponentStateV2( anyFieldFilterValueComponentState, ); const { objectMetadataItem } = useRecordIndexContextOrThrow(); const setObjectFilterDropdownAnyFieldSearchIsSelectedComponentState = - useSetRecoilComponentState( + useSetRecoilComponentStateV2( objectFilterDropdownAnyFieldSearchIsSelectedComponentState, ); - const objectFilterDropdownSearchInput = useRecoilComponentValue( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useOpenCreateViewDropown.ts b/packages/twenty-front/src/modules/views/hooks/useOpenCreateViewDropown.ts index 7c3c672dfc..77475879d1 100644 --- a/packages/twenty-front/src/modules/views/hooks/useOpenCreateViewDropown.ts +++ b/packages/twenty-front/src/modules/views/hooks/useOpenCreateViewDropown.ts @@ -1,5 +1,5 @@ import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { type View } from '@/views/types/View'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode'; @@ -8,7 +8,7 @@ import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/sta import { isDefined } from 'twenty-shared/utils'; export const useOpenCreateViewDropdown = (viewBardId?: string) => { - const setViewPickerReferenceViewId = useSetRecoilComponentState( + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, viewBardId, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useQueryVariablesFromParentView.ts b/packages/twenty-front/src/modules/views/hooks/useQueryVariablesFromParentView.ts index b4916b71e5..32aabd23b3 100644 --- a/packages/twenty-front/src/modules/views/hooks/useQueryVariablesFromParentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useQueryVariablesFromParentView.ts @@ -3,7 +3,7 @@ import { contextStoreRecordShowParentViewComponentState } from '@/context-store/ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { getQueryVariablesFromFiltersAndSorts } from '@/views/utils/getQueryVariablesFromFiltersAndSorts'; export const useQueryVariablesFromParentView = ({ @@ -13,7 +13,7 @@ export const useQueryVariablesFromParentView = ({ }) => { const { objectMetadataItems } = useObjectMetadataItems(); - const recordShowParentView = useRecoilComponentValue( + const recordShowParentView = useRecoilComponentValueV2( contextStoreRecordShowParentViewComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts b/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts index ab610bcd67..1e1c0045a1 100644 --- a/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts +++ b/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts @@ -11,7 +11,7 @@ import { getFilterableFields } from '@/views/utils/getFilterableFields'; import { mapViewFieldToRecordField } from '@/views/utils/mapViewFieldToRecordField'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils'; import { useFindManyCoreViewsLazyQuery } from '~/generated-metadata/graphql'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -19,142 +19,135 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useRefreshCoreViewsByObjectMetadataId = () => { const [findManyCoreViewsLazy] = useFindManyCoreViewsLazyQuery(); - const refreshCoreViewsByObjectMetadataId = useRecoilCallback( - ({ set }) => - async (objectMetadataId: string) => { - const result = await findManyCoreViewsLazy({ - variables: { - objectMetadataId, - }, - fetchPolicy: 'network-only', - }); + const refreshCoreViewsByObjectMetadataId = useCallback( + async (objectMetadataId: string) => { + const result = await findManyCoreViewsLazy({ + variables: { + objectMetadataId, + }, + fetchPolicy: 'network-only', + }); - if (!isDefined(result.data?.getCoreViews)) { - return; + if (!isDefined(result.data?.getCoreViews)) { + return; + } + + const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); + + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => objectMetadataItem.id === objectMetadataId, + ); + + if (!isDefined(objectMetadataItem)) { + return; + } + + const coreViewsForObjectMetadataId = jotaiStore.get( + coreViewsByObjectMetadataIdFamilySelector.selectorFamily( + objectMetadataId, + ), + ); + + const coreViewsFromResult = result.data.getCoreViews; + + if (isDeeplyEqual(coreViewsForObjectMetadataId, coreViewsFromResult)) { + return; + } + + jotaiStore.set( + coreViewsByObjectMetadataIdFamilySelector.selectorFamily( + objectMetadataId, + ), + coreViewsFromResult, + ); + + for (const coreView of coreViewsFromResult) { + const existingView = coreViewsForObjectMetadataId.find( + (coreViewForObjectMetadata) => + coreViewForObjectMetadata.id === coreView.id, + ); + + if (!isDefined(existingView)) { + continue; } - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); - - const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => objectMetadataItem.id === objectMetadataId, - ); - - if (!isDefined(objectMetadataItem)) { - return; - } - - const coreViewsForObjectMetadataId = jotaiStore.get( - coreViewsByObjectMetadataIdFamilySelector.selectorFamily( - objectMetadataId, - ), - ); - - const coreViewsFromResult = result.data.getCoreViews; - - if (isDeeplyEqual(coreViewsForObjectMetadataId, coreViewsFromResult)) { - return; - } - - jotaiStore.set( - coreViewsByObjectMetadataIdFamilySelector.selectorFamily( - objectMetadataId, - ), - coreViewsFromResult, - ); - - for (const coreView of coreViewsFromResult) { - const existingView = coreViewsForObjectMetadataId.find( - (coreViewForObjectMetadata) => - coreViewForObjectMetadata.id === coreView.id, + if ( + !isDeeplyEqual( + coreView.viewFields.map((viewField) => + removePropertiesFromRecord(viewField, ['updatedAt', 'createdAt']), + ), + existingView.viewFields, + ) + ) { + const view = convertCoreViewToView(coreView); + jotaiStore.set( + currentRecordFieldsComponentState.atomFamily({ + instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + view.id, + ), + }), + view.viewFields + .filter(isDefined) + .map((viewField) => mapViewFieldToRecordField(viewField)), ); - - if (!isDefined(existingView)) { - continue; - } - - if ( - !isDeeplyEqual( - coreView.viewFields.map((viewField) => - removePropertiesFromRecord(viewField, [ - 'updatedAt', - 'createdAt', - ]), - ), - existingView.viewFields, - ) - ) { - const view = convertCoreViewToView(coreView); - set( - currentRecordFieldsComponentState.atomFamily({ - instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( - objectMetadataItem.namePlural, - view.id, - ), - }), - view.viewFields - .filter(isDefined) - .map((viewField) => mapViewFieldToRecordField(viewField)), - ); - } - - if ( - !isDeeplyEqual( - coreView.viewFilters.map((viewFilter) => - removePropertiesFromRecord(viewFilter, [ - 'createdAt', - 'updatedAt', - ]), - ), - existingView.viewFilters, - ) - ) { - const view = convertCoreViewToView(coreView); - set( - currentRecordFiltersComponentState.atomFamily({ - instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( - objectMetadataItem.namePlural, - view.id, - ), - }), - mapViewFiltersToFilters( - view.viewFilters, - getFilterableFields(objectMetadataItem), - ), - ); - } - - if (!isDeeplyEqual(coreView.viewSorts, existingView.viewSorts)) { - const view = convertCoreViewToView(coreView); - set( - currentRecordSortsComponentState.atomFamily({ - instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( - objectMetadataItem.namePlural, - view.id, - ), - }), - view.viewSorts, - ); - } - - if ( - coreView.shouldHideEmptyGroups !== - existingView.shouldHideEmptyGroups - ) { - const view = convertCoreViewToView(coreView); - set( - recordIndexShouldHideEmptyRecordGroupsComponentState.atomFamily({ - instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( - objectMetadataItem.namePlural, - view.id, - ), - }), - view.shouldHideEmptyGroups, - ); - } } - }, + + if ( + !isDeeplyEqual( + coreView.viewFilters.map((viewFilter) => + removePropertiesFromRecord(viewFilter, [ + 'createdAt', + 'updatedAt', + ]), + ), + existingView.viewFilters, + ) + ) { + const view = convertCoreViewToView(coreView); + jotaiStore.set( + currentRecordFiltersComponentState.atomFamily({ + instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + view.id, + ), + }), + mapViewFiltersToFilters( + view.viewFilters, + getFilterableFields(objectMetadataItem), + ), + ); + } + + if (!isDeeplyEqual(coreView.viewSorts, existingView.viewSorts)) { + const view = convertCoreViewToView(coreView); + jotaiStore.set( + currentRecordSortsComponentState.atomFamily({ + instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + view.id, + ), + }), + view.viewSorts, + ); + } + + if ( + coreView.shouldHideEmptyGroups !== existingView.shouldHideEmptyGroups + ) { + const view = convertCoreViewToView(coreView); + jotaiStore.set( + recordIndexShouldHideEmptyRecordGroupsComponentState.atomFamily({ + instanceId: getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + view.id, + ), + }), + view.shouldHideEmptyGroups, + ); + } + } + }, [findManyCoreViewsLazy], ); diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveAnyFieldFilterToView.ts b/packages/twenty-front/src/modules/views/hooks/useSaveAnyFieldFilterToView.ts index 981e25a8a2..e5e252a5d8 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveAnyFieldFilterToView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveAnyFieldFilterToView.ts @@ -1,10 +1,11 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useSaveAnyFieldFilterToView = () => { @@ -13,40 +14,38 @@ export const useSaveAnyFieldFilterToView = () => { const { currentView } = useGetCurrentViewOnly(); - const anyFieldFilterValueCallbackState = useRecoilComponentCallbackState( - anyFieldFilterValueComponentState, - ); + const anyFieldFilterValueCallbackState = + useRecoilComponentStateCallbackStateV2(anyFieldFilterValueComponentState); - const saveAnyFieldFilterToView = useRecoilCallback( - ({ snapshot }) => - async () => { - if (!canPersistChanges || !isDefined(currentView)) { - return; - } + const store = useStore(); - const currentViewAnyFieldFilterValue = currentView.anyFieldFilterValue; + const saveAnyFieldFilterToView = useCallback(async () => { + if (!canPersistChanges || !isDefined(currentView)) { + return; + } - const currentAnyFieldFilterValue = snapshot - .getLoadable(anyFieldFilterValueCallbackState) - .getValue(); + const currentViewAnyFieldFilterValue = currentView.anyFieldFilterValue; - if (currentAnyFieldFilterValue !== currentViewAnyFieldFilterValue) { - await performViewAPIUpdate({ - id: currentView.id, - input: convertUpdateViewInputToCore({ - ...currentView, - anyFieldFilterValue: currentAnyFieldFilterValue, - }), - }); - } - }, - [ - canPersistChanges, - performViewAPIUpdate, + const currentAnyFieldFilterValue = store.get( anyFieldFilterValueCallbackState, - currentView, - ], - ); + ); + + if (currentAnyFieldFilterValue !== currentViewAnyFieldFilterValue) { + await performViewAPIUpdate({ + id: currentView.id, + input: convertUpdateViewInputToCore({ + ...currentView, + anyFieldFilterValue: currentAnyFieldFilterValue, + }), + }); + } + }, [ + store, + canPersistChanges, + performViewAPIUpdate, + anyFieldFilterValueCallbackState, + currentView, + ]); return { saveAnyFieldFilterToView, diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFields.ts b/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFields.ts index cf2a5bc591..513384bcba 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFields.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFields.ts @@ -1,7 +1,8 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewFieldAPIPersist } from '@/views/hooks/internal/usePerformViewFieldAPIPersist'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState'; @@ -20,115 +21,115 @@ export const useSaveCurrentViewFields = () => { const { getViewFromPrefetchState } = useGetViewFromPrefetchState(); - const currentViewIdCallbackState = useRecoilComponentCallbackState( + const currentViewIdCallbackState = useRecoilComponentStateCallbackStateV2( contextStoreCurrentViewIdComponentState, ); - const saveViewFields = useRecoilCallback( - ({ snapshot }) => - async (viewFieldsToSave: Omit[]) => { - if (!canPersistChanges) { - return; - } + const store = useStore(); - const currentViewId = snapshot - .getLoadable(currentViewIdCallbackState) - .getValue(); + const saveViewFields = useCallback( + async (viewFieldsToSave: Omit[]) => { + if (!canPersistChanges) { + return; + } - if (!currentViewId) { - return; - } + const currentViewId = store.get(currentViewIdCallbackState); - const view = getViewFromPrefetchState(currentViewId); + if (!currentViewId) { + return; + } - if (isUndefinedOrNull(view)) { - return; - } + const view = getViewFromPrefetchState(currentViewId); - const currentViewFields = view.viewFields; + if (isUndefinedOrNull(view)) { + return; + } - const { viewFieldsToCreate, viewFieldsToUpdate } = - viewFieldsToSave.reduce<{ - viewFieldsToCreate: CreateViewFieldInput[]; - viewFieldsToUpdate: UpdateCoreViewFieldMutationVariables[]; - }>( - ( - { viewFieldsToCreate, viewFieldsToUpdate }, - { __typename, ...viewFieldToCreateOrUpdate }, - ) => { - const createViewFieldInput: CreateViewFieldInput = { - ...viewFieldToCreateOrUpdate, - viewId: currentViewId, + const currentViewFields = view.viewFields; + + const { viewFieldsToCreate, viewFieldsToUpdate } = + viewFieldsToSave.reduce<{ + viewFieldsToCreate: CreateViewFieldInput[]; + viewFieldsToUpdate: UpdateCoreViewFieldMutationVariables[]; + }>( + ( + { viewFieldsToCreate, viewFieldsToUpdate }, + { __typename, ...viewFieldToCreateOrUpdate }, + ) => { + const createViewFieldInput: CreateViewFieldInput = { + ...viewFieldToCreateOrUpdate, + viewId: currentViewId, + }; + const existingField = currentViewFields.find( + (currentViewField) => + currentViewField.fieldMetadataId === + createViewFieldInput.fieldMetadataId, + ); + + if (isUndefinedOrNull(existingField)) { + return { + viewFieldsToCreate: [ + ...viewFieldsToCreate, + createViewFieldInput, + ], + viewFieldsToUpdate, }; - const existingField = currentViewFields.find( - (currentViewField) => - currentViewField.fieldMetadataId === - createViewFieldInput.fieldMetadataId, - ); - - if (isUndefinedOrNull(existingField)) { - return { - viewFieldsToCreate: [ - ...viewFieldsToCreate, - createViewFieldInput, - ], - viewFieldsToUpdate, - }; - } - - if ( - isDeeplyEqual( - { - position: existingField.position, - size: existingField.size, - isVisible: existingField.isVisible, - aggregateOperation: existingField.aggregateOperation, - }, - { - position: createViewFieldInput.position, - size: createViewFieldInput.size, - isVisible: createViewFieldInput.isVisible, - aggregateOperation: createViewFieldInput.aggregateOperation, - }, - ) - ) { - return { - viewFieldsToCreate, - viewFieldsToUpdate, - }; - } + } + if ( + isDeeplyEqual( + { + position: existingField.position, + size: existingField.size, + isVisible: existingField.isVisible, + aggregateOperation: existingField.aggregateOperation, + }, + { + position: createViewFieldInput.position, + size: createViewFieldInput.size, + isVisible: createViewFieldInput.isVisible, + aggregateOperation: createViewFieldInput.aggregateOperation, + }, + ) + ) { return { viewFieldsToCreate, - viewFieldsToUpdate: [ - ...viewFieldsToUpdate, - { - input: { - id: existingField.id, - update: { - aggregateOperation: - createViewFieldInput.aggregateOperation, - isVisible: createViewFieldInput.isVisible, - position: createViewFieldInput.position, - size: createViewFieldInput.size, - }, + viewFieldsToUpdate, + }; + } + + return { + viewFieldsToCreate, + viewFieldsToUpdate: [ + ...viewFieldsToUpdate, + { + input: { + id: existingField.id, + update: { + aggregateOperation: + createViewFieldInput.aggregateOperation, + isVisible: createViewFieldInput.isVisible, + position: createViewFieldInput.position, + size: createViewFieldInput.size, }, }, - ], - }; - }, - { - viewFieldsToUpdate: [], - viewFieldsToCreate: [], - }, - ); + }, + ], + }; + }, + { + viewFieldsToUpdate: [], + viewFieldsToCreate: [], + }, + ); - await Promise.all([ - performViewFieldAPICreate({ inputs: viewFieldsToCreate }), - performViewFieldAPIUpdate(viewFieldsToUpdate), - ]); - }, + await Promise.all([ + performViewFieldAPICreate({ inputs: viewFieldsToCreate }), + performViewFieldAPIUpdate(viewFieldsToUpdate), + ]); + }, [ + store, canPersistChanges, performViewFieldAPICreate, currentViewIdCallbackState, diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewGroups.ts b/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewGroups.ts index 28668cf005..3186181e07 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewGroups.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewGroups.ts @@ -1,7 +1,8 @@ -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewGroupAPIPersist } from '@/views/hooks/internal/usePerformViewGroupAPIPersist'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState'; @@ -16,59 +17,125 @@ export const useSaveCurrentViewGroups = () => { const { getViewFromPrefetchState } = useGetViewFromPrefetchState(); - const currentViewIdCallbackState = useRecoilComponentCallbackState( + const currentViewIdCallbackState = useRecoilComponentStateCallbackStateV2( contextStoreCurrentViewIdComponentState, ); - const saveViewGroup = useRecoilCallback( - ({ snapshot }) => - async (viewGroupToSave: ViewGroup) => { - if (!canPersistChanges) { - return; - } + const store = useStore(); - const currentViewId = snapshot - .getLoadable(currentViewIdCallbackState) - .getValue(); + const saveViewGroup = useCallback( + async (viewGroupToSave: ViewGroup) => { + if (!canPersistChanges) { + return; + } - if (!currentViewId) { - return; - } + const currentViewId = store.get(currentViewIdCallbackState); - const view = getViewFromPrefetchState(currentViewId); + if (!currentViewId) { + return; + } - if (isUndefinedOrNull(view)) { - return; - } + const view = getViewFromPrefetchState(currentViewId); - const currentViewGroups = view.viewGroups; + if (isUndefinedOrNull(view)) { + return; + } - const existingField = currentViewGroups.find( - (currentViewGroup) => - currentViewGroup.fieldValue === viewGroupToSave.fieldValue, - ); + const currentViewGroups = view.viewGroups; - if (isUndefinedOrNull(existingField)) { - return; - } + const existingField = currentViewGroups.find( + (currentViewGroup) => + currentViewGroup.fieldValue === viewGroupToSave.fieldValue, + ); - if ( - isDeeplyEqual( - { - position: existingField.position, - isVisible: existingField.isVisible, - }, - { - position: viewGroupToSave.position, - isVisible: viewGroupToSave.isVisible, - }, - ) - ) { - return; - } + if (isUndefinedOrNull(existingField)) { + return; + } - await performViewGroupAPIUpdate([ + if ( + isDeeplyEqual( { + position: existingField.position, + isVisible: existingField.isVisible, + }, + { + position: viewGroupToSave.position, + isVisible: viewGroupToSave.isVisible, + }, + ) + ) { + return; + } + + await performViewGroupAPIUpdate([ + { + input: { + id: existingField.id, + update: { + isVisible: viewGroupToSave.isVisible, + position: viewGroupToSave.position, + fieldValue: viewGroupToSave.fieldValue, + }, + }, + }, + ]); + }, + [ + store, + canPersistChanges, + currentViewIdCallbackState, + getViewFromPrefetchState, + performViewGroupAPIUpdate, + ], + ); + + const saveViewGroups = useCallback( + async (viewGroupsToSave: ViewGroup[]) => { + if (!canPersistChanges) { + return; + } + + const currentViewId = store.get(currentViewIdCallbackState); + + if (!currentViewId) { + return; + } + + const view = getViewFromPrefetchState(currentViewId); + + if (isUndefinedOrNull(view)) { + return; + } + + const currentViewGroups = view.viewGroups; + + const viewGroupsToUpdate = viewGroupsToSave + .map((viewGroupToSave) => { + const existingField = currentViewGroups.find( + (currentViewGroup) => + currentViewGroup.fieldValue === viewGroupToSave.fieldValue, + ); + + if (isUndefinedOrNull(existingField)) { + return undefined; + } + + if ( + isDeeplyEqual( + { + position: existingField.position, + isVisible: existingField.isVisible, + }, + { + position: viewGroupToSave.position, + isVisible: viewGroupToSave.isVisible, + }, + ) + ) { + return undefined; + } + + return { input: { id: existingField.id, update: { @@ -77,86 +144,18 @@ export const useSaveCurrentViewGroups = () => { fieldValue: viewGroupToSave.fieldValue, }, }, - }, - ]); - }, - [ - canPersistChanges, - currentViewIdCallbackState, - getViewFromPrefetchState, - performViewGroupAPIUpdate, - ], - ); - - const saveViewGroups = useRecoilCallback( - ({ snapshot }) => - async (viewGroupsToSave: ViewGroup[]) => { - if (!canPersistChanges) { - return; - } - - const currentViewId = snapshot - .getLoadable(currentViewIdCallbackState) - .getValue(); - - if (!currentViewId) { - return; - } - - const view = getViewFromPrefetchState(currentViewId); - - if (isUndefinedOrNull(view)) { - return; - } - - const currentViewGroups = view.viewGroups; - - const viewGroupsToUpdate = viewGroupsToSave - .map((viewGroupToSave) => { - const existingField = currentViewGroups.find( - (currentViewGroup) => - currentViewGroup.fieldValue === viewGroupToSave.fieldValue, - ); - - if (isUndefinedOrNull(existingField)) { - return undefined; - } - - if ( - isDeeplyEqual( - { - position: existingField.position, - isVisible: existingField.isVisible, - }, - { - position: viewGroupToSave.position, - isVisible: viewGroupToSave.isVisible, - }, - ) - ) { - return undefined; - } - - return { - input: { - id: existingField.id, - update: { - isVisible: viewGroupToSave.isVisible, - position: viewGroupToSave.position, - fieldValue: viewGroupToSave.fieldValue, - }, - }, - }; - }) - .filter(isDefined); - - if (!isDefined(view.mainGroupByFieldMetadataId)) { - throw new Error('mainGroupByFieldMetadataId is required'); - } - - await performViewGroupAPIUpdate(viewGroupsToUpdate); - }, + }; + }) + .filter(isDefined); + + if (!isDefined(view.mainGroupByFieldMetadataId)) { + throw new Error('mainGroupByFieldMetadataId is required'); + } + + await performViewGroupAPIUpdate(viewGroupsToUpdate); + }, [ + store, canPersistChanges, currentViewIdCallbackState, getViewFromPrefetchState, diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveRecordFilterGroupsToViewFilterGroups.ts b/packages/twenty-front/src/modules/views/hooks/useSaveRecordFilterGroupsToViewFilterGroups.ts index d8a3a2b977..e292cf177c 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveRecordFilterGroupsToViewFilterGroups.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveRecordFilterGroupsToViewFilterGroups.ts @@ -1,6 +1,5 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewFilterGroupAPIPersist } from '@/views/hooks/internal/usePerformViewFilterGroupAPIPersist'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; @@ -8,7 +7,8 @@ import { getViewFilterGroupsToCreate } from '@/views/utils/getViewFilterGroupsTo import { getViewFilterGroupsToDelete } from '@/views/utils/getViewFilterGroupsToDelete'; import { getViewFilterGroupsToUpdate } from '@/views/utils/getViewFilterGroupsToUpdate'; import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useSaveRecordFilterGroupsToViewFilterGroups = () => { @@ -22,65 +22,65 @@ export const useSaveRecordFilterGroupsToViewFilterGroups = () => { const { currentView } = useGetCurrentViewOnly(); const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState(currentRecordFilterGroupsComponentState); + useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + ); - const saveRecordFilterGroupsToViewFilterGroups = useRecoilCallback( - ({ snapshot }) => - async () => { - if (!canPersistChanges || !isDefined(currentView)) { - return; - } + const store = useStore(); - const currentViewFilterGroups = currentView?.viewFilterGroups ?? []; + const saveRecordFilterGroupsToViewFilterGroups = useCallback(async () => { + if (!canPersistChanges || !isDefined(currentView)) { + return; + } - const currentRecordFilterGroups = getSnapshotValue( - snapshot, - currentRecordFilterGroupsCallbackState, - ); + const currentViewFilterGroups = currentView?.viewFilterGroups ?? []; - const newViewFilterGroups = currentRecordFilterGroups.map( - (recordFilterGroup) => - mapRecordFilterGroupToViewFilterGroup({ - recordFilterGroup, - view: currentView, - }), - ); - - const viewFilterGroupsToCreate = getViewFilterGroupsToCreate( - currentViewFilterGroups, - newViewFilterGroups, - ); - - const viewFilterGroupsToDelete = getViewFilterGroupsToDelete( - currentViewFilterGroups, - newViewFilterGroups, - ); - - const viewFilterGroupsToUpdate = getViewFilterGroupsToUpdate( - currentViewFilterGroups, - newViewFilterGroups, - ); - - const viewFilterGroupIdsToDelete = viewFilterGroupsToDelete.map( - (viewFilterGroup) => viewFilterGroup.id, - ); - - await performViewFilterGroupAPICreate( - viewFilterGroupsToCreate, - currentView, - ); - await performViewFilterGroupAPIUpdate(viewFilterGroupsToUpdate); - await performViewFilterGroupAPIDelete(viewFilterGroupIdsToDelete); - }, - [ - canPersistChanges, - currentView, + const currentRecordFilterGroups = store.get( currentRecordFilterGroupsCallbackState, - performViewFilterGroupAPICreate, - performViewFilterGroupAPIUpdate, - performViewFilterGroupAPIDelete, - ], - ); + ); + + const newViewFilterGroups = currentRecordFilterGroups.map( + (recordFilterGroup) => + mapRecordFilterGroupToViewFilterGroup({ + recordFilterGroup, + view: currentView, + }), + ); + + const viewFilterGroupsToCreate = getViewFilterGroupsToCreate( + currentViewFilterGroups, + newViewFilterGroups, + ); + + const viewFilterGroupsToDelete = getViewFilterGroupsToDelete( + currentViewFilterGroups, + newViewFilterGroups, + ); + + const viewFilterGroupsToUpdate = getViewFilterGroupsToUpdate( + currentViewFilterGroups, + newViewFilterGroups, + ); + + const viewFilterGroupIdsToDelete = viewFilterGroupsToDelete.map( + (viewFilterGroup) => viewFilterGroup.id, + ); + + await performViewFilterGroupAPICreate( + viewFilterGroupsToCreate, + currentView, + ); + await performViewFilterGroupAPIUpdate(viewFilterGroupsToUpdate); + await performViewFilterGroupAPIDelete(viewFilterGroupIdsToDelete); + }, [ + store, + canPersistChanges, + currentView, + currentRecordFilterGroupsCallbackState, + performViewFilterGroupAPICreate, + performViewFilterGroupAPIUpdate, + performViewFilterGroupAPIDelete, + ]); return { saveRecordFilterGroupsToViewFilterGroups, diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveRecordFiltersToViewFilters.ts b/packages/twenty-front/src/modules/views/hooks/useSaveRecordFiltersToViewFilters.ts index d2423c2c4c..230b5e6a70 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveRecordFiltersToViewFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveRecordFiltersToViewFilters.ts @@ -1,6 +1,5 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewFilterAPIPersist } from '@/views/hooks/internal/usePerformViewFilterAPIPersist'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; @@ -8,7 +7,8 @@ import { getViewFiltersToCreate } from '@/views/utils/getViewFiltersToCreate'; import { getViewFiltersToDelete } from '@/views/utils/getViewFiltersToDelete'; import { getViewFiltersToUpdate } from '@/views/utils/getViewFiltersToUpdate'; import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useSaveRecordFiltersToViewFilters = () => { @@ -21,111 +21,100 @@ export const useSaveRecordFiltersToViewFilters = () => { const { currentView } = useGetCurrentViewOnly(); - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( - currentRecordFiltersComponentState, - ); + const currentRecordFiltersCallbackState = + useRecoilComponentStateCallbackStateV2(currentRecordFiltersComponentState); - const saveRecordFiltersToViewFilters = useRecoilCallback( - ({ snapshot }) => - async () => { - if (!canPersistChanges || !isDefined(currentView)) { - return; - } + const store = useStore(); - const currentViewFilters = currentView?.viewFilters ?? []; + const saveRecordFiltersToViewFilters = useCallback(async () => { + if (!canPersistChanges || !isDefined(currentView)) { + return; + } - const currentRecordFilters = getSnapshotValue( - snapshot, - currentRecordFiltersCallbackState, - ); + const currentViewFilters = currentView?.viewFilters ?? []; - const newViewFilters = currentRecordFilters.map( - mapRecordFilterToViewFilter, - ); + const currentRecordFilters = store.get(currentRecordFiltersCallbackState); - const viewFiltersToCreate = getViewFiltersToCreate( - currentViewFilters, - newViewFilters, - ); + const newViewFilters = currentRecordFilters.map( + mapRecordFilterToViewFilter, + ); - const viewFiltersToDelete = getViewFiltersToDelete( - currentViewFilters, - newViewFilters, - ); + const viewFiltersToCreate = getViewFiltersToCreate( + currentViewFilters, + newViewFilters, + ); - const viewFiltersToUpdate = getViewFiltersToUpdate( - currentViewFilters, - newViewFilters, - ); + const viewFiltersToDelete = getViewFiltersToDelete( + currentViewFilters, + newViewFilters, + ); - const createViewFilterInputs = viewFiltersToCreate.map( - (viewFilter) => ({ - input: { - id: viewFilter.id, - fieldMetadataId: viewFilter.fieldMetadataId, - viewId: currentView.id, - value: viewFilter.value, - operand: viewFilter.operand, - viewFilterGroupId: viewFilter.viewFilterGroupId, - positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, - subFieldName: viewFilter.subFieldName ?? null, - }, - }), - ); + const viewFiltersToUpdate = getViewFiltersToUpdate( + currentViewFilters, + newViewFilters, + ); - const updateViewFilterInputs = viewFiltersToUpdate.map( - (viewFilter) => ({ - input: { - id: viewFilter.id, - update: { - value: viewFilter.value, - operand: viewFilter.operand, - positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, - viewFilterGroupId: viewFilter.viewFilterGroupId, - subFieldName: viewFilter.subFieldName ?? null, - }, - }, - }), - ); - - const deleteViewFilterInputs = viewFiltersToDelete.map( - (viewFilter) => ({ - input: { - id: viewFilter.id, - }, - }), - ); - - const createResult = await performViewFilterAPICreate( - createViewFilterInputs, - ); - if (createResult.status === 'failed') { - return; - } - - const updateResult = await performViewFilterAPIUpdate( - updateViewFilterInputs, - ); - if (updateResult.status === 'failed') { - return; - } - - const deleteResult = await performViewFilterAPIDelete( - deleteViewFilterInputs, - ); - if (deleteResult.status === 'failed') { - return; - } + const createViewFilterInputs = viewFiltersToCreate.map((viewFilter) => ({ + input: { + id: viewFilter.id, + fieldMetadataId: viewFilter.fieldMetadataId, + viewId: currentView.id, + value: viewFilter.value, + operand: viewFilter.operand, + viewFilterGroupId: viewFilter.viewFilterGroupId, + positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, + subFieldName: viewFilter.subFieldName ?? null, }, - [ - canPersistChanges, - currentView, - currentRecordFiltersCallbackState, - performViewFilterAPICreate, - performViewFilterAPIUpdate, - performViewFilterAPIDelete, - ], - ); + })); + + const updateViewFilterInputs = viewFiltersToUpdate.map((viewFilter) => ({ + input: { + id: viewFilter.id, + update: { + value: viewFilter.value, + operand: viewFilter.operand, + positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, + viewFilterGroupId: viewFilter.viewFilterGroupId, + subFieldName: viewFilter.subFieldName ?? null, + }, + }, + })); + + const deleteViewFilterInputs = viewFiltersToDelete.map((viewFilter) => ({ + input: { + id: viewFilter.id, + }, + })); + + const createResult = await performViewFilterAPICreate( + createViewFilterInputs, + ); + if (createResult.status === 'failed') { + return; + } + + const updateResult = await performViewFilterAPIUpdate( + updateViewFilterInputs, + ); + if (updateResult.status === 'failed') { + return; + } + + const deleteResult = await performViewFilterAPIDelete( + deleteViewFilterInputs, + ); + if (deleteResult.status === 'failed') { + return; + } + }, [ + store, + canPersistChanges, + currentView, + currentRecordFiltersCallbackState, + performViewFilterAPICreate, + performViewFilterAPIUpdate, + performViewFilterAPIDelete, + ]); return { saveRecordFiltersToViewFilters, diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts b/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts index a9217bce89..930ef48b83 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts @@ -1,6 +1,5 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewSortAPIPersist } from '@/views/hooks/internal/usePerformViewSortAPIPersist'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; @@ -8,7 +7,8 @@ import { getViewSortsToCreate } from '@/views/utils/getViewSortsToCreate'; import { getViewSortsToDelete } from '@/views/utils/getViewSortsToDelete'; import { getViewSortsToUpdate } from '@/views/utils/getViewSortsToUpdate'; import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useSaveRecordSortsToViewSorts = () => { @@ -21,56 +21,51 @@ export const useSaveRecordSortsToViewSorts = () => { const { currentView } = useGetCurrentViewOnly(); - const currentRecordSortsCallbackState = useRecoilComponentCallbackState( - currentRecordSortsComponentState, - ); + const currentRecordSortsCallbackState = + useRecoilComponentStateCallbackStateV2(currentRecordSortsComponentState); - const saveRecordSortsToViewSorts = useRecoilCallback( - ({ snapshot }) => - async () => { - if (!canPersistChanges || !isDefined(currentView)) { - return; - } + const store = useStore(); - const currentViewSorts = currentView?.viewSorts ?? []; + const saveRecordSortsToViewSorts = useCallback(async () => { + if (!canPersistChanges || !isDefined(currentView)) { + return; + } - const currentRecordSorts = getSnapshotValue( - snapshot, - currentRecordSortsCallbackState, - ); + const currentViewSorts = currentView?.viewSorts ?? []; - const newViewSorts = currentRecordSorts.map((recordSort) => - mapRecordSortToViewSort(recordSort, currentView.id), - ); + const currentRecordSorts = store.get(currentRecordSortsCallbackState); - const viewSortsToCreate = getViewSortsToCreate( - currentViewSorts, - newViewSorts, - ); + const newViewSorts = currentRecordSorts.map((recordSort) => + mapRecordSortToViewSort(recordSort, currentView.id), + ); - const viewSortsToDelete = getViewSortsToDelete( - currentViewSorts, - newViewSorts, - ); + const viewSortsToCreate = getViewSortsToCreate( + currentViewSorts, + newViewSorts, + ); - const viewSortsToUpdate = getViewSortsToUpdate( - currentViewSorts, - newViewSorts, - ); + const viewSortsToDelete = getViewSortsToDelete( + currentViewSorts, + newViewSorts, + ); - await performViewSortAPICreate(viewSortsToCreate, currentView); - await performViewSortAPIUpdate(viewSortsToUpdate); - await performViewSortAPIDelete(viewSortsToDelete); - }, - [ - canPersistChanges, - currentView, - currentRecordSortsCallbackState, - performViewSortAPICreate, - performViewSortAPIUpdate, - performViewSortAPIDelete, - ], - ); + const viewSortsToUpdate = getViewSortsToUpdate( + currentViewSorts, + newViewSorts, + ); + + await performViewSortAPICreate(viewSortsToCreate, currentView); + await performViewSortAPIUpdate(viewSortsToUpdate); + await performViewSortAPIDelete(viewSortsToDelete); + }, [ + store, + canPersistChanges, + currentView, + currentRecordSortsCallbackState, + performViewSortAPICreate, + performViewSortAPIUpdate, + performViewSortAPIDelete, + ]); return { saveRecordSortsToViewSorts, diff --git a/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts b/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts index fb017a8804..3582dd1b52 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts @@ -5,61 +5,62 @@ import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { getEditableChipObjectFilterDropdownComponentInstanceId } from '@/views/editable-chip/utils/getEditableChipObjectFilterDropdownComponentInstanceId'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useSetEditableFilterChipDropdownStates = () => { const { filterableFieldMetadataItems } = useFilterableFieldMetadataItemsInRecordIndexContext(); - const setEditableFilterChipDropdownStates = useRecoilCallback( - ({ set }) => - (recordFilter: RecordFilter) => { - const fieldMetadataItem = filterableFieldMetadataItems.find( - (fieldMetadataItem) => - fieldMetadataItem.id === recordFilter.fieldMetadataId, - ); + const store = useStore(); - if (isDefined(fieldMetadataItem)) { - set( - fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ - instanceId: - getEditableChipObjectFilterDropdownComponentInstanceId({ - recordFilterId: recordFilter.id, - }), - }), - fieldMetadataItem.id, - ); - } + const setEditableFilterChipDropdownStates = useCallback( + (recordFilter: RecordFilter) => { + const fieldMetadataItem = filterableFieldMetadataItems.find( + (fieldMetadataItem) => + fieldMetadataItem.id === recordFilter.fieldMetadataId, + ); - set( - selectedOperandInDropdownComponentState.atomFamily({ + if (isDefined(fieldMetadataItem)) { + store.set( + fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({ recordFilterId: recordFilter.id, }), }), - recordFilter.operand, + fieldMetadataItem.id, ); + } - set( - objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({ - instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({ - recordFilterId: recordFilter.id, - }), + store.set( + selectedOperandInDropdownComponentState.atomFamily({ + instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({ + recordFilterId: recordFilter.id, }), - recordFilter, - ); + }), + recordFilter.operand, + ); - set( - subFieldNameUsedInDropdownComponentState.atomFamily({ - instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({ - recordFilterId: recordFilter.id, - }), + store.set( + objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({ + instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({ + recordFilterId: recordFilter.id, }), - recordFilter.subFieldName, - ); - }, - [filterableFieldMetadataItems], + }), + recordFilter, + ); + + store.set( + subFieldNameUsedInDropdownComponentState.atomFamily({ + instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({ + recordFilterId: recordFilter.id, + }), + }), + recordFilter.subFieldName, + ); + }, + [store, filterableFieldMetadataItems], ); return { diff --git a/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts b/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts index f0cd1d4ae1..aab0387adf 100644 --- a/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts @@ -1,11 +1,11 @@ import { useStore } from 'jotai'; -import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; @@ -14,19 +14,19 @@ import { type View } from '@/views/types/View'; import { type ViewGroup } from '@/views/types/ViewGroup'; import { type ViewType } from '@/views/types/ViewType'; import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore'; -import { useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { useUpdateCoreViewMutation } from '~/generated-metadata/graphql'; export const useUpdateCurrentView = () => { const { canPersistChanges } = useCanPersistViewChanges(); - const currentViewIdCallbackState = useRecoilComponentCallbackState( + const currentViewIdCallbackState = useRecoilComponentStateCallbackStateV2( contextStoreCurrentViewIdComponentState, ); const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); const { loadRecordIndexStates } = useLoadRecordIndexStates(); - const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState); + const setRecordIndexViewType = useSetRecoilStateV2(recordIndexViewTypeState); const store = useStore(); @@ -91,66 +91,61 @@ export const useUpdateCurrentView = () => { }; }, [objectMetadataItem.fields]); - const updateCurrentView = useRecoilCallback( - ({ snapshot }) => - async (view: Partial & { type?: ViewType }) => { - if (!canPersistChanges) { - return; - } + const updateCurrentView = useCallback( + async (view: Partial & { type?: ViewType }) => { + if (!canPersistChanges) { + return; + } - const currentViewId = snapshot - .getLoadable(currentViewIdCallbackState) - .getValue(); + const currentViewId = store.get(currentViewIdCallbackState); - const currentView = store.get( - coreViewFromViewIdFamilySelector.selectorFamily({ - viewId: currentViewId ?? '', - }), - ); + const currentView = store.get( + coreViewFromViewIdFamilySelector.selectorFamily({ + viewId: currentViewId ?? '', + }), + ); - if (!isDefined(currentView)) { - return; - } + if (!isDefined(currentView)) { + return; + } - if (isDefined(currentViewId)) { - const input = convertUpdateViewInputToCore(view); + if (isDefined(currentViewId)) { + const input = convertUpdateViewInputToCore(view); - await updateOneCoreView({ - variables: { - id: currentViewId, - input, - }, + await updateOneCoreView({ + variables: { + id: currentViewId, + input, + }, + }); + + if ( + input.mainGroupByFieldMetadataId !== undefined && + currentView.mainGroupByFieldMetadataId !== + input.mainGroupByFieldMetadataId + ) { + const { viewGroupsToCreate } = getViewGroupsToCreateAtViewUpdate({ + existingView: currentView, + newMainGroupByFieldMetadataId: input.mainGroupByFieldMetadataId, }); - if ( - input.mainGroupByFieldMetadataId !== undefined && - currentView.mainGroupByFieldMetadataId !== - input.mainGroupByFieldMetadataId - ) { - const { viewGroupsToCreate } = getViewGroupsToCreateAtViewUpdate({ - existingView: currentView, - newMainGroupByFieldMetadataId: input.mainGroupByFieldMetadataId, - }); - - loadRecordIndexStates( - { - ...currentView, - mainGroupByFieldMetadataId: input.mainGroupByFieldMetadataId, - viewGroups: viewGroupsToCreate ?? [], - }, - objectMetadataItem, - ); - } - - if (isDefined(view.type)) { - setRecordIndexViewType(view.type); - } - - await refreshCoreViewsByObjectMetadataId( - currentView.objectMetadataId, + loadRecordIndexStates( + { + ...currentView, + mainGroupByFieldMetadataId: input.mainGroupByFieldMetadataId, + viewGroups: viewGroupsToCreate ?? [], + }, + objectMetadataItem, ); } - }, + + if (isDefined(view.type)) { + setRecordIndexViewType(view.type); + } + + await refreshCoreViewsByObjectMetadataId(currentView.objectMetadataId); + } + }, [ canPersistChanges, currentViewIdCallbackState, diff --git a/packages/twenty-front/src/modules/views/hooks/useUpdateViewAggregate.ts b/packages/twenty-front/src/modules/views/hooks/useUpdateViewAggregate.ts index 89a883906a..8a7eae3224 100644 --- a/packages/twenty-front/src/modules/views/hooks/useUpdateViewAggregate.ts +++ b/packages/twenty-front/src/modules/views/hooks/useUpdateViewAggregate.ts @@ -3,7 +3,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-record/utils/convertExtendedAggregateOperationToAggregateOperation'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; @@ -18,7 +18,7 @@ import { type CoreView } from '~/generated-metadata/graphql'; export const useUpdateViewAggregate = () => { const { canPersistChanges } = useCanPersistViewChanges(); - const currentViewId = useRecoilComponentValue( + const currentViewId = useRecoilComponentValueV2( contextStoreCurrentViewIdComponentState, ); const { performViewAPIUpdate } = usePerformViewAPIUpdate(); diff --git a/packages/twenty-front/src/modules/views/states/availableFieldDefinitionsComponentState.ts b/packages/twenty-front/src/modules/views/states/availableFieldDefinitionsComponentState.ts index 254778e605..710679054f 100644 --- a/packages/twenty-front/src/modules/views/states/availableFieldDefinitionsComponentState.ts +++ b/packages/twenty-front/src/modules/views/states/availableFieldDefinitionsComponentState.ts @@ -1,9 +1,9 @@ import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -export const availableFieldDefinitionsComponentState = createComponentState< +export const availableFieldDefinitionsComponentState = createComponentStateV2< ColumnDefinition[] >({ key: 'availableFieldDefinitionsComponentState', diff --git a/packages/twenty-front/src/modules/views/states/hasInitializedAnyFieldFilterComponentFamilyState.ts b/packages/twenty-front/src/modules/views/states/hasInitializedAnyFieldFilterComponentFamilyState.ts index 942118707a..1f0e42c348 100644 --- a/packages/twenty-front/src/modules/views/states/hasInitializedAnyFieldFilterComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/views/states/hasInitializedAnyFieldFilterComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const hasInitializedAnyFieldFilterComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedAnyFieldFilterComponentFamilyState', defaultValue: false, componentInstanceContext: RecordFiltersComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts index 34cb071eae..6963b01993 100644 --- a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFieldsComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordFieldsComponentInstanceContext } from '@/object-record/record-field/states/context/RecordFieldsComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const hasInitializedCurrentRecordFieldsComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedCurrentRecordFieldsComponentFamilyState', defaultValue: false, componentInstanceContext: RecordFieldsComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState.ts b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState.ts index f16990d027..3be2166778 100644 --- a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const hasInitializedCurrentRecordFilterGroupsComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedCurrentRecordFilterGroupsComponentFamilyState', defaultValue: false, componentInstanceContext: RecordFilterGroupsComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState.ts b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState.ts index 01fb839ebc..ce1c0be4a8 100644 --- a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const hasInitializedCurrentRecordFiltersComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedCurrentRecordFiltersComponentFamilyState', defaultValue: false, componentInstanceContext: RecordFiltersComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordSortsComponentFamilyState.ts b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordSortsComponentFamilyState.ts index 28e25c5375..2908db3317 100644 --- a/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordSortsComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/views/states/hasInitializedCurrentRecordSortsComponentFamilyState.ts @@ -1,8 +1,8 @@ import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; export const hasInitializedCurrentRecordSortsComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedCurrentRecordSortsComponentFamilyState', defaultValue: false, componentInstanceContext: RecordSortsComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/isCurrentViewIndexComponentState.ts b/packages/twenty-front/src/modules/views/states/isCurrentViewIndexComponentState.ts index d071a61e2c..75666dc567 100644 --- a/packages/twenty-front/src/modules/views/states/isCurrentViewIndexComponentState.ts +++ b/packages/twenty-front/src/modules/views/states/isCurrentViewIndexComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const isCurrentViewKeyIndexComponentState = - createComponentState({ + createComponentStateV2({ key: 'isCurrentViewKeyIndexComponentState', defaultValue: true, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/isViewBarExpandedComponentState.ts b/packages/twenty-front/src/modules/views/states/isViewBarExpandedComponentState.ts index 0c59bf4f3e..f3edd1d081 100644 --- a/packages/twenty-front/src/modules/views/states/isViewBarExpandedComponentState.ts +++ b/packages/twenty-front/src/modules/views/states/isViewBarExpandedComponentState.ts @@ -1,7 +1,7 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -export const isViewBarExpandedComponentState = createComponentState({ +export const isViewBarExpandedComponentState = createComponentStateV2({ key: 'isViewBarExpandedComponentState', defaultValue: true, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/states/viewObjectMetadataIdComponentState.ts b/packages/twenty-front/src/modules/views/states/viewObjectMetadataIdComponentState.ts index 88584d1027..d4eb8afb30 100644 --- a/packages/twenty-front/src/modules/views/states/viewObjectMetadataIdComponentState.ts +++ b/packages/twenty-front/src/modules/views/states/viewObjectMetadataIdComponentState.ts @@ -1,7 +1,7 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -export const viewObjectMetadataIdComponentState = createComponentState< +export const viewObjectMetadataIdComponentState = createComponentStateV2< string | undefined >({ key: 'viewObjectMetadataIdComponentState', diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentCreateMode.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentCreateMode.tsx index 80d16f3556..2876ac9132 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentCreateMode.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentCreateMode.tsx @@ -11,9 +11,9 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType'; import { ViewPickerCreateButton } from '@/views/view-picker/components/ViewPickerCreateButton'; @@ -53,40 +53,41 @@ export const ViewPickerContentCreateMode = () => { const { viewPickerMode, setViewPickerMode } = useViewPickerMode(); const [hasManuallySelectedIcon, setHasManuallySelectedIcon] = useState(false); - const viewObjectMetadataId = useRecoilComponentValue( + const viewObjectMetadataId = useRecoilComponentValueV2( viewObjectMetadataIdComponentState, ); const { objectMetadataItem } = useObjectMetadataItemById({ objectId: viewObjectMetadataId ?? '', }); - const [viewPickerInputName, setViewPickerInputName] = useRecoilComponentState( - viewPickerInputNameComponentState, - ); + const [viewPickerInputName, setViewPickerInputName] = + useRecoilComponentStateV2(viewPickerInputNameComponentState); const [viewPickerSelectedIcon, setViewPickerSelectedIcon] = - useRecoilComponentState(viewPickerSelectedIconComponentState); + useRecoilComponentStateV2(viewPickerSelectedIconComponentState); - const viewPickerIsPersisting = useRecoilComponentValue( + const viewPickerIsPersisting = useRecoilComponentValueV2( viewPickerIsPersistingComponentState, ); - const setViewPickerIsDirty = useSetRecoilComponentState( + const setViewPickerIsDirty = useSetRecoilComponentStateV2( viewPickerIsDirtyComponentState, ); const [ viewPickerMainGroupByFieldMetadataId, setViewPickerMainGroupByFieldMetadataId, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( viewPickerMainGroupByFieldMetadataIdComponentState, ); const [ viewPickerCalendarFieldMetadataId, setViewPickerCalendarFieldMetadataId, - ] = useRecoilComponentState(viewPickerCalendarFieldMetadataIdComponentState); + ] = useRecoilComponentStateV2( + viewPickerCalendarFieldMetadataIdComponentState, + ); - const [viewPickerType, setViewPickerType] = useRecoilComponentState( + const [viewPickerType, setViewPickerType] = useRecoilComponentStateV2( viewPickerTypeComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEditMode.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEditMode.tsx index 4db4cd21cf..08e4be62dd 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEditMode.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEditMode.tsx @@ -8,9 +8,9 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ViewPickerEditButton } from '@/views/view-picker/components/ViewPickerEditButton'; import { ViewPickerIconAndNameContainer } from '@/views/view-picker/components/ViewPickerIconAndNameContainer'; import { ViewPickerSaveButtonContainer } from '@/views/view-picker/components/ViewPickerSaveButtonContainer'; @@ -27,16 +27,15 @@ import { IconChevronLeft } from 'twenty-ui/display'; export const ViewPickerContentEditMode = () => { const { setViewPickerMode } = useViewPickerMode(); - const [viewPickerInputName, setViewPickerInputName] = useRecoilComponentState( - viewPickerInputNameComponentState, - ); + const [viewPickerInputName, setViewPickerInputName] = + useRecoilComponentStateV2(viewPickerInputNameComponentState); const [viewPickerSelectedIcon, setViewPickerSelectedIcon] = - useRecoilComponentState(viewPickerSelectedIconComponentState); + useRecoilComponentStateV2(viewPickerSelectedIconComponentState); - const viewPickerIsPersisting = useRecoilComponentValue( + const viewPickerIsPersisting = useRecoilComponentValueV2( viewPickerIsPersistingComponentState, ); - const setViewPickerIsDirty = useSetRecoilComponentState( + const setViewPickerIsDirty = useSetRecoilComponentStateV2( viewPickerIsDirtyComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEffect.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEffect.tsx index 4dcc9e78a9..4671611395 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEffect.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerContentEffect.tsx @@ -2,9 +2,9 @@ import { useEffect } from 'react'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewsFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreViewsFromObjectMetadataItemFamilySelector'; import { viewTypeIconMapping } from '@/views/types/ViewType'; @@ -27,13 +27,13 @@ import { } from '~/generated-metadata/graphql'; export const ViewPickerContentEffect = () => { - const setViewPickerSelectedIcon = useSetRecoilComponentState( + const setViewPickerSelectedIcon = useSetRecoilComponentStateV2( viewPickerSelectedIconComponentState, ); - const setViewPickerInputName = useSetRecoilComponentState( + const setViewPickerInputName = useSetRecoilComponentStateV2( viewPickerInputNameComponentState, ); - const setViewPickerVisibility = useSetRecoilComponentState( + const setViewPickerVisibility = useSetRecoilComponentStateV2( viewPickerVisibilityComponentState, ); const { viewPickerMode } = useViewPickerMode(); @@ -41,28 +41,30 @@ export const ViewPickerContentEffect = () => { const [ viewPickerMainGroupByFieldMetadataId, setViewPickerMainGroupByFieldMetadataId, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( viewPickerMainGroupByFieldMetadataIdComponentState, ); const [ viewPickerCalendarFieldMetadataId, setViewPickerCalendarFieldMetadataId, - ] = useRecoilComponentState(viewPickerCalendarFieldMetadataIdComponentState); + ] = useRecoilComponentStateV2( + viewPickerCalendarFieldMetadataIdComponentState, + ); - const [viewPickerType, setViewPickerType] = useRecoilComponentState( + const [viewPickerType, setViewPickerType] = useRecoilComponentStateV2( viewPickerTypeComponentState, ); - const viewPickerReferenceViewId = useRecoilComponentValue( + const viewPickerReferenceViewId = useRecoilComponentValueV2( viewPickerReferenceViewIdComponentState, ); - const viewPickerIsDirty = useRecoilComponentValue( + const viewPickerIsDirty = useRecoilComponentValueV2( viewPickerIsDirtyComponentState, ); - const viewPickerIsPersisting = useRecoilComponentValue( + const viewPickerIsPersisting = useRecoilComponentValueV2( viewPickerIsPersistingComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateButton.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateButton.tsx index f86e7d9b1e..b6b21b2913 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateButton.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerCreateButton.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; import { useCreateViewFromCurrentState } from '@/views/view-picker/hooks/useCreateViewFromCurrentState'; import { useDestroyViewFromCurrentState } from '@/views/view-picker/hooks/useDestroyViewFromCurrentState'; @@ -20,14 +20,16 @@ export const ViewPickerCreateButton = () => { useGetAvailableFieldsForCalendar(); const { viewPickerMode } = useViewPickerMode(); - const viewPickerType = useRecoilComponentValue(viewPickerTypeComponentState); - const viewPickerIsPersisting = useRecoilComponentValue( + const viewPickerType = useRecoilComponentValueV2( + viewPickerTypeComponentState, + ); + const viewPickerIsPersisting = useRecoilComponentValueV2( viewPickerIsPersistingComponentState, ); - const viewPickerMainGroupByFieldMetadataId = useRecoilComponentValue( + const viewPickerMainGroupByFieldMetadataId = useRecoilComponentValueV2( viewPickerMainGroupByFieldMetadataIdComponentState, ); - const viewPickerCalendarFieldMetadataId = useRecoilComponentValue( + const viewPickerCalendarFieldMetadataId = useRecoilComponentValueV2( viewPickerCalendarFieldMetadataIdComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerEditButton.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerEditButton.tsx index 700877e06f..0d921ab66e 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerEditButton.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerEditButton.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; import { useCreateViewFromCurrentState } from '@/views/view-picker/hooks/useCreateViewFromCurrentState'; import { useDestroyViewFromCurrentState } from '@/views/view-picker/hooks/useDestroyViewFromCurrentState'; @@ -15,11 +15,13 @@ export const ViewPickerEditButton = () => { useGetAvailableFieldsToGroupRecordsBy(); const { viewPickerMode } = useViewPickerMode(); - const viewPickerType = useRecoilComponentValue(viewPickerTypeComponentState); - const viewPickerIsPersisting = useRecoilComponentValue( + const viewPickerType = useRecoilComponentValueV2( + viewPickerTypeComponentState, + ); + const viewPickerIsPersisting = useRecoilComponentValueV2( viewPickerIsPersistingComponentState, ); - const viewPickerMainGroupByFieldMetadataId = useRecoilComponentValue( + const viewPickerMainGroupByFieldMetadataId = useRecoilComponentValueV2( viewPickerMainGroupByFieldMetadataIdComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerFavoriteFoldersDropdown.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerFavoriteFoldersDropdown.tsx index 89534545aa..01ce6268e7 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerFavoriteFoldersDropdown.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerFavoriteFoldersDropdown.tsx @@ -1,14 +1,14 @@ import { FavoriteFolderPicker } from '@/favorites/favorite-folder-picker/components/FavoriteFolderPicker'; import { FavoriteFolderPickerEffect } from '@/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect'; import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState'; export const ViewPickerFavoriteFoldersDropdown = () => { - const [viewPickerReferenceViewId] = useRecoilComponentState( + const [viewPickerReferenceViewId] = useRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx index d5ace32e87..e8cd9f91c3 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx @@ -10,7 +10,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate'; import { useChangeView } from '@/views/hooks/useChangeView'; @@ -54,7 +54,7 @@ export const ViewPickerListContent = () => { const { currentView } = useGetCurrentViewOnly(); - const setViewPickerReferenceViewId = useSetRecoilComponentState( + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx index 589b48f825..a048d63529 100644 --- a/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/components/ViewPickerOptionDropdown.tsx @@ -6,7 +6,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { MenuItemWithOptionDropdown } from '@/ui/navigation/menu-item/components/MenuItemWithOptionDropdown'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { type View } from '@/views/types/View'; import { useDestroyViewFromCurrentState } from '@/views/view-picker/hooks/useDestroyViewFromCurrentState'; import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode'; @@ -54,7 +54,7 @@ export const ViewPickerOptionDropdown = ({ const { closeDropdown } = useCloseDropdown(); const { getIcon } = useIcons(); const { destroyViewFromCurrentState } = useDestroyViewFromCurrentState(); - const setViewPickerReferenceViewId = useSetRecoilComponentState( + const setViewPickerReferenceViewId = useSetRecoilComponentStateV2( viewPickerReferenceViewIdComponentState, ); const { setViewPickerMode } = useViewPickerMode(); diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx b/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx index a81ca2a544..3f59d68d85 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx @@ -7,7 +7,6 @@ import { renderHook } from '@testing-library/react'; import { type ReactNode } from 'react'; import { Provider as JotaiProvider } from 'jotai'; import { MemoryRouter } from 'react-router-dom'; -import { RecoilRoot } from 'recoil'; import { FieldMetadataType } from '~/generated-metadata/graphql'; const mockObjectMetadataId = 'test-object-id'; @@ -24,26 +23,21 @@ const createMockObjectMetadataItem = (fields: any[]) => ({ const createWrapper = (objectMetadataItems: any[]) => { return ({ children }: { children: ReactNode }) => { jotaiStore.set(objectMetadataItemsState.atom, objectMetadataItems); + jotaiStore.set( + viewObjectMetadataIdComponentState.atomFamily({ + instanceId: mockViewInstanceId, + }), + mockObjectMetadataId, + ); return ( - { - snapshot.set( - viewObjectMetadataIdComponentState.atomFamily({ - instanceId: mockViewInstanceId, - }), - mockObjectMetadataId, - ); - }} - > - - - {children} - - - + + + {children} + + ); }; diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsToGroupRecordsBy.test.tsx b/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsToGroupRecordsBy.test.tsx index a06839e68d..0ed7f578b9 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsToGroupRecordsBy.test.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsToGroupRecordsBy.test.tsx @@ -7,7 +7,6 @@ import { renderHook } from '@testing-library/react'; import { type ReactNode } from 'react'; import { Provider as JotaiProvider } from 'jotai'; import { MemoryRouter } from 'react-router-dom'; -import { RecoilRoot } from 'recoil'; import { FieldMetadataType } from '~/generated-metadata/graphql'; const mockObjectMetadataId = 'test-object-id'; @@ -24,26 +23,21 @@ const createMockObjectMetadataItem = (fields: any[]) => ({ const createWrapper = (objectMetadataItems: any[]) => { return ({ children }: { children: ReactNode }) => { jotaiStore.set(objectMetadataItemsState.atom, objectMetadataItems); + jotaiStore.set( + viewObjectMetadataIdComponentState.atomFamily({ + instanceId: mockViewInstanceId, + }), + mockObjectMetadataId, + ); return ( - { - snapshot.set( - viewObjectMetadataIdComponentState.atomFamily({ - instanceId: mockViewInstanceId, - }), - mockObjectMetadataId, - ); - }} - > - - - {children} - - - + + + {children} + + ); }; diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts index 5e64ed141e..3130637e47 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useCloseAndResetViewPicker.ts @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId'; import { VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerViewTypeDropdownId'; @@ -9,11 +9,11 @@ import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states import { viewPickerModeComponentState } from '@/views/view-picker/states/viewPickerModeComponentState'; export const useCloseAndResetViewPicker = () => { - const setViewPickerMode = useSetRecoilComponentState( + const setViewPickerMode = useSetRecoilComponentStateV2( viewPickerModeComponentState, ); - const setViewPickerIsPersisting = useSetRecoilComponentState( + const setViewPickerIsPersisting = useSetRecoilComponentStateV2( viewPickerIsPersistingComponentState, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts index 763ea8fe31..ebb81e76f1 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useCreateViewFromCurrentState.ts @@ -1,5 +1,4 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useChangeView } from '@/views/hooks/useChangeView'; import { useCreateViewFromCurrentView } from '@/views/hooks/useCreateViewFromCurrentView'; import { ViewType } from '@/views/types/ViewType'; @@ -13,122 +12,108 @@ import { viewPickerModeComponentState } from '@/views/view-picker/states/viewPic import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState'; import { viewPickerTypeComponentState } from '@/views/view-picker/states/viewPickerTypeComponentState'; import { viewPickerVisibilityComponentState } from '@/views/view-picker/states/viewPickerVisibilityComponentState'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useCreateViewFromCurrentState = () => { const { closeAndResetViewPicker } = useCloseAndResetViewPicker(); - const viewPickerInputNameCallbackState = useRecoilComponentCallbackState( - viewPickerInputNameComponentState, - ); + const viewPickerInputNameCallbackState = + useRecoilComponentStateCallbackStateV2(viewPickerInputNameComponentState); - const viewPickerSelectedIconCallbackState = useRecoilComponentCallbackState( - viewPickerSelectedIconComponentState, - ); + const viewPickerSelectedIconCallbackState = + useRecoilComponentStateCallbackStateV2( + viewPickerSelectedIconComponentState, + ); - const viewPickerTypeCallbackState = useRecoilComponentCallbackState( + const viewPickerTypeCallbackState = useRecoilComponentStateCallbackStateV2( viewPickerTypeComponentState, ); const viewPickerMainGroupByFieldMetadataIdCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( viewPickerMainGroupByFieldMetadataIdComponentState, ); const viewPickerCalendarFieldMetadataIdCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( viewPickerCalendarFieldMetadataIdComponentState, ); - const viewPickerIsPersistingCallbackState = useRecoilComponentCallbackState( - viewPickerIsPersistingComponentState, - ); + const viewPickerIsPersistingCallbackState = + useRecoilComponentStateCallbackStateV2( + viewPickerIsPersistingComponentState, + ); - const viewPickerIsDirtyCallbackState = useRecoilComponentCallbackState( + const viewPickerIsDirtyCallbackState = useRecoilComponentStateCallbackStateV2( viewPickerIsDirtyComponentState, ); - const viewPickerModeCallbackState = useRecoilComponentCallbackState( + const viewPickerModeCallbackState = useRecoilComponentStateCallbackStateV2( viewPickerModeComponentState, ); - const viewPickerVisibilityCallbackState = useRecoilComponentCallbackState( - viewPickerVisibilityComponentState, - ); + const viewPickerVisibilityCallbackState = + useRecoilComponentStateCallbackStateV2(viewPickerVisibilityComponentState); const { createViewFromCurrentView } = useCreateViewFromCurrentView(); const { changeView } = useChangeView(); - const createViewFromCurrentState = useRecoilCallback( - ({ snapshot, set }) => - async () => { - const name = getSnapshotValue( - snapshot, - viewPickerInputNameCallbackState, - ); - const iconKey = getSnapshotValue( - snapshot, - viewPickerSelectedIconCallbackState, - ); - const type = getSnapshotValue(snapshot, viewPickerTypeCallbackState); - const mainGroupByFieldMetadataId = getSnapshotValue( - snapshot, - viewPickerMainGroupByFieldMetadataIdCallbackState, - ); - const calendarFieldMetadataId = getSnapshotValue( - snapshot, - viewPickerCalendarFieldMetadataIdCallbackState, - ); + const store = useStore(); - const viewPickerMode = getSnapshotValue( - snapshot, - viewPickerModeCallbackState, - ); - const visibility = getSnapshotValue( - snapshot, - viewPickerVisibilityCallbackState, - ); - - const shouldCopyFiltersAndSortsAndAggregate = - viewPickerMode === 'create-from-current'; - - set(viewPickerIsPersistingCallbackState, true); - set(viewPickerIsDirtyCallbackState, false); - - const createdViewId = await createViewFromCurrentView( - { - name, - icon: iconKey, - type, - mainGroupByFieldMetadataId: - type === ViewType.Kanban ? mainGroupByFieldMetadataId : null, - calendarFieldMetadataId, - visibility, - }, - shouldCopyFiltersAndSortsAndAggregate, - ); - - if (isDefined(createdViewId)) { - closeAndResetViewPicker(); - changeView(createdViewId); - } - }, - [ - closeAndResetViewPicker, - createViewFromCurrentView, - changeView, - viewPickerInputNameCallbackState, - viewPickerIsDirtyCallbackState, - viewPickerIsPersistingCallbackState, + const createViewFromCurrentState = useCallback(async () => { + const name = store.get(viewPickerInputNameCallbackState); + const iconKey = store.get(viewPickerSelectedIconCallbackState); + const type = store.get(viewPickerTypeCallbackState); + const mainGroupByFieldMetadataId = store.get( viewPickerMainGroupByFieldMetadataIdCallbackState, + ); + const calendarFieldMetadataId = store.get( viewPickerCalendarFieldMetadataIdCallbackState, - viewPickerSelectedIconCallbackState, - viewPickerTypeCallbackState, - viewPickerModeCallbackState, - viewPickerVisibilityCallbackState, - ], - ); + ); + + const viewPickerMode = store.get(viewPickerModeCallbackState); + const visibility = store.get(viewPickerVisibilityCallbackState); + + const shouldCopyFiltersAndSortsAndAggregate = + viewPickerMode === 'create-from-current'; + + store.set(viewPickerIsPersistingCallbackState, true); + store.set(viewPickerIsDirtyCallbackState, false); + + const createdViewId = await createViewFromCurrentView( + { + name, + icon: iconKey, + type, + mainGroupByFieldMetadataId: + type === ViewType.Kanban ? mainGroupByFieldMetadataId : null, + calendarFieldMetadataId, + visibility, + }, + shouldCopyFiltersAndSortsAndAggregate, + ); + + if (isDefined(createdViewId)) { + closeAndResetViewPicker(); + changeView(createdViewId); + } + }, [ + store, + closeAndResetViewPicker, + createViewFromCurrentView, + changeView, + viewPickerInputNameCallbackState, + viewPickerIsDirtyCallbackState, + viewPickerIsPersistingCallbackState, + viewPickerMainGroupByFieldMetadataIdCallbackState, + viewPickerCalendarFieldMetadataIdCallbackState, + viewPickerSelectedIconCallbackState, + viewPickerTypeCallbackState, + viewPickerModeCallbackState, + viewPickerVisibilityCallbackState, + ]); return { createViewFromCurrentState }; }; diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useDestroyViewFromCurrentState.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useDestroyViewFromCurrentState.ts index 159be0740c..fcbe169831 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useDestroyViewFromCurrentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useDestroyViewFromCurrentState.ts @@ -1,15 +1,14 @@ -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { usePerformViewAPIPersist } from '@/views/hooks/internal/usePerformViewAPIPersist'; import { useChangeView } from '@/views/hooks/useChangeView'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { coreViewsByObjectMetadataIdFamilySelector } from '@/views/states/selectors/coreViewsByObjectMetadataIdFamilySelector'; import { coreViewsFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreViewsFromObjectMetadataItemFamilySelector'; -import { useStore } from 'jotai'; import { useCloseAndResetViewPicker } from '@/views/view-picker/hooks/useCloseAndResetViewPicker'; import { viewPickerIsDirtyComponentState } from '@/views/view-picker/states/viewPickerIsDirtyComponentState'; import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states/viewPickerIsPersistingComponentState'; @@ -18,18 +17,19 @@ import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/sta export const useDestroyViewFromCurrentState = (viewBarInstanceId?: string) => { const { closeAndResetViewPicker } = useCloseAndResetViewPicker(); - const viewPickerIsPersistingCallbackState = useRecoilComponentCallbackState( - viewPickerIsPersistingComponentState, - viewBarInstanceId, - ); + const viewPickerIsPersistingCallbackState = + useRecoilComponentStateCallbackStateV2( + viewPickerIsPersistingComponentState, + viewBarInstanceId, + ); - const viewPickerIsDirtyCallbackState = useRecoilComponentCallbackState( + const viewPickerIsDirtyCallbackState = useRecoilComponentStateCallbackStateV2( viewPickerIsDirtyComponentState, viewBarInstanceId, ); const viewPickerReferenceViewIdCallbackState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( viewPickerReferenceViewIdComponentState, viewBarInstanceId, ); @@ -49,51 +49,45 @@ export const useDestroyViewFromCurrentState = (viewBarInstanceId?: string) => { const store = useStore(); - const destroyViewFromCurrentState = useRecoilCallback( - ({ set, snapshot }) => - async () => { - set(viewPickerIsPersistingCallbackState, true); - closeAndResetViewPicker(); - set(viewPickerIsDirtyCallbackState, false); + const destroyViewFromCurrentState = useCallback(async () => { + store.set(viewPickerIsPersistingCallbackState, true); + closeAndResetViewPicker(); + store.set(viewPickerIsDirtyCallbackState, false); - const viewPickerReferenceViewId = getSnapshotValue( - snapshot, - viewPickerReferenceViewIdCallbackState, - ); - - const shouldChangeView = viewPickerReferenceViewId === currentView?.id; - - if (shouldChangeView) { - changeView( - viewsOnCurrentObject.filter( - (view) => view.id !== viewPickerReferenceViewId, - )[0].id, - ); - } - - store.set( - coreViewsByObjectMetadataIdFamilySelector.selectorFamily( - objectMetadataItem.id, - ), - (views) => - views.filter((view) => view.id !== viewPickerReferenceViewId), - ); - - await performViewAPIDestroy({ id: viewPickerReferenceViewId }); - }, - [ - currentView, - closeAndResetViewPicker, - objectMetadataItem.id, - changeView, - performViewAPIDestroy, - store, - viewPickerIsDirtyCallbackState, - viewPickerIsPersistingCallbackState, + const viewPickerReferenceViewId = store.get( viewPickerReferenceViewIdCallbackState, - viewsOnCurrentObject, - ], - ); + ); + + const shouldChangeView = viewPickerReferenceViewId === currentView?.id; + + if (shouldChangeView) { + changeView( + viewsOnCurrentObject.filter( + (view) => view.id !== viewPickerReferenceViewId, + )[0].id, + ); + } + + store.set( + coreViewsByObjectMetadataIdFamilySelector.selectorFamily( + objectMetadataItem.id, + ), + (views) => views.filter((view) => view.id !== viewPickerReferenceViewId), + ); + + await performViewAPIDestroy({ id: viewPickerReferenceViewId }); + }, [ + currentView, + closeAndResetViewPicker, + objectMetadataItem.id, + changeView, + performViewAPIDestroy, + store, + viewPickerIsDirtyCallbackState, + viewPickerIsPersistingCallbackState, + viewPickerReferenceViewIdCallbackState, + viewsOnCurrentObject, + ]); return { destroyViewFromCurrentState, 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 7a7ef19134..02676cf2f4 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 @@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom'; 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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; import { FieldMetadataType, SettingsPath } from 'twenty-shared/types'; @@ -12,7 +12,7 @@ import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; export const useGetAvailableFieldsForCalendar = () => { - const viewObjectMetadataId = useRecoilComponentValue( + const viewObjectMetadataId = useRecoilComponentValueV2( viewObjectMetadataIdComponentState, ); const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); 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 d3c3144217..9719705d28 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 @@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom'; 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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; import { SettingsPath } from 'twenty-shared/types'; @@ -13,7 +13,7 @@ import { FieldMetadataType } from '~/generated-metadata/graphql'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; export const useGetAvailableFieldsToGroupRecordsBy = () => { - const viewObjectMetadataId = useRecoilComponentValue( + const viewObjectMetadataId = useRecoilComponentValueV2( viewObjectMetadataIdComponentState, ); const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useUpdateViewFromCurrentState.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useUpdateViewFromCurrentState.ts index 74c2ceb1c7..126b701ca8 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useUpdateViewFromCurrentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useUpdateViewFromCurrentState.ts @@ -1,5 +1,7 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useCallback } from 'react'; +import { useStore } from 'jotai'; + +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate'; import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges'; import { useCloseAndResetViewPicker } from '@/views/view-picker/hooks/useCloseAndResetViewPicker'; @@ -9,87 +11,79 @@ import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState'; import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState'; import { viewPickerVisibilityComponentState } from '@/views/view-picker/states/viewPickerVisibilityComponentState'; -import { useRecoilCallback } from 'recoil'; export const useUpdateViewFromCurrentState = () => { const { canPersistChanges } = useCanPersistViewChanges(); const { closeAndResetViewPicker } = useCloseAndResetViewPicker(); - const viewPickerInputNameCallbackState = useRecoilComponentCallbackState( - viewPickerInputNameComponentState, - ); + const viewPickerInputNameCallbackState = + useRecoilComponentStateCallbackStateV2(viewPickerInputNameComponentState); - const viewPickerSelectedIconCallbackState = useRecoilComponentCallbackState( - viewPickerSelectedIconComponentState, - ); + const viewPickerSelectedIconCallbackState = + useRecoilComponentStateCallbackStateV2( + viewPickerSelectedIconComponentState, + ); - const viewPickerIsPersistingCallbackState = useRecoilComponentCallbackState( - viewPickerIsPersistingComponentState, - ); + const viewPickerIsPersistingCallbackState = + useRecoilComponentStateCallbackStateV2( + viewPickerIsPersistingComponentState, + ); - const viewPickerIsDirtyCallbackState = useRecoilComponentCallbackState( + const viewPickerIsDirtyCallbackState = useRecoilComponentStateCallbackStateV2( viewPickerIsDirtyComponentState, ); const viewPickerReferenceViewIdCallbackState = - useRecoilComponentCallbackState(viewPickerReferenceViewIdComponentState); + useRecoilComponentStateCallbackStateV2( + viewPickerReferenceViewIdComponentState, + ); - const viewPickerVisibilityCallbackState = useRecoilComponentCallbackState( - viewPickerVisibilityComponentState, - ); + const viewPickerVisibilityCallbackState = + useRecoilComponentStateCallbackStateV2(viewPickerVisibilityComponentState); const { performViewAPIUpdate } = usePerformViewAPIUpdate(); - const updateViewFromCurrentState = useRecoilCallback( - ({ set, snapshot }) => - async () => { - if (!canPersistChanges) { - closeAndResetViewPicker(); - return; - } + const store = useStore(); - set(viewPickerIsPersistingCallbackState, true); - set(viewPickerIsDirtyCallbackState, false); - closeAndResetViewPicker(); + const updateViewFromCurrentState = useCallback(async () => { + if (!canPersistChanges) { + closeAndResetViewPicker(); + return; + } - const viewPickerReferenceViewId = getSnapshotValue( - snapshot, - viewPickerReferenceViewIdCallbackState, - ); - const viewPickerInputName = getSnapshotValue( - snapshot, - viewPickerInputNameCallbackState, - ); - const viewPickerSelectedIcon = getSnapshotValue( - snapshot, - viewPickerSelectedIconCallbackState, - ); - const visibility = getSnapshotValue( - snapshot, - viewPickerVisibilityCallbackState, - ); + store.set(viewPickerIsPersistingCallbackState, true); + store.set(viewPickerIsDirtyCallbackState, false); + closeAndResetViewPicker(); - await performViewAPIUpdate({ - id: viewPickerReferenceViewId, - input: { - name: viewPickerInputName, - icon: viewPickerSelectedIcon, - visibility: visibility, - }, - }); - }, - [ - canPersistChanges, - viewPickerIsPersistingCallbackState, - viewPickerIsDirtyCallbackState, - closeAndResetViewPicker, + const viewPickerReferenceViewId = store.get( viewPickerReferenceViewIdCallbackState, - viewPickerInputNameCallbackState, + ); + const viewPickerInputName = store.get(viewPickerInputNameCallbackState); + const viewPickerSelectedIcon = store.get( viewPickerSelectedIconCallbackState, - viewPickerVisibilityCallbackState, - performViewAPIUpdate, - ], - ); + ); + const visibility = store.get(viewPickerVisibilityCallbackState); + + await performViewAPIUpdate({ + id: viewPickerReferenceViewId, + input: { + name: viewPickerInputName, + icon: viewPickerSelectedIcon, + visibility: visibility, + }, + }); + }, [ + canPersistChanges, + viewPickerIsPersistingCallbackState, + viewPickerIsDirtyCallbackState, + closeAndResetViewPicker, + viewPickerReferenceViewIdCallbackState, + viewPickerInputNameCallbackState, + viewPickerSelectedIconCallbackState, + viewPickerVisibilityCallbackState, + performViewAPIUpdate, + store, + ]); return { updateViewFromCurrentState, diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerMode.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerMode.ts index ef27c65f28..7f7e5a4a72 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerMode.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useViewPickerMode.ts @@ -1,8 +1,8 @@ -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { viewPickerModeComponentState } from '@/views/view-picker/states/viewPickerModeComponentState'; export const useViewPickerMode = (viewBarComponentId?: string) => { - const [viewPickerMode, setViewPickerMode] = useRecoilComponentState( + const [viewPickerMode, setViewPickerMode] = useRecoilComponentStateV2( viewPickerModeComponentState, viewBarComponentId, ); diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerCalendarFieldMetadataIdComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerCalendarFieldMetadataIdComponentState.ts index 14cb8dfd67..cd6bf515a6 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerCalendarFieldMetadataIdComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerCalendarFieldMetadataIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const viewPickerCalendarFieldMetadataIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerCalendarFieldMetadataIdComponentState', defaultValue: '', componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerInputNameComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerInputNameComponentState.ts index cdcb13ea31..c80c7bd948 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerInputNameComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerInputNameComponentState.ts @@ -1,8 +1,10 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -export const viewPickerInputNameComponentState = createComponentState({ - key: 'viewPickerInputNameComponentState', - defaultValue: '', - componentInstanceContext: ViewComponentInstanceContext, -}); +export const viewPickerInputNameComponentState = createComponentStateV2( + { + key: 'viewPickerInputNameComponentState', + defaultValue: '', + componentInstanceContext: ViewComponentInstanceContext, + }, +); diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts index 8107a71d05..be881283ba 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsDirtyComponentState.ts @@ -1,7 +1,7 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; -export const viewPickerIsDirtyComponentState = createComponentState({ +export const viewPickerIsDirtyComponentState = createComponentStateV2({ key: 'viewPickerIsDirtyComponentState', defaultValue: false, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsPersistingComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsPersistingComponentState.ts index 1cdec7d8dc..ec321e2dad 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsPersistingComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerIsPersistingComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const viewPickerIsPersistingComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerIsPersistingComponentState', defaultValue: false, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerMainGroupByFieldMetadataIdComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerMainGroupByFieldMetadataIdComponentState.ts index 3af0ece3c5..01bf81811b 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerMainGroupByFieldMetadataIdComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerMainGroupByFieldMetadataIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const viewPickerMainGroupByFieldMetadataIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerMainGroupByFieldMetadataIdComponentState', defaultValue: '', componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerModeComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerModeComponentState.ts index 6ad5b692c2..6ede272f8f 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerModeComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerModeComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { type ViewPickerMode } from '@/views/view-picker/types/ViewPickerMode'; export const viewPickerModeComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerModeComponentState', defaultValue: 'list', componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerReferenceViewIdComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerReferenceViewIdComponentState.ts index 0f5bc44d46..ee7dbbec68 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerReferenceViewIdComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerReferenceViewIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const viewPickerReferenceViewIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerReferenceViewIdComponentState', defaultValue: '', componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerSelectedIconComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerSelectedIconComponentState.ts index 5deb21acf9..b53bb9a692 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerSelectedIconComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerSelectedIconComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const viewPickerSelectedIconComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerSelectedIconComponentState', defaultValue: '', componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerTypeComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerTypeComponentState.ts index b810d42b98..182c71948b 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerTypeComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerTypeComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewType } from '@/views/types/ViewType'; -export const viewPickerTypeComponentState = createComponentState({ +export const viewPickerTypeComponentState = createComponentStateV2({ key: 'viewPickerTypeComponentState', defaultValue: ViewType.Table, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerVisibilityComponentState.ts b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerVisibilityComponentState.ts index ac6c561a27..3e00317c53 100644 --- a/packages/twenty-front/src/modules/views/view-picker/states/viewPickerVisibilityComponentState.ts +++ b/packages/twenty-front/src/modules/views/view-picker/states/viewPickerVisibilityComponentState.ts @@ -1,9 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewVisibility } from '~/generated-metadata/graphql'; export const viewPickerVisibilityComponentState = - createComponentState({ + createComponentStateV2({ key: 'viewPickerVisibilityComponentState', defaultValue: ViewVisibility.UNLISTED, componentInstanceContext: ViewComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts index 502920298c..8e4a609526 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts @@ -1,9 +1,9 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import { isDefined } from 'twenty-shared/utils'; export const useFlowOrThrow = () => { - const flow = useRecoilComponentValue(flowComponentState); + const flow = useRecoilComponentValueV2(flowComponentState); if (!isDefined(flow)) { throw new Error('Expected the flow to be defined'); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts index 05e1e72d23..f177380b06 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useCreateDraftFromWorkflowVersion } from '@/workflow/hooks/useCreateDraftFromWorkflowVersion'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; @@ -7,7 +7,7 @@ import { isDefined } from 'twenty-shared/utils'; export const useGetUpdatableWorkflowVersionOrThrow = (instanceId?: string) => { const { createDraftFromWorkflowVersion } = useCreateDraftFromWorkflowVersion(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, instanceId, ); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts index af7637b669..27d58fbaa5 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts @@ -14,7 +14,7 @@ import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/work import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram'; import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -25,102 +25,93 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => { const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); - const runWorkflowRunOpeningInCommandMenuSideEffects = useRecoilCallback( - ({ set }) => - ({ + const runWorkflowRunOpeningInCommandMenuSideEffects = useCallback( + ({ + objectMetadataItem, + recordId, + }: { + objectMetadataItem: ObjectMetadataItem; + recordId: string; + }) => { + const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom); + + const workflowRunRecord = getRecordFromCache({ objectMetadataItem, + cache: apolloCoreClient.cache, recordId, - }: { - objectMetadataItem: ObjectMetadataItem; - recordId: string; - }) => { - const objectMetadataItems = jotaiStore.get( - objectMetadataItemsState.atom, - ); + objectMetadataItems, + objectPermissionsByObjectMetadataId, + }); + if ( + !(isDefined(workflowRunRecord) && isDefined(workflowRunRecord.state)) + ) { + return; + } - const workflowRunRecord = getRecordFromCache({ - objectMetadataItem, - cache: apolloCoreClient.cache, - recordId, - objectMetadataItems, - objectPermissionsByObjectMetadataId, - }); - if ( - !(isDefined(workflowRunRecord) && isDefined(workflowRunRecord.state)) - ) { - return; - } + const { stepToOpenByDefault } = generateWorkflowRunDiagram({ + steps: workflowRunRecord.state.flow.steps, + stepInfos: workflowRunRecord.state.stepInfos, + trigger: workflowRunRecord.state.flow.trigger, + }); - const { stepToOpenByDefault } = generateWorkflowRunDiagram({ - steps: workflowRunRecord.state.flow.steps, - stepInfos: workflowRunRecord.state.stepInfos, + if (!isDefined(stepToOpenByDefault)) { + return; + } + + const instanceId = getWorkflowVisualizerComponentInstanceId({ + recordId, + }); + + jotaiStore.set( + workflowVisualizerWorkflowRunIdComponentState.atomFamily({ + instanceId, + }), + workflowRunRecord.id, + ); + jotaiStore.set( + workflowVisualizerWorkflowIdComponentState.atomFamily({ + instanceId, + }), + workflowRunRecord.workflowId, + ); + jotaiStore.set( + flowComponentState.atomFamily({ + instanceId, + }), + { + workflowVersionId: workflowRunRecord.workflowVersionId, trigger: workflowRunRecord.state.flow.trigger, - }); + steps: workflowRunRecord.state.flow.steps, + }, + ); + jotaiStore.set( + workflowSelectedNodeComponentState.atomFamily({ + instanceId, + }), + stepToOpenByDefault.id, + ); - if (!isDefined(stepToOpenByDefault)) { - return; - } - - set( - workflowVisualizerWorkflowRunIdComponentState.atomFamily({ - instanceId: getWorkflowVisualizerComponentInstanceId({ - recordId, - }), - }), - workflowRunRecord.id, - ); - set( - workflowVisualizerWorkflowIdComponentState.atomFamily({ - instanceId: getWorkflowVisualizerComponentInstanceId({ - recordId, - }), - }), - workflowRunRecord.workflowId, - ); - set( - flowComponentState.atomFamily({ - instanceId: getWorkflowVisualizerComponentInstanceId({ - recordId, - }), - }), + jotaiStore.set( + workflowRunDiagramAutomaticallyOpenedStepsComponentState.atomFamily({ + instanceId, + }), + (steps) => [ + ...steps, { - workflowVersionId: workflowRunRecord.workflowVersionId, - trigger: workflowRunRecord.state.flow.trigger, - steps: workflowRunRecord.state.flow.steps, + stepId: stepToOpenByDefault.id, + isInRightDrawer: true, }, - ); - set( - workflowSelectedNodeComponentState.atomFamily({ - instanceId: getWorkflowVisualizerComponentInstanceId({ - recordId, - }), - }), - stepToOpenByDefault.id, - ); - - set( - workflowRunDiagramAutomaticallyOpenedStepsComponentState.atomFamily({ - instanceId: getWorkflowVisualizerComponentInstanceId({ - recordId, - }), - }), - (steps) => [ - ...steps, - { - stepId: stepToOpenByDefault.id, - isInRightDrawer: true, - }, - ], - ); - openWorkflowRunViewStepInCommandMenu({ - workflowId: workflowRunRecord.workflowId, - workflowRunId: workflowRunRecord.id, - title: stepToOpenByDefault.data.name, - icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)), - workflowSelectedNode: stepToOpenByDefault.id, - stepExecutionStatus: stepToOpenByDefault.data.runStatus, - }); - }, + ], + ); + openWorkflowRunViewStepInCommandMenu({ + workflowId: workflowRunRecord.workflowId, + workflowRunId: workflowRunRecord.id, + title: stepToOpenByDefault.data.name, + icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)), + workflowSelectedNode: stepToOpenByDefault.id, + stepExecutionStatus: stepToOpenByDefault.data.runStatus, + }); + }, [ apolloCoreClient.cache, objectPermissionsByObjectMetadataId, diff --git a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.tsx b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.tsx index 557c0146ee..9da8c4186f 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.tsx +++ b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.tsx @@ -13,13 +13,14 @@ import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graph import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { computeOptimisticCreateRecordBaseRecordInput } from '@/object-record/utils/computeOptimisticCreateRecordBaseRecordInput'; import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput'; import { RUN_WORKFLOW_VERSION } from '@/workflow/graphql/mutations/runWorkflowVersion'; import { type WorkflowRun } from '@/workflow/types/Workflow'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; +import { useCallback } from 'react'; import { useMutation } from '@apollo/client'; -import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { @@ -62,13 +63,12 @@ export const useRunWorkflowVersion = () => { const { openRecordInCommandMenu } = useOpenRecordInCommandMenu(); - const setRecordInStore = useRecoilCallback( - ({ set }) => - (workflowRun: WorkflowRun) => { - set(recordStoreFamilyState(workflowRun.id), workflowRun); - }, - [], - ); + const setRecordInStore = useCallback((workflowRun: WorkflowRun) => { + jotaiStore.set( + recordStoreFamilyState.atomFamily(workflowRun.id), + workflowRun, + ); + }, []); const runWorkflowVersion = async ({ workflowId, diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts index 061304827e..2e8c0fc91b 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts @@ -1,9 +1,9 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState'; import { isDefined } from 'twenty-shared/utils'; export const useWorkflowRunIdOrThrow = () => { - const workflowRunId = useRecoilComponentValue( + const workflowRunId = useRecoilComponentValueV2( workflowVisualizerWorkflowRunIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts index f21d83cb08..6b442561d3 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts @@ -1,9 +1,9 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; import { isDefined } from 'twenty-shared/utils'; export const useWorkflowVersionIdOrThrow = () => { - const workflowVersionId = useRecoilComponentValue( + const workflowVersionId = useRecoilComponentValueV2( workflowVisualizerWorkflowVersionIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts index ecf01b19fb..b52e4d617f 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowWithCurrentVersion.ts @@ -1,8 +1,9 @@ import { useEffect } from 'react'; -import { useRecoilState } from 'recoil'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { shouldWorkflowRefetchRequestFamilyState } from '@/workflow/states/shouldWorkflowRefetchRequestFamilyState'; import { type Workflow, @@ -20,8 +21,14 @@ type WorkflowWithAllVersions = Omit & { export const useWorkflowWithCurrentVersion = ( workflowId: string | undefined, ): WorkflowWithCurrentVersion | undefined => { - const [shouldWorkflowRefetchRequest, setShouldWorkflowRefetchRequest] = - useRecoilState(shouldWorkflowRefetchRequestFamilyState(workflowId ?? '')); + const shouldWorkflowRefetchRequest = useFamilyRecoilValueV2( + shouldWorkflowRefetchRequestFamilyState, + workflowId ?? '', + ); + const setShouldWorkflowRefetchRequest = useSetFamilyRecoilStateV2( + shouldWorkflowRefetchRequestFamilyState, + workflowId ?? '', + ); const { record: workflow, refetch: refetchWorkflow } = useFindOneRecord({ diff --git a/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts b/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts index c87ba9983a..422feb8385 100644 --- a/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts @@ -1,11 +1,11 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { type WorkflowAction, type WorkflowTrigger, } from '@/workflow/types/Workflow'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; -export const flowComponentState = createComponentState< +export const flowComponentState = createComponentStateV2< | { workflowVersionId: string; trigger: WorkflowTrigger | null; diff --git a/packages/twenty-front/src/modules/workflow/states/selectors/stepSelector.ts b/packages/twenty-front/src/modules/workflow/states/selectors/stepSelector.ts index 334747cb35..6c7f2fb25d 100644 --- a/packages/twenty-front/src/modules/workflow/states/selectors/stepSelector.ts +++ b/packages/twenty-front/src/modules/workflow/states/selectors/stepSelector.ts @@ -1,16 +1,16 @@ -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import type { WorkflowAction } from '@/workflow/types/Workflow'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { isDefined } from 'twenty-shared/utils'; export const createStepSelector = (stepId: string) => - createComponentSelector({ + createComponentSelectorV2({ key: `stepSelector-${stepId}`, get: - ({ instanceId }) => + (componentStateKey) => ({ get }) => { - const flowState = get(flowComponentState.atomFamily({ instanceId })); + const flowState = get(flowComponentState, componentStateKey); if (!isDefined(flowState) || !isDefined(flowState.steps)) { return null; diff --git a/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts b/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts index 4ea7da42d2..2b7987ffe6 100644 --- a/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts +++ b/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts @@ -1,10 +1,10 @@ +import { createFamilySelectorV2 } from '@/ui/utilities/state/jotai/utils/createFamilySelectorV2'; import { getStepOutputSchemaFamilyStateKey } from '@/workflow/utils/getStepOutputSchemaFamilyStateKey'; import { stepsOutputSchemaFamilyState } from '@/workflow/workflow-variables/states/stepsOutputSchemaFamilyState'; import { type StepOutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2'; -import { selectorFamily } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; -export const stepsOutputSchemaFamilySelector = selectorFamily< +export const stepsOutputSchemaFamilySelector = createFamilySelectorV2< StepOutputSchemaV2[], { workflowVersionId: string; stepIds: string[] } >({ @@ -17,7 +17,7 @@ export const stepsOutputSchemaFamilySelector = selectorFamily< getStepOutputSchemaFamilyStateKey(workflowVersionId, stepId), ) .map((stepOutputSchemaKey) => - get(stepsOutputSchemaFamilyState(stepOutputSchemaKey)), + get(stepsOutputSchemaFamilyState, stepOutputSchemaKey), ) .filter(isDefined); diff --git a/packages/twenty-front/src/modules/workflow/states/shouldWorkflowRefetchRequestFamilyState.ts b/packages/twenty-front/src/modules/workflow/states/shouldWorkflowRefetchRequestFamilyState.ts index 98988fd045..646c0c60c8 100644 --- a/packages/twenty-front/src/modules/workflow/states/shouldWorkflowRefetchRequestFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/states/shouldWorkflowRefetchRequestFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const shouldWorkflowRefetchRequestFamilyState = createFamilyState< +export const shouldWorkflowRefetchRequestFamilyState = createFamilyStateV2< boolean, string >({ diff --git a/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts index 77655fd838..f1696cec50 100644 --- a/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts @@ -1,7 +1,7 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; -export const workflowLastCreatedStepIdComponentState = createComponentState< +export const workflowLastCreatedStepIdComponentState = createComponentStateV2< string | undefined >({ key: 'workflowLastCreatedStepIdComponentState', diff --git a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts index aa615b9e84..6fb77afffa 100644 --- a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts @@ -1,10 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; -export const workflowVisualizerWorkflowIdComponentState = createComponentState< - string | undefined ->({ - key: 'workflowVisualizerWorkflowIdComponentState', - defaultValue: undefined, - componentInstanceContext: WorkflowVisualizerComponentInstanceContext, -}); +export const workflowVisualizerWorkflowIdComponentState = + createComponentStateV2({ + key: 'workflowVisualizerWorkflowIdComponentState', + defaultValue: undefined, + componentInstanceContext: WorkflowVisualizerComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts index 6564f15b23..bee706400b 100644 --- a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; export const workflowVisualizerWorkflowRunIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowVisualizerWorkflowRunIdComponentState', defaultValue: undefined, componentInstanceContext: WorkflowVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts index bbb52e8538..1b78268b39 100644 --- a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; export const workflowVisualizerWorkflowVersionIdComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowVisualizerWorkflowVersionIdComponentState', defaultValue: undefined, componentInstanceContext: WorkflowVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx index e9a1e5e9be..359f7f4509 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx @@ -1,11 +1,11 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { commandMenuWidthState } from '@/command-menu/states/commandMenuWidthState'; import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuOpenedStateV2'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { useListenToSidePanelClosing } from '@/ui/layout/right-drawer/hooks/useListenToSidePanelClosing'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { WorkflowDiagramRightClickCommandMenu } from '@/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu'; import { WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEmptyNodeDefinition'; import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds'; @@ -61,7 +61,6 @@ import React, { useRef, useState, } from 'react'; -import { useRecoilCallback } from 'recoil'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; import { Tag, type TagColor } from 'twenty-ui/components'; @@ -170,31 +169,31 @@ export const WorkflowDiagramCanvasBase = ({ const reactflow = useReactFlow(); - const workflowDiagram = useRecoilComponentValue( + const workflowDiagram = useRecoilComponentValueV2( workflowDiagramComponentState, ); - const workflowDiagramPanOnDrag = useRecoilComponentValue( + const workflowDiagramPanOnDrag = useRecoilComponentValueV2( workflowDiagramPanOnDragComponentState, ); - const workflowDiagramState = useRecoilComponentCallbackState( + const workflowDiagramAtom = useRecoilComponentStateCallbackStateV2( workflowDiagramComponentState, ); - const setWorkflowDiagram = useSetRecoilComponentState( + const setWorkflowDiagram = useSetRecoilComponentStateV2( workflowDiagramComponentState, ); - const setWorkflowSelectedNode = useSetRecoilComponentState( + const setWorkflowSelectedNode = useSetRecoilComponentStateV2( workflowSelectedNodeComponentState, ); const { resetWorkflowInsertStepIds } = useResetWorkflowInsertStepIds(); - const workflowDiagramWaitingNodesDimensionsState = - useRecoilComponentCallbackState( + const workflowDiagramWaitingNodesDimensionsAtom = + useRecoilComponentStateCallbackStateV2( workflowDiagramWaitingNodesDimensionsComponentState, ); - const setWorkflowDiagramWaitingNodesDimensions = useSetRecoilComponentState( + const setWorkflowDiagramWaitingNodesDimensions = useSetRecoilComponentStateV2( workflowDiagramWaitingNodesDimensionsComponentState, ); - const workflowInsertStepIds = useRecoilComponentValue( + const workflowInsertStepIds = useRecoilComponentValueV2( workflowInsertStepIdsComponentState, ); @@ -284,91 +283,83 @@ export const WorkflowDiagramCanvasBase = ({ const containerRef = useRef(null); - const setFlowViewport = useRecoilCallback( - ({ snapshot }) => - ({ - workflowDiagramFlowInitialized, - isCommandMenuOpened, - workflowDiagram, - isInRightDrawer, - }: { - workflowDiagramFlowInitialized: boolean; - isCommandMenuOpened: boolean; - workflowDiagram: WorkflowDiagram | undefined; - isInRightDrawer: boolean; - }) => { - if ( - !isDefined(containerRef.current) || - !workflowDiagramFlowInitialized - ) { - return; - } + const setFlowViewport = useCallback( + ({ + workflowDiagramFlowInitialized, + isCommandMenuOpened, + workflowDiagram, + isInRightDrawer, + }: { + workflowDiagramFlowInitialized: boolean; + isCommandMenuOpened: boolean; + workflowDiagram: WorkflowDiagram | undefined; + isInRightDrawer: boolean; + }) => { + if (!isDefined(containerRef.current) || !workflowDiagramFlowInitialized) { + return; + } - const currentViewport = reactflow.getViewport(); - const nodes = workflowDiagram?.nodes ?? []; + const currentViewport = reactflow.getViewport(); + const nodes = workflowDiagram?.nodes ?? []; - const canComputeNodesBounds = nodes.every((node) => - isDefined(node.measured), - ); + const canComputeNodesBounds = nodes.every((node) => + isDefined(node.measured), + ); - if (!canComputeNodesBounds) { - setWorkflowDiagramWaitingNodesDimensions(true); - return; - } + if (!canComputeNodesBounds) { + setWorkflowDiagramWaitingNodesDimensions(true); + return; + } - setWorkflowDiagramWaitingNodesDimensions(false); + setWorkflowDiagramWaitingNodesDimensions(false); - const baseContainerWidth = containerRef.current.offsetWidth; - const hasViewportBeenMoved = currentViewport.x !== 0; + const baseContainerWidth = containerRef.current.offsetWidth; + const hasViewportBeenMoved = currentViewport.x !== 0; - let adjustedContainerWidth = baseContainerWidth; + let adjustedContainerWidth = baseContainerWidth; - const commandMenuWidth = getSnapshotValue( - snapshot, - commandMenuWidthState, - ); + const commandMenuWidth = jotaiStore.get(commandMenuWidthState.atom); - if (!isInRightDrawer && isCommandMenuOpened) { - adjustedContainerWidth = baseContainerWidth - commandMenuWidth; - } else if (!isInRightDrawer && hasViewportBeenMoved) { - adjustedContainerWidth = baseContainerWidth + commandMenuWidth; - } + if (!isInRightDrawer && isCommandMenuOpened) { + adjustedContainerWidth = baseContainerWidth - commandMenuWidth; + } else if (!isInRightDrawer && hasViewportBeenMoved) { + adjustedContainerWidth = baseContainerWidth + commandMenuWidth; + } - const flowBounds = reactflow.getNodesBounds(nodes); - const centeredXPosition = - adjustedContainerWidth / 2 - flowBounds.width / 2; + const flowBounds = reactflow.getNodesBounds(nodes); + const centeredXPosition = + adjustedContainerWidth / 2 - flowBounds.width / 2; - reactflow.setViewport( - { - ...currentViewport, - x: centeredXPosition, - zoom: defaultFitViewOptions.maxZoom, - }, - { duration: hasViewportBeenMoved ? 300 : 0 }, - ); - }, + reactflow.setViewport( + { + ...currentViewport, + x: centeredXPosition, + zoom: defaultFitViewOptions.maxZoom, + }, + { duration: hasViewportBeenMoved ? 300 : 0 }, + ); + }, [reactflow, setWorkflowDiagramWaitingNodesDimensions], ); - const handleSetFlowViewportOnChange = useRecoilCallback( - ({ snapshot }) => - ({ - workflowDiagramFlowInitialized, - isCommandMenuOpened, + const handleSetFlowViewportOnChange = useCallback( + ({ + workflowDiagramFlowInitialized, + isCommandMenuOpened, + isInRightDrawer, + }: { + workflowDiagramFlowInitialized: boolean; + isCommandMenuOpened: boolean; + isInRightDrawer: boolean; + }) => { + setFlowViewport({ isInRightDrawer, - }: { - workflowDiagramFlowInitialized: boolean; - isCommandMenuOpened: boolean; - isInRightDrawer: boolean; - }) => { - setFlowViewport({ - isInRightDrawer, - isCommandMenuOpened, - workflowDiagramFlowInitialized, - workflowDiagram: getSnapshotValue(snapshot, workflowDiagramState), - }); - }, - [setFlowViewport, workflowDiagramState], + isCommandMenuOpened, + workflowDiagramFlowInitialized, + workflowDiagram: jotaiStore.get(workflowDiagramAtom), + }); + }, + [setFlowViewport, workflowDiagramAtom], ); useEffect(() => { @@ -384,53 +375,48 @@ export const WorkflowDiagramCanvasBase = ({ isInRightDrawer, ]); - const handleNodesChanges = useRecoilCallback( - ({ snapshot, set }) => - (changes: NodeChange[]) => { - const workflowDiagram = getSnapshotValue( - snapshot, - workflowDiagramState, - ); + const handleNodesChanges = useCallback( + (changes: NodeChange[]) => { + const workflowDiagram = jotaiStore.get(workflowDiagramAtom); - const filteredChanges = changes.filter( - (change) => - !( - 'id' in change && - change.id === WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION.id - ), - ); + const filteredChanges = changes.filter( + (change) => + !( + 'id' in change && + change.id === WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION.id + ), + ); - let updatedWorkflowDiagram = workflowDiagram; - if (isDefined(workflowDiagram) && filteredChanges.length > 0) { - updatedWorkflowDiagram = { - ...workflowDiagram, - nodes: applyNodeChanges(filteredChanges, workflowDiagram.nodes), - }; - } + let updatedWorkflowDiagram = workflowDiagram; + if (isDefined(workflowDiagram) && filteredChanges.length > 0) { + updatedWorkflowDiagram = { + ...workflowDiagram, + nodes: applyNodeChanges(filteredChanges, workflowDiagram.nodes), + }; + } - set(workflowDiagramState, updatedWorkflowDiagram); + jotaiStore.set(workflowDiagramAtom, updatedWorkflowDiagram); - const workflowDiagramWaitingNodesDimensions = getSnapshotValue( - snapshot, - workflowDiagramWaitingNodesDimensionsState, - ); - if (!workflowDiagramWaitingNodesDimensions) { - return; - } + const workflowDiagramWaitingNodesDimensions = jotaiStore.get( + workflowDiagramWaitingNodesDimensionsAtom, + ); + if (!workflowDiagramWaitingNodesDimensions) { + return; + } - setFlowViewport({ - isCommandMenuOpened, - workflowDiagramFlowInitialized, - workflowDiagram: updatedWorkflowDiagram, - isInRightDrawer, - }); - }, + setFlowViewport({ + isCommandMenuOpened, + workflowDiagramFlowInitialized, + workflowDiagram: updatedWorkflowDiagram, + isInRightDrawer, + }); + }, [ isCommandMenuOpened, setFlowViewport, workflowDiagramFlowInitialized, - workflowDiagramState, - workflowDiagramWaitingNodesDimensionsState, + workflowDiagramAtom, + workflowDiagramWaitingNodesDimensionsAtom, isInRightDrawer, ], ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx index 23994314fb..e4b7fd1701 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx @@ -1,5 +1,5 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase'; @@ -35,7 +35,7 @@ import React, { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const WorkflowDiagramCanvasEditable = () => { - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); @@ -43,11 +43,11 @@ export const WorkflowDiagramCanvasEditable = () => { workflowVisualizerWorkflowId, ); - const setWorkflowDiagram = useSetRecoilComponentState( + const setWorkflowDiagram = useSetRecoilComponentStateV2( workflowDiagramComponentState, ); - const setWorkflowDiagramRightClickMenuPosition = useSetRecoilComponentState( + const setWorkflowDiagramRightClickMenuPosition = useSetRecoilComponentStateV2( workflowDiagramRightClickMenuPositionState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx index 01926731db..4e29214ea2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx @@ -1,7 +1,6 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState'; @@ -12,12 +11,12 @@ import { useStepsOutputSchema } from '@/workflow/workflow-variables/hooks/useSte import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram'; import { mergeWorkflowDiagrams } from '@/workflow/workflow-diagram/utils/mergeWorkflowDiagrams'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const WorkflowDiagramEffect = () => { - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); @@ -25,62 +24,55 @@ export const WorkflowDiagramEffect = () => { workflowVisualizerWorkflowId, ); - const workflowDiagramState = useRecoilComponentCallbackState( + const workflowDiagramAtom = useRecoilComponentStateCallbackStateV2( workflowDiagramComponentState, ); - const setFlow = useSetRecoilComponentState(flowComponentState); + const setFlow = useSetRecoilComponentStateV2(flowComponentState); const { populateStepsOutputSchema } = useStepsOutputSchema(); - const workflowLastCreatedStepIdState = useRecoilComponentCallbackState( + const workflowLastCreatedStepIdAtom = useRecoilComponentStateCallbackStateV2( workflowLastCreatedStepIdComponentState, ); + const store = useStore(); const currentVersion = workflowWithCurrentVersion?.currentVersion; - const computeAndMergeNewWorkflowDiagram = useRecoilCallback( - ({ snapshot, set }) => { - return (currentVersion: WorkflowVersion) => { - const previousWorkflowDiagram = getSnapshotValue( - snapshot, - workflowDiagramState, + const computeAndMergeNewWorkflowDiagram = useCallback( + (version: WorkflowVersion) => { + const previousWorkflowDiagram = store.get(workflowDiagramAtom); + + const nextWorkflowDiagram = getWorkflowVersionDiagram({ + workflowVersion: version, + workflowContext: 'workflow', + }); + + let mergedWorkflowDiagram = nextWorkflowDiagram; + + if (isDefined(previousWorkflowDiagram)) { + mergedWorkflowDiagram = mergeWorkflowDiagrams( + previousWorkflowDiagram, + nextWorkflowDiagram, + ); + } + + const lastCreatedStepId = store.get(workflowLastCreatedStepIdAtom); + + if (isDefined(lastCreatedStepId)) { + mergedWorkflowDiagram.nodes = mergedWorkflowDiagram.nodes.map( + (node) => { + return { + ...node, + selected: node.id === lastCreatedStepId, + }; + }, ); - const nextWorkflowDiagram = getWorkflowVersionDiagram({ - workflowVersion: currentVersion, - workflowContext: 'workflow', - }); + store.set(workflowLastCreatedStepIdAtom, undefined); + } - let mergedWorkflowDiagram = nextWorkflowDiagram; - - if (isDefined(previousWorkflowDiagram)) { - mergedWorkflowDiagram = mergeWorkflowDiagrams( - previousWorkflowDiagram, - nextWorkflowDiagram, - ); - } - - const lastCreatedStepId = getSnapshotValue( - snapshot, - workflowLastCreatedStepIdState, - ); - - if (isDefined(lastCreatedStepId)) { - mergedWorkflowDiagram.nodes = mergedWorkflowDiagram.nodes.map( - (node) => { - return { - ...node, - selected: node.id === lastCreatedStepId, - }; - }, - ); - - set(workflowLastCreatedStepIdState, undefined); - } - - set(workflowDiagramState, mergedWorkflowDiagram); - }; + store.set(workflowDiagramAtom, mergedWorkflowDiagram); }, - [workflowDiagramState, workflowLastCreatedStepIdState], + [workflowDiagramAtom, workflowLastCreatedStepIdAtom, store], ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx index bb2d498c60..fba494d818 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useCloseRightClickMenu } from '@/workflow/workflow-diagram/hooks/useCloseRightClickMenu'; import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation'; import { useWorkflowDiagramScreenToFlowPosition } from '@/workflow/workflow-diagram/hooks/useWorkflowDiagramScreenToFlowPosition'; @@ -37,7 +37,7 @@ export const WorkflowDiagramRightClickCommandMenu = () => { const { closeRightClickMenu } = useCloseRightClickMenu(); - const workflowDiagramRightClickMenuPosition = useRecoilComponentValue( + const workflowDiagramRightClickMenuPosition = useRecoilComponentValueV2( workflowDiagramRightClickMenuPositionState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenuClickOutsideEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenuClickOutsideEffect.tsx index 5b9718f1d5..ccdb602c27 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenuClickOutsideEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenuClickOutsideEffect.tsx @@ -1,6 +1,6 @@ import { COMMAND_MENU_CLICK_OUTSIDE_ID } from '@/command-menu/constants/CommandMenuClickOutsideId'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { WORKFLOW_DIAGRAM_RIGHT_CLICK_MENU_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramRightClickMenuClickOutsideId'; import { workflowDiagramRightClickMenuPositionState } from '@/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState'; @@ -9,7 +9,7 @@ export const WorkflowDiagramRightClickCommandMenuClickOutsideEffect = ({ }: { rightClickCommandMenuRef: React.RefObject; }) => { - const setWorkflowDiagramRightClickMenuPosition = useSetRecoilComponentState( + const setWorkflowDiagramRightClickMenuPosition = useSetRecoilComponentStateV2( workflowDiagramRightClickMenuPositionState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx index a670d84079..45b8e39045 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { WorkflowRunDiagramCanvas } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramCanvas'; import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState'; @@ -10,7 +10,7 @@ export const WorkflowRunVisualizer = ({ workflowRunId: string; }) => { const workflowRun = useWorkflowRun({ workflowRunId }); - const workflowDiagramStatus = useRecoilComponentValue( + const workflowDiagramStatus = useRecoilComponentValueV2( workflowDiagramStatusComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx index c55ab9acb7..2d7869abbb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx @@ -1,8 +1,7 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { flowComponentState } from '@/workflow/states/flowComponentState'; @@ -18,8 +17,8 @@ import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/ge import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey'; import { selectWorkflowDiagramNode } from '@/workflow/workflow-diagram/utils/selectWorkflowDiagramNode'; import { useStepsOutputSchema } from '@/workflow/workflow-variables/hooks/useStepsOutputSchema'; -import { useContext, useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext, useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -31,35 +30,37 @@ export const WorkflowRunVisualizerEffect = ({ const { getIcon } = useIcons(); const workflowRun = useWorkflowRun({ workflowRunId }); - const setWorkflowRunId = useSetRecoilComponentState( + const setWorkflowRunId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowRunIdComponentState, ); const workflowVersionId = workflowRun?.workflowVersionId; const workflowVersion = useWorkflowVersion(workflowVersionId); - const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentState( + const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowVersionIdComponentState, ); - const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackState( - workflowVisualizerWorkflowIdComponentState, - ); - const setWorkflowVisualizerWorkflowId = useSetRecoilComponentState( + const workflowVisualizerWorkflowIdAtom = + useRecoilComponentStateCallbackStateV2( + workflowVisualizerWorkflowIdComponentState, + ); + const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowIdComponentState, ); - const flowState = useRecoilComponentCallbackState(flowComponentState); - const workflowDiagramState = useRecoilComponentCallbackState( + const flowAtom = useRecoilComponentStateCallbackStateV2(flowComponentState); + const workflowDiagramAtom = useRecoilComponentStateCallbackStateV2( workflowDiagramComponentState, ); - const workflowDiagramStatusState = useRecoilComponentCallbackState( - workflowDiagramStatusComponentState, - ); - const workflowSelectedNodeState = useRecoilComponentCallbackState( + const workflowSelectedNodeAtom = useRecoilComponentStateCallbackStateV2( workflowSelectedNodeComponentState, ); + + const workflowDiagramStatusState = useRecoilComponentStateCallbackStateV2( + workflowDiagramStatusComponentState, + ); const workflowRunDiagramAutomaticallyOpenedStepsState = - useRecoilComponentCallbackState( + useRecoilComponentStateCallbackStateV2( workflowRunDiagramAutomaticallyOpenedStepsComponentState, ); @@ -69,6 +70,8 @@ export const WorkflowRunVisualizerEffect = ({ const { isInRightDrawer } = useContext(ActionMenuContext); + const store = useStore(); + useEffect(() => { setWorkflowRunId(workflowRunId); }, [setWorkflowRunId, workflowRunId]); @@ -89,121 +92,116 @@ export const WorkflowRunVisualizerEffect = ({ setWorkflowVisualizerWorkflowVersionId(workflowVersionId); }, [setWorkflowVisualizerWorkflowVersionId, workflowVersionId]); - const handleWorkflowRunDiagramGeneration = useRecoilCallback( - ({ snapshot, set }) => - ({ - workflowRunState, - workflowVersionId, - isInRightDrawer, - }: { - workflowRunState: WorkflowRunState | undefined; - workflowVersionId: string | undefined; - isInRightDrawer: boolean; - }) => { - if (!(isDefined(workflowRunState) && isDefined(workflowVersionId))) { - set(flowState, undefined); - set(workflowDiagramState, undefined); + const handleWorkflowRunDiagramGeneration = useCallback( + ({ + workflowRunState, + workflowVersionId: versionId, + isInRightDrawer: inRightDrawer, + }: { + workflowRunState: WorkflowRunState | undefined; + workflowVersionId: string | undefined; + isInRightDrawer: boolean; + }) => { + if (!(isDefined(workflowRunState) && isDefined(versionId))) { + store.set(flowAtom, undefined); + store.set(workflowDiagramAtom, undefined); - return; - } + return; + } - const workflowDiagramStatus = getSnapshotValue( - snapshot, - workflowDiagramStatusState, - ); + const workflowDiagramStatus = store.get(workflowDiagramStatusState); - if (workflowDiagramStatus !== 'done') { - set(workflowDiagramStatusState, 'computing-diagram'); - } + if (workflowDiagramStatus !== 'done') { + store.set(workflowDiagramStatusState, 'computing-diagram'); + } - set(flowState, { - workflowVersionId, + store.set(flowAtom, { + workflowVersionId: versionId, + trigger: workflowRunState.flow.trigger, + steps: workflowRunState.flow.steps, + }); + + const { diagram: baseWorkflowRunDiagram, stepToOpenByDefault } = + generateWorkflowRunDiagram({ trigger: workflowRunState.flow.trigger, steps: workflowRunState.flow.steps, + stepInfos: workflowRunState.stepInfos, }); - const { diagram: baseWorkflowRunDiagram, stepToOpenByDefault } = - generateWorkflowRunDiagram({ - trigger: workflowRunState.flow.trigger, - steps: workflowRunState.flow.steps, - stepInfos: workflowRunState.stepInfos, - }); + if (workflowDiagramStatus !== 'done') { + store.set(workflowDiagramStatusState, 'computing-dimensions'); + } - if (workflowDiagramStatus !== 'done') { - set(workflowDiagramStatusState, 'computing-dimensions'); - } + if (!isDefined(stepToOpenByDefault)) { + store.set(workflowDiagramAtom, baseWorkflowRunDiagram); - if (!isDefined(stepToOpenByDefault)) { - set(workflowDiagramState, baseWorkflowRunDiagram); + return; + } - return; - } - - const workflowRunDiagramAutomaticallyOpenedSteps = getSnapshotValue( - snapshot, - workflowRunDiagramAutomaticallyOpenedStepsState, + const workflowRunDiagramAutomaticallyOpenedSteps = store.get( + workflowRunDiagramAutomaticallyOpenedStepsState, + ); + const hasStepAlreadyBeenOpenedAutomatically = + workflowRunDiagramAutomaticallyOpenedSteps.some( + (step) => + step.stepId === stepToOpenByDefault.id && + step.isInRightDrawer === inRightDrawer, ); - const hasStepAlreadyBeenOpenedAutomatically = - workflowRunDiagramAutomaticallyOpenedSteps.some( - (step) => - step.stepId === stepToOpenByDefault.id && - step.isInRightDrawer === isInRightDrawer, - ); - const workflowVisualizerWorkflowId = getSnapshotValue( - snapshot, - workflowVisualizerWorkflowIdState, + const workflowVisualizerWorkflowId = store.get( + workflowVisualizerWorkflowIdAtom, + ); + if (!isDefined(workflowVisualizerWorkflowId)) { + throw new Error( + 'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.', ); - if (!isDefined(workflowVisualizerWorkflowId)) { - throw new Error( - 'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.', - ); - } + } - if (isInRightDrawer) { - set(workflowDiagramState, baseWorkflowRunDiagram); - } else { - const workflowRunDiagram = selectWorkflowDiagramNode({ - diagram: baseWorkflowRunDiagram, - nodeIdToSelect: stepToOpenByDefault.id, - }); - - set(workflowDiagramState, workflowRunDiagram); - } - - if (hasStepAlreadyBeenOpenedAutomatically) { - return; - } - - set(workflowSelectedNodeState, stepToOpenByDefault.id); - - set(workflowRunDiagramAutomaticallyOpenedStepsState, [ - ...workflowRunDiagramAutomaticallyOpenedSteps, - { - stepId: stepToOpenByDefault.id, - isInRightDrawer, - }, - ]); - - openWorkflowRunViewStepInCommandMenu({ - workflowId: workflowVisualizerWorkflowId, - workflowRunId, - title: stepToOpenByDefault.data.name, - icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)), - workflowSelectedNode: stepToOpenByDefault.id, - stepExecutionStatus: stepToOpenByDefault.data.runStatus, + if (inRightDrawer) { + store.set(workflowDiagramAtom, baseWorkflowRunDiagram); + } else { + const workflowRunDiagram = selectWorkflowDiagramNode({ + diagram: baseWorkflowRunDiagram, + nodeIdToSelect: stepToOpenByDefault.id, }); - }, + + store.set(workflowDiagramAtom, workflowRunDiagram); + } + + if (hasStepAlreadyBeenOpenedAutomatically) { + return; + } + + store.set(workflowSelectedNodeAtom, stepToOpenByDefault.id); + + store.set(workflowRunDiagramAutomaticallyOpenedStepsState, [ + ...workflowRunDiagramAutomaticallyOpenedSteps, + { + stepId: stepToOpenByDefault.id, + isInRightDrawer: inRightDrawer, + }, + ]); + + openWorkflowRunViewStepInCommandMenu({ + workflowId: workflowVisualizerWorkflowId, + workflowRunId, + title: stepToOpenByDefault.data.name, + icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)), + workflowSelectedNode: stepToOpenByDefault.id, + stepExecutionStatus: stepToOpenByDefault.data.runStatus, + }); + }, [ - flowState, + flowAtom, getIcon, openWorkflowRunViewStepInCommandMenu, - workflowDiagramState, + workflowDiagramAtom, workflowDiagramStatusState, workflowRunDiagramAutomaticallyOpenedStepsState, workflowRunId, - workflowSelectedNodeState, - workflowVisualizerWorkflowIdState, + workflowSelectedNodeAtom, + workflowVisualizerWorkflowIdAtom, + store, ], ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowSSESubscribeEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowSSESubscribeEffect.tsx index bd3e37b3c9..3f0dbaf15b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowSSESubscribeEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowSSESubscribeEffect.tsx @@ -1,10 +1,10 @@ import { useCallback } from 'react'; -import { useSetRecoilState } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useListenToObjectRecordOperationBrowserEvent } from '@/browser-event/hooks/useListenToObjectRecordOperationBrowserEvent'; import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { shouldWorkflowRefetchRequestFamilyState } from '@/workflow/states/shouldWorkflowRefetchRequestFamilyState'; export const WorkflowSSESubscribeEffect = ({ @@ -14,8 +14,9 @@ export const WorkflowSSESubscribeEffect = ({ }) => { const queryId = `workflow-versions-for-workflow-${workflowId}`; - const setShouldWorkflowRefetchRequest = useSetRecoilState( - shouldWorkflowRefetchRequestFamilyState(workflowId), + const setShouldWorkflowRefetchRequest = useSetFamilyRecoilStateV2( + shouldWorkflowRefetchRequestFamilyState, + workflowId, ); const { objectMetadataItem: workflowVersionMetadataItem } = diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx index 15ab7d2614..5c169a4cec 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx @@ -1,4 +1,4 @@ -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; @@ -16,14 +16,14 @@ export const WorkflowVersionVisualizerEffect = ({ }) => { const workflowVersion = useWorkflowVersion(workflowVersionId); - const setFlow = useSetRecoilComponentState(flowComponentState); - const setWorkflowDiagram = useSetRecoilComponentState( + const setFlow = useSetRecoilComponentStateV2(flowComponentState); + const setWorkflowDiagram = useSetRecoilComponentStateV2( workflowDiagramComponentState, ); - const setWorkflowVisualizerWorkflowId = useSetRecoilComponentState( + const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowIdComponentState, ); - const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentState( + const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowVersionIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx index 17962ace0f..fea6df2068 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx @@ -1,4 +1,4 @@ -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; @@ -10,10 +10,10 @@ export const WorkflowVisualizerEffect = ({ }: { workflowId: string; }) => { - const setWorkflowVisualizerWorkflowId = useSetRecoilComponentState( + const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowIdComponentState, ); - const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentState( + const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentStateV2( workflowVisualizerWorkflowVersionIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTriggerEditable.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTriggerEditable.stories.tsx index b656022c1f..9011bae297 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTriggerEditable.stories.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTriggerEditable.stories.tsx @@ -4,10 +4,36 @@ import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow- import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowDiagramEmptyTriggerEditable } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable'; import '@xyflow/react/dist/style.css'; +import { useStore } from 'jotai'; +import { useEffect } from 'react'; import { RecoilRoot } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; import { ComponentDecorator } from 'twenty-ui/testing'; import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator'; +const JotaiInitializer = ({ + children, + selectedNodeId, +}: { + children: React.ReactNode; + selectedNodeId?: string; +}) => { + const store = useStore(); + + useEffect(() => { + if (isDefined(selectedNodeId)) { + store.set( + workflowSelectedNodeComponentState.atomFamily({ + instanceId: 'workflow-visualizer-instance-id', + }), + selectedNodeId, + ); + } + }, [store, selectedNodeId]); + + return <>{children}; +}; + const meta: Meta = { title: 'Modules/Workflow/WorkflowDiagramEmptyTriggerEditable', component: WorkflowDiagramEmptyTriggerEditable, @@ -45,20 +71,13 @@ export const Selected: Story = { decorators: [ (Story) => (
- { - set( - workflowSelectedNodeComponentState.atomFamily({ - instanceId: 'workflow-visualizer-instance-id', - }), - 'trigger-node', - ); - }} - > + - + + +
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx index 4362992cf2..3d03cf134b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx @@ -5,11 +5,37 @@ import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/ import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent'; import '@xyflow/react/dist/style.css'; +import { useStore } from 'jotai'; +import { useEffect } from 'react'; import { RecoilRoot } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; import { CatalogDecorator, type CatalogStory } from 'twenty-ui/testing'; import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; +const JotaiInitializer = ({ + children, + selectedNodeId, +}: { + children: React.ReactNode; + selectedNodeId?: string; +}) => { + const store = useStore(); + + useEffect(() => { + if (isDefined(selectedNodeId)) { + store.set( + workflowSelectedNodeComponentState.atomFamily({ + instanceId: 'workflow-visualizer-instance-id', + }), + selectedNodeId, + ); + } + }, [store, selectedNodeId]); + + return <>{children}; +}; + const meta: Meta = { title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent', component: WorkflowDiagramStepNodeEditableContent, @@ -150,22 +176,15 @@ export const Catalog: CatalogStory< (Story, { args }) => { return (
- { - if (args.selected === true) { - set( - workflowSelectedNodeComponentState.atomFamily({ - instanceId: 'workflow-visualizer-instance-id', - }), - args.id, - ); - } - }} - > + - + + +
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useCloseRightClickMenu.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useCloseRightClickMenu.ts index f74ad2873c..d69757eb8e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useCloseRightClickMenu.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useCloseRightClickMenu.ts @@ -1,8 +1,8 @@ -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { workflowDiagramRightClickMenuPositionState } from '@/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState'; export const useCloseRightClickMenu = () => { - const setWorkflowDiagramRightClickMenuPosition = useSetRecoilComponentState( + const setWorkflowDiagramRightClickMenuPosition = useSetRecoilComponentStateV2( workflowDiagramRightClickMenuPositionState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds.ts index b97304cb49..1569d2215e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds.ts @@ -1,19 +1,20 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; export const useResetWorkflowInsertStepIds = () => { - const workflowInsertStepIdsState = useRecoilComponentCallbackState( + const setWorkflowInsertStepIds = useSetRecoilComponentStateV2( workflowInsertStepIdsComponentState, ); - const resetWorkflowInsertStepIds = useRecoilCallback( - ({ reset }) => - () => { - reset(workflowInsertStepIdsState); - }, - [workflowInsertStepIdsState], - ); + const resetWorkflowInsertStepIds = useCallback(() => { + setWorkflowInsertStepIds({ + parentStepId: undefined, + nextStepId: undefined, + position: undefined, + connectionOptions: undefined, + }); + }, [setWorkflowInsertStepIds]); return { resetWorkflowInsertStepIds }; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab.ts index 48c00bd995..7b350687fb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab.ts @@ -2,66 +2,59 @@ import { getIsInputTabDisabled } from '@/command-menu/pages/workflow/step/view-r import { getIsOutputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsOutputTabDisabled'; import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useStore } from 'jotai'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { WorkflowRunTabId } from '@/workflow/workflow-steps/types/WorkflowRunTabId'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type WorkflowRunStepStatus } from '@/workflow/types/Workflow'; export const useSetInitialWorkflowRunRightDrawerTab = () => { - const store = useStore(); + const setInitialWorkflowRunRightDrawerTab = useCallback( + ({ + workflowSelectedNode, + stepExecutionStatus, + }: { + workflowSelectedNode: string; + stepExecutionStatus: WorkflowRunStepStatus; + }) => { + const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom); - const setInitialWorkflowRunRightDrawerTab = useRecoilCallback( - ({ snapshot }) => - ({ - workflowSelectedNode, + const activeTabIdAtom = activeTabIdComponentState.atomFamily({ + instanceId: commandMenuPageInfo.instanceId, + }); + + const activeWorkflowRunRightDrawerTab = jotaiStore.get( + activeTabIdAtom, + ) as WorkflowRunTabId | null; + + const isInputTabDisabled = getIsInputTabDisabled({ stepExecutionStatus, - }: { - workflowSelectedNode: string; - stepExecutionStatus: WorkflowRunStepStatus; - }) => { - const commandMenuPageInfo = getSnapshotValue( - snapshot, - commandMenuPageInfoState, - ); + workflowSelectedNode, + }); + const isOutputTabDisabled = getIsOutputTabDisabled({ + stepExecutionStatus, + }); - const activeTabIdAtom = activeTabIdComponentState.atomFamily({ - instanceId: commandMenuPageInfo.instanceId, - }); + if (!isDefined(activeWorkflowRunRightDrawerTab)) { + const defaultTabId = isOutputTabDisabled + ? WorkflowRunTabId.NODE + : WorkflowRunTabId.OUTPUT; - const activeWorkflowRunRightDrawerTab = store.get( - activeTabIdAtom, - ) as WorkflowRunTabId | null; + jotaiStore.set(activeTabIdAtom, defaultTabId); - const isInputTabDisabled = getIsInputTabDisabled({ - stepExecutionStatus, - workflowSelectedNode, - }); - const isOutputTabDisabled = getIsOutputTabDisabled({ - stepExecutionStatus, - }); + return; + } - if (!isDefined(activeWorkflowRunRightDrawerTab)) { - const defaultTabId = isOutputTabDisabled - ? WorkflowRunTabId.NODE - : WorkflowRunTabId.OUTPUT; - - store.set(activeTabIdAtom, defaultTabId); - - return; - } - - if ( - (isInputTabDisabled && - activeWorkflowRunRightDrawerTab === WorkflowRunTabId.INPUT) || - (isOutputTabDisabled && - activeWorkflowRunRightDrawerTab === WorkflowRunTabId.OUTPUT) - ) { - store.set(activeTabIdAtom, WorkflowRunTabId.NODE); - } - }, - [store], + if ( + (isInputTabDisabled && + activeWorkflowRunRightDrawerTab === WorkflowRunTabId.INPUT) || + (isOutputTabDisabled && + activeWorkflowRunRightDrawerTab === WorkflowRunTabId.OUTPUT) + ) { + jotaiStore.set(activeTabIdAtom, WorkflowRunTabId.NODE); + } + }, + [], ); return { diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts index 3addeaa693..d9897adc31 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts @@ -1,34 +1,34 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { type StartNodeCreationParams } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useCallback, useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const useStartNodeCreation = () => { const { isInRightDrawer } = useContext(ActionMenuContext); const [workflowInsertStepIds, setWorkflowInsertStepIds] = - useRecoilComponentState(workflowInsertStepIdsComponentState); + useRecoilComponentStateV2(workflowInsertStepIdsComponentState); - const setWorkflowSelectedNode = useSetRecoilComponentState( + const setWorkflowSelectedNode = useSetRecoilComponentStateV2( workflowSelectedNodeComponentState, ); const { openWorkflowCreateStepInCommandMenu } = useWorkflowCommandMenu(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts index 7c65a7e88e..1fd486f308 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { type WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; -export const workflowDiagramComponentState = createComponentState< +export const workflowDiagramComponentState = createComponentStateV2< WorkflowDiagram | undefined >({ key: 'workflowDiagramComponentState', diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState.ts index 3f734a4f88..42fd0ae3d0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; export const workflowDiagramPanOnDragComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowDiagramPanOnDragComponentState', defaultValue: true, componentInstanceContext: WorkflowVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState.ts index d7a6f098cb..4a24bafadb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState.ts @@ -1,4 +1,4 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; type WorkflowDiagramRightClickMenuPositionState = @@ -9,7 +9,7 @@ type WorkflowDiagramRightClickMenuPositionState = | undefined; export const workflowDiagramRightClickMenuPositionState = - createComponentState({ + createComponentStateV2({ key: 'workflowDiagramRightClickMenuPositionState', defaultValue: undefined, componentInstanceContext: WorkflowVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts index d30a6f029b..6401fe7165 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts @@ -1,11 +1,11 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowRunVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext'; import { type WorkflowDiagramStatus } from '@/workflow/workflow-diagram/types/WorkflowDiagramStatus'; // This state must be fresh every time the Reactflow component is mounted. // We use another instance context whose instanceId is an id unique to the component hierarchy. export const workflowDiagramStatusComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowDiagramStatusComponentState', defaultValue: 'computing-diagram', componentInstanceContext: WorkflowRunVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState.ts index e496cd5b36..fa8d2271f4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; export const workflowDiagramWaitingNodesDimensionsComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowDiagramWaitingNodesDimensionsComponentState', defaultValue: false, componentInstanceContext: WorkflowVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState.ts index 9cf49e83bf..8d3f9d546e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; export const workflowRunDiagramAutomaticallyOpenedStepsComponentState = - createComponentState<{ stepId: string; isInRightDrawer: boolean }[]>({ + createComponentStateV2<{ stepId: string; isInRightDrawer: boolean }[]>({ key: 'workflowRunDiagramAutomaticallyOpenedStepsComponentState', defaultValue: [], componentInstanceContext: WorkflowVisualizerComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts index 30eaf8f816..8dddf9d8ec 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts @@ -1,7 +1,7 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; -export const workflowSelectedNodeComponentState = createComponentState< +export const workflowSelectedNodeComponentState = createComponentStateV2< string | undefined >({ key: 'workflowSelectedNodeComponentState', diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState.ts index 63a08b49a8..e4edc89001 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState.ts @@ -1,4 +1,4 @@ -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { EDGE_BRANCH_ARROW_MARKER } from '@/workflow/workflow-diagram/workflow-edges/constants/EdgeBranchArrowMarker'; import { workflowHoveredEdgeComponentState } from '@/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState'; import { workflowSelectedEdgeComponentState } from '@/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState'; @@ -9,11 +9,10 @@ export const useEdgeState = () => { const reactflow = useReactFlow(); const [workflowSelectedEdge, setWorkflowSelectedEdge] = - useRecoilComponentState(workflowSelectedEdgeComponentState); + useRecoilComponentStateV2(workflowSelectedEdgeComponentState); - const [workflowHoveredEdge, setWorkflowHoveredEdge] = useRecoilComponentState( - workflowHoveredEdgeComponentState, - ); + const [workflowHoveredEdge, setWorkflowHoveredEdge] = + useRecoilComponentStateV2(workflowHoveredEdgeComponentState); const isSourceSelected = ({ nodeId, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState.ts index acb6648bc3..469d40d804 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor'; -export const workflowHoveredEdgeComponentState = createComponentState< +export const workflowHoveredEdgeComponentState = createComponentStateV2< WorkflowDiagramEdgeDescriptor | undefined >({ key: 'workflowHoveredEdgeComponentState', diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState.ts index 01d59f0bac..0c1b0bcc86 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor'; -export const workflowSelectedEdgeComponentState = createComponentState< +export const workflowSelectedEdgeComponentState = createComponentStateV2< WorkflowDiagramEdgeDescriptor | undefined >({ key: 'workflowSelectedEdgeComponentState', diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx index d5f4e23d90..393884a489 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx @@ -1,8 +1,8 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId'; import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds'; @@ -14,8 +14,8 @@ import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/wo import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart'; import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle'; import { useLingui } from '@lingui/react/macro'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const WorkflowDiagramEmptyTriggerEditable = ({ id }: { id: string }) => { @@ -23,16 +23,16 @@ export const WorkflowDiagramEmptyTriggerEditable = ({ id }: { id: string }) => { const { openWorkflowTriggerTypeInCommandMenu } = useWorkflowCommandMenu(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const [workflowSelectedNode, setWorkflowSelectedNode] = - useRecoilComponentState(workflowSelectedNodeComponentState); + useRecoilComponentStateV2(workflowSelectedNodeComponentState); const { isInRightDrawer } = useContext(ActionMenuContext); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx index 8d4501828c..5d9ba79907 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx @@ -1,8 +1,8 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId'; @@ -14,8 +14,8 @@ import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/wo import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart'; import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle'; import { useLingui } from '@lingui/react/macro'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; @@ -24,21 +24,21 @@ export const WorkflowDiagramEmptyTriggerReadonly = ({ id }: { id: string }) => { const { getIcon } = useIcons(); const { t } = useLingui(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); - const workflowVisualizerWorkflowVersionId = useRecoilComponentValue( + const workflowVisualizerWorkflowVersionId = useRecoilComponentValueV2( workflowVisualizerWorkflowVersionIdComponentState, ); const [workflowSelectedNode, setWorkflowSelectedNode] = - useRecoilComponentState(workflowSelectedNodeComponentState); + useRecoilComponentStateV2(workflowSelectedNodeComponentState); const { isInRightDrawer } = useContext(ActionMenuContext); const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu(); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditable.tsx index f47c91f4b6..1db6857aaf 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditable.tsx @@ -1,16 +1,16 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey'; import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -23,12 +23,12 @@ export const WorkflowDiagramStepNodeEditable = ({ }) => { const { getIcon } = useIcons(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const [workflowSelectedNode, setWorkflowSelectedNode] = - useRecoilComponentState(workflowSelectedNodeComponentState); + useRecoilComponentStateV2(workflowSelectedNodeComponentState); const selected = workflowSelectedNode === id; @@ -38,7 +38,7 @@ export const WorkflowDiagramStepNodeEditable = ({ const { isInRightDrawer } = useContext(ActionMenuContext); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx index 723a30c8f6..fd79b6fd52 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { WorkflowDiagramCreateStepElement } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepElement'; import { EMPTY_NODE_ID } from '@/workflow/workflow-diagram/constants/EmptyNodeId'; import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId'; @@ -64,7 +64,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({ const { isNodeCreationStarted } = useStartNodeCreation(); - const workflowInsertStepIds = useRecoilComponentValue( + const workflowInsertStepIds = useRecoilComponentValueV2( workflowInsertStepIdsComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx index 83db1fdfd0..f9bfbb4b06 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx @@ -1,8 +1,8 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId'; @@ -21,8 +21,8 @@ import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/co import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId'; import { isNodeTitleHighlighted } from '@/workflow/workflow-diagram/workflow-nodes/utils/isNodeTitleHighlighted'; import { Position } from '@xyflow/react'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -35,15 +35,15 @@ export const WorkflowDiagramStepNodeReadonly = ({ }) => { const { getIcon } = useIcons(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); - const workflowVisualizerWorkflowVersionId = useRecoilComponentValue( + const workflowVisualizerWorkflowVersionId = useRecoilComponentValueV2( workflowVisualizerWorkflowVersionIdComponentState, ); const [workflowSelectedNode, setWorkflowSelectedNode] = - useRecoilComponentState(workflowSelectedNodeComponentState); + useRecoilComponentStateV2(workflowSelectedNodeComponentState); const selected = workflowSelectedNode === id; @@ -51,7 +51,7 @@ export const WorkflowDiagramStepNodeReadonly = ({ const { isInRightDrawer } = useContext(ActionMenuContext); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx index b03129600a..e59b4c9e1a 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx @@ -1,8 +1,8 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; @@ -26,8 +26,8 @@ import { getNodeIterationCount } from '@/workflow/workflow-diagram/workflow-node import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { Position } from '@xyflow/react'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useContext } from 'react'; -import { useSetRecoilState } from 'recoil'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { StepStatus } from 'twenty-shared/workflow'; import { IconCheck, IconX, useIcons } from 'twenty-ui/display'; @@ -87,13 +87,13 @@ export const WorkflowRunDiagramStepNode = ({ const { getIcon } = useIcons(); const theme = useTheme(); - const workflowId = useRecoilComponentValue( + const workflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const workflowRunId = useWorkflowRunIdOrThrow(); const [workflowSelectedNode, setWorkflowSelectedNode] = - useRecoilComponentState(workflowSelectedNodeComponentState); + useRecoilComponentStateV2(workflowSelectedNodeComponentState); const selected = workflowSelectedNode === id; @@ -101,7 +101,7 @@ export const WorkflowRunDiagramStepNode = ({ const { isInRightDrawer } = useContext(ActionMenuContext); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowDropdownStepOutputItems.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowDropdownStepOutputItems.tsx index 4884eb3e41..e06e71e16a 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowDropdownStepOutputItems.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowDropdownStepOutputItems.tsx @@ -22,7 +22,8 @@ import { getStepItemIcon } from '@/workflow/workflow-variables/utils/getStepItem import { getVariableTemplateFromPath } from '@/workflow/workflow-variables/utils/getVariableTemplateFromPath'; import { searchVariableThroughOutputSchemaV2 } from '@/workflow/workflow-variables/utils/searchVariableThroughOutputSchemaV2'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; import { type FilterableAndTSVectorFieldType, type StepFilter, @@ -61,71 +62,71 @@ export const WorkflowDropdownStepOutputItems = ({ const { getInitialFilterValue } = useGetInitialFilterValue(); - const updateStepFilter = useRecoilCallback( - ({ snapshot }) => - ({ + const jotaiStore = useStore(); + + const updateStepFilter = useCallback( + ({ + rawVariableName, + isFullRecord, + }: { + rawVariableName: string; + isFullRecord: boolean; + }) => { + const stepId = extractRawVariableNamePart({ rawVariableName, - isFullRecord, - }: { - rawVariableName: string; - isFullRecord: boolean; - }) => { - const stepId = extractRawVariableNamePart({ + part: 'stepId', + }); + const [currentStepOutputSchema] = jotaiStore.get( + stepsOutputSchemaFamilySelector.selectorFamily({ + workflowVersionId, + stepIds: [stepId], + }), + ); + + const { variableType, fieldMetadataId, compositeFieldSubFieldName } = + searchVariableThroughOutputSchemaV2({ + stepOutputSchema: currentStepOutputSchema, + stepType: step.type, rawVariableName, - part: 'stepId', + isFullRecord: false, }); - const [currentStepOutputSchema] = snapshot - .getLoadable( - stepsOutputSchemaFamilySelector({ - workflowVersionId, - stepIds: [stepId], - }), - ) - .getValue(); - const { variableType, fieldMetadataId, compositeFieldSubFieldName } = - searchVariableThroughOutputSchemaV2({ - stepOutputSchema: currentStepOutputSchema, - stepType: step.type, - rawVariableName, - isFullRecord: false, - }); + const { fieldMetadataItem: filterFieldMetadataItem } = isDefined( + fieldMetadataId, + ) + ? getFieldMetadataItemByIdOrThrow(fieldMetadataId) + : { fieldMetadataItem: undefined }; - const { fieldMetadataItem: filterFieldMetadataItem } = isDefined( + const filterType = isDefined(fieldMetadataId) + ? (filterFieldMetadataItem?.type ?? 'unknown') + : variableType; + + const availableOperandsForFilter = getStepFilterOperands({ + filterType, + subFieldName: compositeFieldSubFieldName, + }); + const defaultOperand = availableOperandsForFilter[0]; + + const { value } = getInitialFilterValue( + filterType as FilterableAndTSVectorFieldType, + defaultOperand, + ); + + upsertStepFilterSettings({ + stepFilterToUpsert: { + ...stepFilter, + stepOutputKey: rawVariableName, + isFullRecord, + type: filterType ?? 'unknown', + value: value, fieldMetadataId, - ) - ? getFieldMetadataItemByIdOrThrow(fieldMetadataId) - : { fieldMetadataItem: undefined }; - - const filterType = isDefined(fieldMetadataId) - ? (filterFieldMetadataItem?.type ?? 'unknown') - : variableType; - - const availableOperandsForFilter = getStepFilterOperands({ - filterType, - subFieldName: compositeFieldSubFieldName, - }); - const defaultOperand = availableOperandsForFilter[0]; - - const { value } = getInitialFilterValue( - filterType as FilterableAndTSVectorFieldType, - defaultOperand, - ); - - upsertStepFilterSettings({ - stepFilterToUpsert: { - ...stepFilter, - stepOutputKey: rawVariableName, - isFullRecord, - type: filterType ?? 'unknown', - value: value, - fieldMetadataId, - compositeFieldSubFieldName, - operand: defaultOperand, - }, - }); - }, + compositeFieldSubFieldName, + operand: defaultOperand, + }, + }); + }, [ + jotaiStore, workflowVersionId, step.type, getFieldMetadataItemByIdOrThrow, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx index 432468d8c4..48b6782a83 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx @@ -1,5 +1,5 @@ import { workflowRunIteratorSubStepIterationIndexComponentState } from '@/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow'; @@ -29,7 +29,7 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => { (step) => step.id === stepId, ); - const workflowRunIteratorSubStepIterationIndex = useRecoilComponentValue( + const workflowRunIteratorSubStepIterationIndex = useRecoilComponentValueV2( workflowRunIteratorSubStepIterationIndexComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowEditActionFilterBodyEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowEditActionFilterBodyEffect.tsx index 13267f0edd..3c47567aff 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowEditActionFilterBodyEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowEditActionFilterBodyEffect.tsx @@ -1,6 +1,6 @@ -import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState'; import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState'; @@ -31,7 +31,7 @@ export const WorkflowEditActionFilterBodyEffect = ({ const [ hasInitializedCurrentStepFilters, setHasInitializedCurrentStepFilters, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( hasInitializedCurrentStepFiltersComponentFamilyState, { stepId }, ); @@ -39,23 +39,23 @@ export const WorkflowEditActionFilterBodyEffect = ({ const [ hasInitializedCurrentStepFilterGroups, setHasInitializedCurrentStepFilterGroups, - ] = useRecoilComponentFamilyState( + ] = useRecoilComponentFamilyStateV2( hasInitializedCurrentStepFilterGroupsComponentFamilyState, { stepId }, ); - const currentStepFilters = useRecoilComponentValue( + const currentStepFilters = useRecoilComponentValueV2( currentStepFiltersComponentState, ); - const currentStepFilterGroups = useRecoilComponentValue( + const currentStepFilterGroups = useRecoilComponentValueV2( currentStepFilterGroupsComponentState, ); - const setCurrentStepFilters = useSetRecoilComponentState( + const setCurrentStepFilters = useSetRecoilComponentStateV2( currentStepFiltersComponentState, ); - const setCurrentStepFilterGroups = useSetRecoilComponentState( + const setCurrentStepFilterGroups = useSetRecoilComponentStateV2( currentStepFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useAddRootStepFilter.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useAddRootStepFilter.ts index f4c2f3a488..9f34fb3a7e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useAddRootStepFilter.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useAddRootStepFilter.ts @@ -1,12 +1,12 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; +import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentFamilyStateV2'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState'; import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState'; import { hasInitializedCurrentStepFiltersComponentFamilyState } from '@/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { type StepFilter, type StepFilterGroup, @@ -19,64 +19,64 @@ export const useAddRootStepFilter = () => { const { stepId, onFilterSettingsUpdate } = useContext( WorkflowStepFilterContext, ); - const currentStepFilterGroupsCallbackState = useRecoilComponentCallbackState( + const currentStepFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( currentStepFilterGroupsComponentState, ); - const currentStepFiltersCallbackState = useRecoilComponentCallbackState( + const currentStepFiltersAtom = useRecoilComponentStateCallbackStateV2( currentStepFiltersComponentState, ); - const setHasInitializedCurrentStepFilters = useSetRecoilComponentFamilyState( - hasInitializedCurrentStepFiltersComponentFamilyState, - { stepId }, - ); + const setHasInitializedCurrentStepFilters = + useSetRecoilComponentFamilyStateV2( + hasInitializedCurrentStepFiltersComponentFamilyState, + { stepId }, + ); const setHasInitializedCurrentStepFilterGroups = - useSetRecoilComponentFamilyState( + useSetRecoilComponentFamilyStateV2( hasInitializedCurrentStepFilterGroupsComponentFamilyState, { stepId }, ); - const addRootStepFilterRecoilCallback = useRecoilCallback( - ({ set }) => - () => { - const newStepFilterGroup: StepFilterGroup = { - id: v4(), - logicalOperator: StepLogicalOperator.AND, - }; + const store = useStore(); - const newStepFilter: StepFilter = { - id: v4(), - type: 'unknown', - value: '', - operand: ViewFilterOperand.IS, - stepFilterGroupId: newStepFilterGroup.id, - stepOutputKey: '', - positionInStepFilterGroup: 0, - }; + const addRootStepFilter = useCallback(() => { + const newStepFilterGroup: StepFilterGroup = { + id: v4(), + logicalOperator: StepLogicalOperator.AND, + }; - set(currentStepFilterGroupsCallbackState, [newStepFilterGroup]); - set(currentStepFiltersCallbackState, [newStepFilter]); + const newStepFilter: StepFilter = { + id: v4(), + type: 'unknown', + value: '', + operand: ViewFilterOperand.IS, + stepFilterGroupId: newStepFilterGroup.id, + stepOutputKey: '', + positionInStepFilterGroup: 0, + }; - setHasInitializedCurrentStepFilters(true); - setHasInitializedCurrentStepFilterGroups(true); + store.set(currentStepFilterGroupsAtom, [newStepFilterGroup]); + store.set(currentStepFiltersAtom, [newStepFilter]); - onFilterSettingsUpdate({ - stepFilterGroups: [newStepFilterGroup], - stepFilters: [newStepFilter], - }); - }, - [ - onFilterSettingsUpdate, - currentStepFilterGroupsCallbackState, - currentStepFiltersCallbackState, - setHasInitializedCurrentStepFilters, - setHasInitializedCurrentStepFilterGroups, - ], - ); + setHasInitializedCurrentStepFilters(true); + setHasInitializedCurrentStepFilterGroups(true); + + onFilterSettingsUpdate({ + stepFilterGroups: [newStepFilterGroup], + stepFilters: [newStepFilter], + }); + }, [ + onFilterSettingsUpdate, + currentStepFilterGroupsAtom, + currentStepFiltersAtom, + setHasInitializedCurrentStepFilters, + setHasInitializedCurrentStepFilterGroups, + store, + ]); return { - addRootStepFilter: addRootStepFilterRecoilCallback, + addRootStepFilter, }; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups.ts index b42c939811..8a3a306078 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups.ts @@ -1,4 +1,4 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState'; import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types'; @@ -9,11 +9,13 @@ export const useChildStepFiltersAndChildStepFilterGroups = ({ }: { stepFilterGroupId: string; }) => { - const stepFilterGroups = useRecoilComponentValue( + const stepFilterGroups = useRecoilComponentValueV2( currentStepFilterGroupsComponentState, ); - const stepFilters = useRecoilComponentValue(currentStepFiltersComponentState); + const stepFilters = useRecoilComponentValueV2( + currentStepFiltersComponentState, + ); const currentStepFilterGroup = stepFilterGroups?.find( (stepFilterGroup) => stepFilterGroup.id === stepFilterGroupId, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useFilterCounter.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useFilterCounter.ts index a5c9632f60..2a0922005b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useFilterCounter.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useFilterCounter.ts @@ -1,11 +1,11 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { createStepSelector } from '@/workflow/states/selectors/stepSelector'; import { useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useFilterCounter = ({ stepId }: { stepId: string }) => { const stepSelector = useMemo(() => createStepSelector(stepId), [stepId]); - const step = useRecoilComponentValue(stepSelector); + const step = useRecoilComponentSelectorValueV2(stepSelector); if (!isDefined(step)) { return { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilter.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilter.ts index a5436e7c8c..5940afe300 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilter.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilter.ts @@ -1,107 +1,100 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; export const useRemoveStepFilter = () => { const { onFilterSettingsUpdate } = useContext(WorkflowStepFilterContext); - const currentStepFiltersCallbackState = useRecoilComponentCallbackState( + const currentStepFiltersAtom = useRecoilComponentStateCallbackStateV2( currentStepFiltersComponentState, ); - const currentStepFilterGroupsCallbackState = useRecoilComponentCallbackState( + const currentStepFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( currentStepFilterGroupsComponentState, ); - const removeStepFilterRecoilCallback = useRecoilCallback( - ({ set, snapshot }) => - (stepFilterId: string) => { - const stepFilters = getSnapshotValue( - snapshot, - currentStepFiltersCallbackState, - ); + const store = useStore(); - const stepFilterGroups = getSnapshotValue( - snapshot, - currentStepFilterGroupsCallbackState, - ); + const removeStepFilter = useCallback( + (stepFilterId: string) => { + const stepFilters = store.get(currentStepFiltersAtom); + const stepFilterGroups = store.get(currentStepFilterGroupsAtom); - const rootStepFilterGroup = stepFilterGroups?.find( - (filterGroup) => !isDefined(filterGroup.parentStepFilterGroupId), - ); + const rootStepFilterGroup = stepFilterGroups.find( + (filterGroup) => !isDefined(filterGroup.parentStepFilterGroupId), + ); - if (!isDefined(rootStepFilterGroup)) return; + if (!isDefined(rootStepFilterGroup)) return; - const stepFilterToRemove = stepFilters?.find( - (filter) => filter.id === stepFilterId, - ); + const stepFilterToRemove = stepFilters.find( + (filter) => filter.id === stepFilterId, + ); - if (!isDefined(stepFilterToRemove)) return; + if (!isDefined(stepFilterToRemove)) return; - const updatedStepFilters = (stepFilters ?? []).filter( - (filter) => filter.id !== stepFilterId, - ); + const updatedStepFilters = stepFilters.filter( + (filter) => filter.id !== stepFilterId, + ); - const parentStepFilterGroup = stepFilterGroups?.find( - (filterGroup) => - filterGroup.id === stepFilterToRemove.stepFilterGroupId, - ); + const parentStepFilterGroup = stepFilterGroups.find( + (filterGroup) => + filterGroup.id === stepFilterToRemove.stepFilterGroupId, + ); - const stepFiltersInParentStepFilterGroup = updatedStepFilters?.filter( - (filter) => filter.stepFilterGroupId === parentStepFilterGroup?.id, - ); + const stepFiltersInParentStepFilterGroup = updatedStepFilters.filter( + (filter) => filter.stepFilterGroupId === parentStepFilterGroup?.id, + ); - const stepFilterGroupsInParentStepFilterGroup = - stepFilterGroups?.filter( - (g) => g.parentStepFilterGroupId === parentStepFilterGroup?.id, - ); + const stepFilterGroupsInParentStepFilterGroup = stepFilterGroups.filter( + (group) => group.parentStepFilterGroupId === parentStepFilterGroup?.id, + ); - const shouldDeleteParentStepFilterGroup = - stepFiltersInParentStepFilterGroup?.length === 0 && - stepFilterGroupsInParentStepFilterGroup?.length === 0; + const shouldDeleteParentStepFilterGroup = + stepFiltersInParentStepFilterGroup.length === 0 && + stepFilterGroupsInParentStepFilterGroup.length === 0; - const updatedStepFilterGroups = shouldDeleteParentStepFilterGroup - ? (stepFilterGroups ?? []).filter( - (filterGroup) => filterGroup.id !== parentStepFilterGroup?.id, - ) - : stepFilterGroups; + const updatedStepFilterGroups = shouldDeleteParentStepFilterGroup + ? stepFilterGroups.filter( + (filterGroup) => filterGroup.id !== parentStepFilterGroup?.id, + ) + : stepFilterGroups; - const shouldResetStepFilterSettings = - updatedStepFilterGroups.length === 1 && - updatedStepFilterGroups[0].id === rootStepFilterGroup?.id && - updatedStepFilters.length === 0; + const shouldResetStepFilterSettings = + updatedStepFilterGroups.length === 1 && + updatedStepFilterGroups[0].id === rootStepFilterGroup?.id && + updatedStepFilters.length === 0; - if (shouldResetStepFilterSettings) { - set(currentStepFilterGroupsCallbackState, []); - set(currentStepFiltersCallbackState, []); + if (shouldResetStepFilterSettings) { + store.set(currentStepFilterGroupsAtom, []); + store.set(currentStepFiltersAtom, []); - onFilterSettingsUpdate({ - stepFilterGroups: [], - stepFilters: [], - }); - } else { - set(currentStepFilterGroupsCallbackState, updatedStepFilterGroups); - set(currentStepFiltersCallbackState, updatedStepFilters); + onFilterSettingsUpdate({ + stepFilterGroups: [], + stepFilters: [], + }); + } else { + store.set(currentStepFilterGroupsAtom, updatedStepFilterGroups); + store.set(currentStepFiltersAtom, updatedStepFilters); - onFilterSettingsUpdate({ - stepFilters: updatedStepFilters, - stepFilterGroups: updatedStepFilterGroups, - }); - } - }, + onFilterSettingsUpdate({ + stepFilters: updatedStepFilters, + stepFilterGroups: updatedStepFilterGroups, + }); + } + }, [ onFilterSettingsUpdate, - currentStepFilterGroupsCallbackState, - currentStepFiltersCallbackState, + currentStepFilterGroupsAtom, + currentStepFiltersAtom, + store, ], ); return { - removeStepFilter: removeStepFilterRecoilCallback, + removeStepFilter, }; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilterGroup.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilterGroup.ts index fba01adbd7..4f46831d79 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilterGroup.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useRemoveStepFilterGroup.ts @@ -1,79 +1,73 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useRemoveStepFilterGroup = () => { const { onFilterSettingsUpdate } = useContext(WorkflowStepFilterContext); - const currentStepFilterGroupsCallbackState = useRecoilComponentCallbackState( + const currentStepFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( currentStepFilterGroupsComponentState, ); - const currentStepFiltersCallbackState = useRecoilComponentCallbackState( + const currentStepFiltersAtom = useRecoilComponentStateCallbackStateV2( currentStepFiltersComponentState, ); - const removeStepFilterGroupRecoilCallback = useRecoilCallback( - ({ set, snapshot }) => - (stepFilterGroupId: string) => { - const stepFilterGroups = getSnapshotValue( - snapshot, - currentStepFilterGroupsCallbackState, - ); + const store = useStore(); - const stepFilters = getSnapshotValue( - snapshot, - currentStepFiltersCallbackState, - ); + const removeStepFilterGroup = useCallback( + (stepFilterGroupId: string) => { + const stepFilterGroups = store.get(currentStepFilterGroupsAtom); + const stepFilters = store.get(currentStepFiltersAtom); - const rootStepFilterGroup = stepFilterGroups?.find( - (filterGroup) => !isDefined(filterGroup.parentStepFilterGroupId), - ); + const rootStepFilterGroup = stepFilterGroups.find( + (filterGroup) => !isDefined(filterGroup.parentStepFilterGroupId), + ); - const updatedStepFilterGroups = (stepFilterGroups ?? []).filter( - (filterGroup) => filterGroup.id !== stepFilterGroupId, - ); + const updatedStepFilterGroups = stepFilterGroups.filter( + (filterGroup) => filterGroup.id !== stepFilterGroupId, + ); - const updatedStepFilters = (stepFilters ?? []).filter( - (filter) => filter.stepFilterGroupId !== stepFilterGroupId, - ); + const updatedStepFilters = stepFilters.filter( + (filter) => filter.stepFilterGroupId !== stepFilterGroupId, + ); - const shouldResetStepFilterSettings = - updatedStepFilterGroups.length === 1 && - updatedStepFilterGroups[0].id === rootStepFilterGroup?.id && - updatedStepFilters.length === 0; + const shouldResetStepFilterSettings = + updatedStepFilterGroups.length === 1 && + updatedStepFilterGroups[0].id === rootStepFilterGroup?.id && + updatedStepFilters.length === 0; - if (shouldResetStepFilterSettings) { - set(currentStepFilterGroupsCallbackState, []); - set(currentStepFiltersCallbackState, []); + if (shouldResetStepFilterSettings) { + store.set(currentStepFilterGroupsAtom, []); + store.set(currentStepFiltersAtom, []); - onFilterSettingsUpdate({ - stepFilterGroups: [], - stepFilters: [], - }); - } else { - set(currentStepFilterGroupsCallbackState, updatedStepFilterGroups); - set(currentStepFiltersCallbackState, updatedStepFilters); + onFilterSettingsUpdate({ + stepFilterGroups: [], + stepFilters: [], + }); + } else { + store.set(currentStepFilterGroupsAtom, updatedStepFilterGroups); + store.set(currentStepFiltersAtom, updatedStepFilters); - onFilterSettingsUpdate({ - stepFilterGroups: updatedStepFilterGroups, - stepFilters: updatedStepFilters, - }); - } - }, + onFilterSettingsUpdate({ + stepFilterGroups: updatedStepFilterGroups, + stepFilters: updatedStepFilters, + }); + } + }, [ onFilterSettingsUpdate, - currentStepFilterGroupsCallbackState, - currentStepFiltersCallbackState, + currentStepFilterGroupsAtom, + currentStepFiltersAtom, + store, ], ); return { - removeStepFilterGroup: removeStepFilterGroupRecoilCallback, + removeStepFilterGroup, }; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings.ts index ed79b2e7e7..36e54ec861 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings.ts @@ -1,84 +1,78 @@ -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFiltersComponentState'; -import { useContext } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useContext } from 'react'; import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const useUpsertStepFilterSettings = () => { - const currentStepFilterGroupsCallbackState = useRecoilComponentCallbackState( + const currentStepFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( currentStepFilterGroupsComponentState, ); - const currentStepFiltersCallbackState = useRecoilComponentCallbackState( + const currentStepFiltersAtom = useRecoilComponentStateCallbackStateV2( currentStepFiltersComponentState, ); const { onFilterSettingsUpdate } = useContext(WorkflowStepFilterContext); - const upsertStepFilterSettingsRecoilCallback = useRecoilCallback( - ({ set, snapshot }) => - ({ - stepFilterGroupToUpsert, - stepFilterToUpsert, - }: { - stepFilterGroupToUpsert?: StepFilterGroup; - stepFilterToUpsert?: StepFilter; - }) => { - const stepFilterGroups = getSnapshotValue( - snapshot, - currentStepFilterGroupsCallbackState, + const store = useStore(); + + const upsertStepFilterSettings = useCallback( + ({ + stepFilterGroupToUpsert, + stepFilterToUpsert, + }: { + stepFilterGroupToUpsert?: StepFilterGroup; + stepFilterToUpsert?: StepFilter; + }) => { + const stepFilterGroups = store.get(currentStepFilterGroupsAtom); + const stepFilters = store.get(currentStepFiltersAtom); + + const updatedStepFilterGroups = [...stepFilterGroups]; + const updatedStepFilters = [...stepFilters]; + + if (isDefined(stepFilterGroupToUpsert)) { + const existingIndex = updatedStepFilterGroups.findIndex( + (filterGroup) => filterGroup.id === stepFilterGroupToUpsert.id, ); - const stepFilters = getSnapshotValue( - snapshot, - currentStepFiltersCallbackState, + if (existingIndex >= 0) { + updatedStepFilterGroups[existingIndex] = stepFilterGroupToUpsert; + } else { + updatedStepFilterGroups.push(stepFilterGroupToUpsert); + } + store.set(currentStepFilterGroupsAtom, updatedStepFilterGroups); + } + + if (isDefined(stepFilterToUpsert)) { + const existingIndex = updatedStepFilters.findIndex( + (filter) => filter.id === stepFilterToUpsert.id, ); - const updatedStepFilterGroups = [...(stepFilterGroups ?? [])]; - const updatedStepFilters = [...(stepFilters ?? [])]; - - if (isDefined(stepFilterGroupToUpsert)) { - const existingIndex = updatedStepFilterGroups.findIndex( - (filterGroup) => filterGroup.id === stepFilterGroupToUpsert.id, - ); - - if (existingIndex >= 0) { - updatedStepFilterGroups[existingIndex] = stepFilterGroupToUpsert; - } else { - updatedStepFilterGroups.push(stepFilterGroupToUpsert); - } - set(currentStepFilterGroupsCallbackState, updatedStepFilterGroups); + if (existingIndex >= 0) { + updatedStepFilters[existingIndex] = stepFilterToUpsert; + } else { + updatedStepFilters.push(stepFilterToUpsert); } + store.set(currentStepFiltersAtom, updatedStepFilters); + } - if (isDefined(stepFilterToUpsert)) { - const existingIndex = updatedStepFilters.findIndex( - (filter) => filter.id === stepFilterToUpsert.id, - ); - - if (existingIndex >= 0) { - updatedStepFilters[existingIndex] = stepFilterToUpsert; - } else { - updatedStepFilters.push(stepFilterToUpsert); - } - set(currentStepFiltersCallbackState, updatedStepFilters); - } - - onFilterSettingsUpdate({ - stepFilterGroups: updatedStepFilterGroups, - stepFilters: updatedStepFilters, - }); - }, + onFilterSettingsUpdate({ + stepFilterGroups: updatedStepFilterGroups, + stepFilters: updatedStepFilters, + }); + }, [ onFilterSettingsUpdate, - currentStepFilterGroupsCallbackState, - currentStepFiltersCallbackState, + currentStepFilterGroupsAtom, + currentStepFiltersAtom, + store, ], ); return { - upsertStepFilterSettings: upsertStepFilterSettingsRecoilCallback, + upsertStepFilterSettings, }; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState.ts index 7ee54b30b0..992a8e13f2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext'; import { type StepFilterGroup } from 'twenty-shared/types'; -export const currentStepFilterGroupsComponentState = createComponentState< +export const currentStepFilterGroupsComponentState = createComponentStateV2< StepFilterGroup[] >({ key: 'currentStepFilterGroupsComponentState', diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFiltersComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFiltersComponentState.ts index 6ac181407e..d6718d20c1 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFiltersComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/currentStepFiltersComponentState.ts @@ -1,8 +1,8 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext'; import { type StepFilter } from 'twenty-shared/types'; -export const currentStepFiltersComponentState = createComponentState< +export const currentStepFiltersComponentState = createComponentStateV2< StepFilter[] >({ key: 'currentStepFiltersComponentState', diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState.ts index aa9d4256d8..cfb778a75f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState.ts @@ -1,8 +1,8 @@ -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext'; export const hasInitializedCurrentStepFilterGroupsComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedCurrentStepFilterGroupsComponentFamilyState', defaultValue: false, componentInstanceContext: StepFilterGroupsComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState.ts index e3919a11b3..287850e3aa 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/hasInitializedCurrentStepFiltersComponentFamilyState.ts @@ -1,8 +1,8 @@ -import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentFamilyStateV2'; import { StepFiltersComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFiltersComponentInstanceContext'; export const hasInitializedCurrentStepFiltersComponentFamilyState = - createComponentFamilyState({ + createComponentFamilyStateV2({ key: 'hasInitializedCurrentStepFiltersComponentFamilyState', defaultValue: false, componentInstanceContext: StepFiltersComponentInstanceContext, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/rootLevelStepFilterGroupComponentSelector.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/rootLevelStepFilterGroupComponentSelector.ts index c13168a41e..1a0cf227f7 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/rootLevelStepFilterGroupComponentSelector.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/states/rootLevelStepFilterGroupComponentSelector.ts @@ -1,16 +1,18 @@ -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; +import { createComponentSelectorV2 } from '@/ui/utilities/state/jotai/utils/createComponentSelectorV2'; import { StepFilterGroupsComponentInstanceContext } from '@/workflow/workflow-steps/filters/states/context/StepFilterGroupsComponentInstanceContext'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/filters/states/currentStepFilterGroupsComponentState'; +import { type StepFilterGroup } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const rootLevelStepFilterGroupComponentSelector = - createComponentSelector({ + createComponentSelectorV2({ key: 'rootLevelStepFilterGroupComponentSelector', get: ({ instanceId }) => ({ get }) => { const currentStepFilterGroups = get( - currentStepFilterGroupsComponentState.atomFamily({ instanceId }), + currentStepFilterGroupsComponentState, + { instanceId }, ); const rootLevelStepFilterGroup = currentStepFilterGroups.find( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts index 6d866294e0..fe91b9d12f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts @@ -1,4 +1,4 @@ -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState'; import { type WorkflowActionType } from '@/workflow/types/Workflow'; @@ -18,10 +18,10 @@ import { v4 } from 'uuid'; export const useCreateStep = () => { const [isLoading, setIsLoading] = useState(false); const { createWorkflowVersionStep } = useCreateWorkflowVersionStep(); - const setWorkflowSelectedNode = useSetRecoilComponentState( + const setWorkflowSelectedNode = useSetRecoilComponentStateV2( workflowSelectedNodeComponentState, ); - const setWorkflowLastCreatedStepId = useSetRecoilComponentState( + const setWorkflowLastCreatedStepId = useSetRecoilComponentStateV2( workflowLastCreatedStepIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep.ts index 7031095bc5..b85faf0d4e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep.ts @@ -8,7 +8,7 @@ import { } from '~/generated/graphql'; import { useUpdateWorkflowVersionCache } from '@/workflow/workflow-steps/hooks/useUpdateWorkflowVersionCache'; import { flowComponentState } from '@/workflow/states/flowComponentState'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isDefined } from 'twenty-shared/utils'; export const useCreateWorkflowVersionStep = () => { @@ -16,7 +16,7 @@ export const useCreateWorkflowVersionStep = () => { const { updateWorkflowVersionCache } = useUpdateWorkflowVersionCache(); - const setFlow = useSetRecoilComponentState(flowComponentState); + const setFlow = useSetRecoilComponentStateV2(flowComponentState); const [mutate] = useMutation< CreateWorkflowVersionStepMutation, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts index 71e612fa2f..c508b371ba 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts @@ -1,5 +1,5 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; @@ -17,7 +17,7 @@ export const useDeleteStep = () => { const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersionOrThrow(); const { closeCommandMenu } = useCommandMenu(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateStep.ts index 2ec9e3d582..5d7f8b15a9 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateStep.ts @@ -1,4 +1,4 @@ -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; @@ -10,10 +10,10 @@ import { isDefined } from 'twenty-shared/utils'; export const useDuplicateStep = () => { const [isLoading, setIsLoading] = useState(false); const { duplicateWorkflowVersionStep } = useDuplicateWorkflowVersionStep(); - const setWorkflowSelectedNode = useSetRecoilComponentState( + const setWorkflowSelectedNode = useSetRecoilComponentStateV2( workflowSelectedNodeComponentState, ); - const setWorkflowLastCreatedStepId = useSetRecoilComponentState( + const setWorkflowLastCreatedStepId = useSetRecoilComponentStateV2( workflowLastCreatedStepIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateWorkflowVersionStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateWorkflowVersionStep.ts index db9b144389..68bae309db 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateWorkflowVersionStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateWorkflowVersionStep.ts @@ -1,5 +1,5 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { DUPLICATE_WORKFLOW_VERSION_STEP } from '@/workflow/graphql/mutations/duplicateWorkflowVersionStep'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import { useUpdateWorkflowVersionCache } from '@/workflow/workflow-steps/hooks/useUpdateWorkflowVersionCache'; @@ -16,7 +16,7 @@ export const useDuplicateWorkflowVersionStep = () => { const { updateWorkflowVersionCache } = useUpdateWorkflowVersionCache(); - const setFlow = useSetRecoilComponentState(flowComponentState); + const setFlow = useSetRecoilComponentStateV2(flowComponentState); const [mutate] = useMutation< DuplicateWorkflowVersionStepMutation, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useWorkflowRunStepInfo.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useWorkflowRunStepInfo.ts index f9e492d810..e973a82465 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useWorkflowRunStepInfo.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useWorkflowRunStepInfo.ts @@ -1,5 +1,5 @@ import { workflowRunIteratorSubStepIterationIndexComponentState } from '@/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; import { isDefined } from 'twenty-shared/utils'; @@ -9,7 +9,7 @@ export const useWorkflowRunStepInfo = ({ stepId }: { stepId: string }) => { const workflowRunId = useWorkflowRunIdOrThrow(); const workflowRun = useWorkflowRun({ workflowRunId }); - const workflowRunIteratorSubStepIterationIndex = useRecoilComponentValue( + const workflowRunIteratorSubStepIterationIndex = useRecoilComponentValueV2( workflowRunIteratorSubStepIterationIndexComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowInsertStepIdsComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowInsertStepIdsComponentState.ts index d8ebdb12e5..e69063c573 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowInsertStepIdsComponentState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowInsertStepIdsComponentState.ts @@ -1,4 +1,4 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { type WorkflowStepConnectionOptions } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowStepConnectionOptions'; @@ -10,7 +10,7 @@ type WorkflowInsertStepIdsState = { }; export const workflowInsertStepIdsComponentState = - createComponentState({ + createComponentStateV2({ key: 'workflowInsertStepIdsComponentState', defaultValue: { parentStepId: undefined, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx index aed74ab81d..f15ef6bf4c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx @@ -17,16 +17,14 @@ import { TabList } from '@/ui/layout/tab-list/components/TabList'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowCodeEditor } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowCodeEditor'; import { WorkflowEditActionCodeFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields'; import { WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowLogicFunctionTabListComponentId'; -import { - type LogicFunctionTestData, - logicFunctionTestDataFamilyState, -} from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; +import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState'; import { WorkflowLogicFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowLogicFunctionTabId'; import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; @@ -39,7 +37,6 @@ import { type Monaco } from '@monaco-editor/react'; import { type editor } from 'monaco-editor'; import { AutoTypings } from 'monaco-editor-auto-typings'; import { useState } from 'react'; -import { useRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; import { isDefined } from 'twenty-shared/utils'; import { @@ -105,7 +102,7 @@ export const WorkflowEditActionCode = ({ const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersionOrThrow(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId); @@ -131,10 +128,14 @@ export const WorkflowEditActionCode = ({ id: logicFunctionId, }); - const [logicFunctionTestData, setLogicFunctionTestData] = - useRecoilState( - logicFunctionTestDataFamilyState(logicFunctionId), - ); + const logicFunctionTestData = useFamilyRecoilValueV2( + logicFunctionTestDataFamilyState, + logicFunctionId, + ); + const setLogicFunctionTestData = useSetFamilyRecoilStateV2( + logicFunctionTestDataFamilyState, + logicFunctionId, + ); const [functionInput, setFunctionInput] = useState( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState.ts index ae90ab4000..7ad5113bb2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState.ts @@ -1,4 +1,4 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { LogicFunctionExecutionStatus } from '~/generated-metadata/graphql'; export type LogicFunctionTestData = { @@ -21,7 +21,7 @@ export const DEFAULT_OUTPUT_VALUE = { status: LogicFunctionExecutionStatus.IDLE, }; -export const logicFunctionTestDataFamilyState = createFamilyState< +export const logicFunctionTestDataFamilyState = createFamilyStateV2< LogicFunctionTestData, string >({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx index fec2e7a4e0..24803b02cb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx @@ -17,7 +17,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; @@ -62,7 +62,7 @@ export const WorkflowEditActionEmailBase = ({ const { enqueueErrorSnackBar } = useSnackBar(); const { uploadAttachmentFile } = useUploadAttachmentFile(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx index 89c5efd22e..f100ca9837 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx @@ -1,5 +1,5 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; import { type WorkflowFilterAction } from '@/workflow/types/Workflow'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterAddFilterRuleSelect'; @@ -49,7 +49,7 @@ export const WorkflowEditActionFilterBody = ({ action, actionOptions, }: WorkflowEditActionFilterBodyProps) => { - const rootStepFilterGroup = useRecoilComponentValue( + const rootStepFilterGroup = useRecoilComponentSelectorValueV2( rootLevelStepFilterGroupComponentSelector, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx index 734aa13f93..786c798f1e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx @@ -3,13 +3,13 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { AdvancedFilterCommandMenuContainer } from '@/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuContainer'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2'; import { type FindRecordsActionFilter } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; export const WorkflowFindRecordsFilters = ({ objectMetadataItem, @@ -20,39 +20,33 @@ export const WorkflowFindRecordsFilters = ({ onChange: (filter: FindRecordsActionFilter) => void; readonly?: boolean; }) => { - const currentRecordFilterGroupsCallbackState = - useRecoilComponentCallbackState(currentRecordFilterGroupsComponentState); + const currentRecordFilterGroupsAtom = useRecoilComponentStateCallbackStateV2( + currentRecordFilterGroupsComponentState, + ); - const currentRecordFiltersCallbackState = useRecoilComponentCallbackState( + const currentRecordFiltersAtom = useRecoilComponentStateCallbackStateV2( currentRecordFiltersComponentState, ); - const onUpdate = useRecoilCallback( - ({ snapshot }) => - () => { - const currentRecordFilterGroups = getSnapshotValue( - snapshot, - currentRecordFilterGroupsCallbackState, - ); + const store = useStore(); - const currentRecordFilters = getSnapshotValue( - snapshot, - currentRecordFiltersCallbackState, - ); + const onUpdate = useCallback(() => { + const currentRecordFilterGroups = store.get(currentRecordFilterGroupsAtom); - const newFilter = { - recordFilterGroups: currentRecordFilterGroups, - recordFilters: currentRecordFilters, - } satisfies FindRecordsActionFilter; + const currentRecordFilters = store.get(currentRecordFiltersAtom); - onChange(newFilter); - }, - [ - currentRecordFilterGroupsCallbackState, - currentRecordFiltersCallbackState, - onChange, - ], - ); + const newFilter = { + recordFilterGroups: currentRecordFilterGroups, + recordFilters: currentRecordFilters, + } satisfies FindRecordsActionFilter; + + onChange(newFilter); + }, [ + currentRecordFilterGroupsAtom, + currentRecordFiltersAtom, + onChange, + store, + ]); return ( { - const [httpRequestTestData, setHttpRequestTestData] = useRecoilState( - httpRequestTestDataFamilyState(actionId), + const httpRequestTestData = useFamilyRecoilValueV2( + httpRequestTestDataFamilyState, + actionId, + ); + const setHttpRequestTestData = useSetFamilyRecoilStateV2( + httpRequestTestDataFamilyState, + actionId, ); const mockStep: WorkflowStep = { id: 'test-step', diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useTestHttpRequest.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useTestHttpRequest.ts index eac8a4f5fa..bd26575fbc 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useTestHttpRequest.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useTestHttpRequest.ts @@ -4,12 +4,13 @@ import { type HttpRequestFormData, } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest'; import { TEST_HTTP_REQUEST } from '@/workflow/workflow-steps/workflow-actions/http-request-action/graphql/mutations/testHttpRequest'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { httpRequestTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/http-request-action/states/httpRequestTestDataFamilyState'; import { useMutation } from '@apollo/client'; import { t } from '@lingui/core/macro'; import { isObject, isString } from '@sniptt/guards'; import { useState } from 'react'; -import { useRecoilState } from 'recoil'; import { isDefined, parseJson, resolveInput } from 'twenty-shared/utils'; import { type TestHttpRequestInput, @@ -43,8 +44,13 @@ const convertFlatVariablesToNestedContext = (flatVariables: { export const useTestHttpRequest = (actionId: string) => { const apolloCoreClient = useApolloCoreClient(); const [isTesting, setIsTesting] = useState(false); - const [httpRequestTestData, setHttpRequestTestData] = useRecoilState( - httpRequestTestDataFamilyState(actionId), + const httpRequestTestData = useFamilyRecoilValueV2( + httpRequestTestDataFamilyState, + actionId, + ); + const setHttpRequestTestData = useSetFamilyRecoilStateV2( + httpRequestTestDataFamilyState, + actionId, ); const [mutate] = useMutation< diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/states/httpRequestTestDataFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/states/httpRequestTestDataFamilyState.ts index a8cabb6a20..8c3393b003 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/states/httpRequestTestDataFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/states/httpRequestTestDataFamilyState.ts @@ -1,8 +1,8 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { DEFAULT_HTTP_REQUEST_OUTPUT_VALUE } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest'; import { type HttpRequestTestData } from '@/workflow/workflow-steps/workflow-actions/http-request-action/types/HttpRequestTestData'; -export const httpRequestTestDataFamilyState = createFamilyState< +export const httpRequestTestDataFamilyState = createFamilyStateV2< HttpRequestTestData, string >({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx index ec64670109..cdf73a8cd1 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx @@ -1,6 +1,6 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; @@ -68,21 +68,21 @@ export const WorkflowEditActionIfElseBody = ({ const { updateWorkflowVersionPosition } = useTidyUpWorkflowVersion(); const { deleteWorkflowVersionStep } = useDeleteWorkflowVersionStep(); const { deleteStepsOutputSchema } = useStepsOutputSchema(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId); - const currentStepFilters = useRecoilComponentValue( + const currentStepFilters = useRecoilComponentValueV2( currentStepFiltersComponentState, ); - const currentStepFilterGroups = useRecoilComponentValue( + const currentStepFilterGroups = useRecoilComponentValueV2( currentStepFilterGroupsComponentState, ); - const setCurrentStepFilters = useSetRecoilComponentState( + const setCurrentStepFilters = useSetRecoilComponentStateV2( currentStepFiltersComponentState, ); - const setCurrentStepFilterGroups = useSetRecoilComponentState( + const setCurrentStepFilterGroups = useSetRecoilComponentStateV2( currentStepFilterGroupsComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx index 78eacb8859..3a128e4a33 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx @@ -1,5 +1,5 @@ import { workflowRunIteratorSubStepIterationIndexComponentState } from '@/command-menu/pages/workflow/step/view-run/states/workflowRunIteratorSubStepIterationIndexComponentState'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; @@ -37,7 +37,7 @@ export const WorkflowIteratorSubStepSwitcher = ({ const [ workflowRunIteratorSubStepIterationIndex, setWorkflowRunIteratorSubStepIterationIndex, - ] = useRecoilComponentState( + ] = useRecoilComponentStateV2( workflowRunIteratorSubStepIterationIndexComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx index 39b1d631f3..5d449caa19 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx @@ -5,11 +5,11 @@ import { calculateNextExecutionsForMinuteInterval } from '@/workflow/workflow-tr import { convertScheduleToCronExpression } from '@/workflow/workflow-trigger/utils/cron-to-human/utils/convertScheduleToCronExpression'; import { normalizeCronExpression } from '@/workflow/workflow-trigger/utils/cron-to-human/utils/normalizeCronExpression'; import { getTriggerScheduleDescription } from '@/workflow/workflow-trigger/utils/getTriggerScheduleDescription'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { CronExpressionParser } from 'cron-parser'; -import { useRecoilValue } from 'recoil'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { formatDateTimeString } from '~/utils/string/formatDateTimeString'; const getNextExecutions = ( @@ -93,7 +93,7 @@ export const CronExpressionHelper = ({ isUpcomingExecutionVisible = true, }: CronExpressionHelperProps) => { const { timeZone, dateFormat, timeFormat } = useDateTimeFormat(); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); if (!isVisible) { return null; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx index 416d19d7f8..822d8842e9 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx @@ -11,13 +11,13 @@ import { } from '@/workflow/workflow-trigger/constants/CronTriggerIntervalOptions'; import { getCronTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getCronTriggerDefaultSettings'; import { getTriggerScheduleDescription } from '@/workflow/workflow-trigger/utils/getTriggerScheduleDescription'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { t } from '@lingui/core/macro'; import { isNumber } from '@sniptt/guards'; import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; type WorkflowEditTriggerCronFormProps = { trigger: WorkflowCronTrigger; @@ -48,7 +48,7 @@ export const WorkflowEditTriggerCronForm = ({ }: WorkflowEditTriggerCronFormProps) => { const [errorMessages, setErrorMessages] = useState({}); const [errorMessagesVisible, setErrorMessagesVisible] = useState(false); - const dateLocale = useRecoilValue(dateLocaleState); + const dateLocale = useRecoilValueV2(dateLocaleStateV2); const customDescription = getTriggerScheduleDescription( trigger, diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx index dc99ef01d6..50ed1c7562 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx @@ -3,7 +3,7 @@ import { FormRawJsonFieldInput } from '@/object-record/record-field/ui/form-type import { Select } from '@/ui/input/components/Select'; import { TextInput } from '@/ui/input/components/TextInput'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { type WorkflowWebhookTrigger } from '@/workflow/types/Workflow'; import { parseAndValidateVariableFriendlyStringifiedJson } from '@/workflow/utils/parseAndValidateVariableFriendlyStringifiedJson'; @@ -54,7 +54,7 @@ export const WorkflowEditTriggerWebhookForm = ({ const { copyToClipboard } = useCopyToClipboard(); const [errorMessages, setErrorMessages] = useState({}); const [errorMessagesVisible, setErrorMessagesVisible] = useState(false); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); const currentWorkspace = useRecoilValueV2(currentWorkspaceState); diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts index c4b070b7ec..0990550c67 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts @@ -1,4 +1,5 @@ -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector'; import { @@ -9,7 +10,6 @@ import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/ import { getPreviousSteps } from '@/workflow/workflow-steps/utils/getWorkflowPreviousSteps'; import { type StepOutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2'; import { filterOutputSchema } from '@/workflow/workflow-variables/utils/filterOutputSchema'; -import { useRecoilValue } from 'recoil'; import { isDefined, isEmptyObject } from 'twenty-shared/utils'; export const useAvailableVariablesInWorkflowStep = ({ @@ -21,7 +21,7 @@ export const useAvailableVariablesInWorkflowStep = ({ shouldDisplayRecordObjects: boolean; fieldTypesToExclude?: InputSchemaPropertyType[]; }): StepOutputSchemaV2[] => { - const workflowSelectedNode = useRecoilComponentValue( + const workflowSelectedNode = useRecoilComponentValueV2( workflowSelectedNodeComponentState, ); const flow = useFlowOrThrow(); @@ -32,12 +32,11 @@ export const useAvailableVariablesInWorkflowStep = ({ ? getPreviousSteps({ steps, currentStep }).map((step) => step.id) : []; - const availableStepsOutputSchema: StepOutputSchemaV2[] = useRecoilValue( - stepsOutputSchemaFamilySelector({ + const availableStepsOutputSchema: StepOutputSchemaV2[] = + useFamilySelectorValueV2(stepsOutputSchemaFamilySelector, { workflowVersionId: flow.workflowVersionId, stepIds: [TRIGGER_STEP_ID, ...previousStepIds], - }), - ); + }); const availableVariablesInWorkflowStep = availableStepsOutputSchema .map((stepOutputSchema) => { diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useSearchVariable.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useSearchVariable.ts index ad1883dff1..932ad63c26 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useSearchVariable.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useSearchVariable.ts @@ -1,8 +1,8 @@ +import { useFamilySelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilySelectorValueV2'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowVersionIdOrThrow } from '@/workflow/hooks/useWorkflowVersionIdOrThrow'; import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector'; import { searchVariableThroughOutputSchemaV2 } from '@/workflow/workflow-variables/utils/searchVariableThroughOutputSchemaV2'; -import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; @@ -25,11 +25,12 @@ export const useSearchVariable = ({ }): VariableSearchResult => { const workflowVersionId = useWorkflowVersionIdOrThrow(); const flow = useFlowOrThrow(); - const [stepOutputSchema] = useRecoilValue( - stepsOutputSchemaFamilySelector({ + const [stepOutputSchema] = useFamilySelectorValueV2( + stepsOutputSchemaFamilySelector, + { workflowVersionId, stepIds: [stepId], - }), + }, ); if (!isDefined(stepOutputSchema)) { diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useStepsOutputSchema.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useStepsOutputSchema.ts index c081e14124..55f74fc2cb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useStepsOutputSchema.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useStepsOutputSchema.ts @@ -15,140 +15,155 @@ import { shouldComputeOutputSchemaOnFrontend, } from '@/workflow/workflow-variables/utils/generate/computeStepOutputSchema'; import { useStore } from 'jotai'; -import { useRecoilCallback } from 'recoil'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; export const useStepsOutputSchema = () => { const store = useStore(); - const populateStepsOutputSchema = useRecoilCallback( - ({ set, snapshot }) => - (workflowVersion: WorkflowVersion) => { - const objectMetadataItems = store.get(objectMetadataItemsState.atom); + const populateStepsOutputSchema = useCallback( + (workflowVersion: WorkflowVersion) => { + const objectMetadataItems = store.get(objectMetadataItemsState.atom); - workflowVersion.steps?.forEach((step) => { - const stepKey = getStepOutputSchemaFamilyStateKey( - workflowVersion.id, - step.id, - ); + workflowVersion.steps?.forEach((step) => { + const stepKey = getStepOutputSchemaFamilyStateKey( + workflowVersion.id, + step.id, + ); - const shouldRecompute = snapshot - .getLoadable(shouldRecomputeOutputSchemaFamilyState(stepKey)) - .getValue(); + const shouldRecompute = store.get( + shouldRecomputeOutputSchemaFamilyState.atomFamily(stepKey), + ); - const shouldComputeOnFrontend = shouldComputeOutputSchemaOnFrontend( - step.type, - ); + const shouldComputeOnFrontend = shouldComputeOutputSchemaOnFrontend( + step.type, + ); - if (!shouldRecompute) { - return; - } - - const outputSchema = shouldComputeOnFrontend - ? computeStepOutputSchema({ - step, - objectMetadataItems, - }) - : step.settings?.outputSchema; - - const stepOutputSchema: StepOutputSchemaV2 = { - id: step.id, - name: step.name, - type: step.type, - icon: getActionIcon(step.type), - outputSchema: (outputSchema ?? {}) as OutputSchemaV2, - objectName: (step.settings?.input as { objectName?: string }) - ?.objectName, - }; - - set(stepsOutputSchemaFamilyState(stepKey), stepOutputSchema); - set(shouldRecomputeOutputSchemaFamilyState(stepKey), false); - }); - - const trigger = workflowVersion.trigger; - - if (isDefined(trigger)) { - const triggerKey = getStepOutputSchemaFamilyStateKey( - workflowVersion.id, - TRIGGER_STEP_ID, - ); - - const shouldRecompute = snapshot - .getLoadable(shouldRecomputeOutputSchemaFamilyState(triggerKey)) - .getValue(); - - const shouldComputeOnFrontend = shouldComputeOutputSchemaOnFrontend( - trigger.type, - ); - - if (!shouldRecompute) { - return; - } - - const triggerIconKey = getTriggerIcon(trigger); - - const outputSchema = shouldComputeOnFrontend - ? computeStepOutputSchema({ - step: trigger, - objectMetadataItems, - }) - : trigger.settings?.outputSchema; - - const triggerOutputSchema: StepOutputSchemaV2 = { - id: TRIGGER_STEP_ID, - name: isDefined(trigger.name) - ? trigger.name - : getTriggerDefaultLabel(trigger), - type: trigger.type, - icon: triggerIconKey, - outputSchema: (outputSchema ?? {}) as OutputSchemaV2, - }; - - set(stepsOutputSchemaFamilyState(triggerKey), triggerOutputSchema); - set(shouldRecomputeOutputSchemaFamilyState(triggerKey), false); + if (!shouldRecompute) { + return; } - }, + + const outputSchema = shouldComputeOnFrontend + ? computeStepOutputSchema({ + step, + objectMetadataItems, + }) + : step.settings?.outputSchema; + + const stepOutputSchema: StepOutputSchemaV2 = { + id: step.id, + name: step.name, + type: step.type, + icon: getActionIcon(step.type), + outputSchema: (outputSchema ?? {}) as OutputSchemaV2, + objectName: (step.settings?.input as { objectName?: string }) + ?.objectName, + }; + + store.set( + stepsOutputSchemaFamilyState.atomFamily(stepKey), + stepOutputSchema, + ); + store.set( + shouldRecomputeOutputSchemaFamilyState.atomFamily(stepKey), + false, + ); + }); + + const trigger = workflowVersion.trigger; + + if (isDefined(trigger)) { + const triggerKey = getStepOutputSchemaFamilyStateKey( + workflowVersion.id, + TRIGGER_STEP_ID, + ); + + const shouldRecompute = store.get( + shouldRecomputeOutputSchemaFamilyState.atomFamily(triggerKey), + ); + + const shouldComputeOnFrontend = shouldComputeOutputSchemaOnFrontend( + trigger.type, + ); + + if (!shouldRecompute) { + return; + } + + const triggerIconKey = getTriggerIcon(trigger); + + const outputSchema = shouldComputeOnFrontend + ? computeStepOutputSchema({ + step: trigger, + objectMetadataItems, + }) + : trigger.settings?.outputSchema; + + const triggerOutputSchema: StepOutputSchemaV2 = { + id: TRIGGER_STEP_ID, + name: isDefined(trigger.name) + ? trigger.name + : getTriggerDefaultLabel(trigger), + type: trigger.type, + icon: triggerIconKey, + outputSchema: (outputSchema ?? {}) as OutputSchemaV2, + }; + + store.set( + stepsOutputSchemaFamilyState.atomFamily(triggerKey), + triggerOutputSchema, + ); + store.set( + shouldRecomputeOutputSchemaFamilyState.atomFamily(triggerKey), + false, + ); + } + }, [store], ); - const markStepForRecomputation = useRecoilCallback( - ({ set }) => - ({ - stepId, + const markStepForRecomputation = useCallback( + ({ + stepId, + workflowVersionId, + }: { + stepId: string; + workflowVersionId: string; + }) => { + const stepKey = getStepOutputSchemaFamilyStateKey( workflowVersionId, - }: { - stepId: string; - workflowVersionId: string; - }) => { + stepId, + ); + store.set( + shouldRecomputeOutputSchemaFamilyState.atomFamily(stepKey), + true, + ); + }, + [store], + ); + + const deleteStepsOutputSchema = useCallback( + ({ + stepIds, + workflowVersionId, + }: { + stepIds: string[]; + workflowVersionId: string; + }) => { + stepIds.forEach((stepId) => { const stepKey = getStepOutputSchemaFamilyStateKey( workflowVersionId, stepId, ); - set(shouldRecomputeOutputSchemaFamilyState(stepKey), true); - }, - [], - ); - - const deleteStepsOutputSchema = useRecoilCallback( - ({ set }) => - ({ - stepIds, - workflowVersionId, - }: { - stepIds: string[]; - workflowVersionId: string; - }) => { - stepIds.forEach((stepId) => { - const stepKey = getStepOutputSchemaFamilyStateKey( - workflowVersionId, - stepId, - ); - set(stepsOutputSchemaFamilyState(stepKey), null); - set(shouldRecomputeOutputSchemaFamilyState(stepKey), true); - }); - }, - [], + store.set(stepsOutputSchemaFamilyState.atomFamily(stepKey), null); + store.set( + shouldRecomputeOutputSchemaFamilyState.atomFamily(stepKey), + true, + ); + }); + }, + [store], ); return { diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useVariableDropdown.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useVariableDropdown.ts index f46cea18fa..e5f282a5ec 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useVariableDropdown.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useVariableDropdown.ts @@ -1,8 +1,7 @@ import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu'; import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState'; @@ -11,8 +10,8 @@ import { type LinkOutputSchema } from '@/workflow/workflow-variables/types/LinkO import { type FieldOutputSchemaV2 } from '@/workflow/workflow-variables/types/RecordOutputSchemaV2'; import { type StepOutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2'; import { getVariableTemplateFromPath } from '@/workflow/workflow-variables/utils/getVariableTemplateFromPath'; +import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2'; import { useState } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; @@ -49,21 +48,21 @@ export const useVariableDropdown = ({ const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu(); - const workflowVisualizerWorkflowId = useRecoilComponentValue( + const workflowVisualizerWorkflowId = useRecoilComponentValueV2( workflowVisualizerWorkflowIdComponentState, ); - const setWorkflowSelectedNode = useSetRecoilComponentState( + const setWorkflowSelectedNode = useSetRecoilComponentStateV2( workflowSelectedNodeComponentState, ); const setActiveTabId = useSetRecoilComponentStateV2( activeTabIdComponentState, 'workflow-logic-function-tab-list-component-id', ); - const setWorkflowDiagram = useSetRecoilComponentState( + const setWorkflowDiagram = useSetRecoilComponentStateV2( workflowDiagramComponentState, ); - const setCommandMenuNavigationStack = useSetRecoilState( + const setCommandMenuNavigationStack = useSetRecoilStateV2( commandMenuNavigationStackState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/states/shouldRecomputeOutputSchemaFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/states/shouldRecomputeOutputSchemaFamilyState.ts index df7b49fd98..6c58eb5279 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/states/shouldRecomputeOutputSchemaFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/states/shouldRecomputeOutputSchemaFamilyState.ts @@ -1,6 +1,6 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; -export const shouldRecomputeOutputSchemaFamilyState = createFamilyState< +export const shouldRecomputeOutputSchemaFamilyState = createFamilyStateV2< boolean, string | undefined >({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/states/stepsOutputSchemaFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/states/stepsOutputSchemaFamilyState.ts index 9599b6c657..9f3ff70dc4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/states/stepsOutputSchemaFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/states/stepsOutputSchemaFamilyState.ts @@ -1,7 +1,7 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; +import { createFamilyStateV2 } from '@/ui/utilities/state/jotai/utils/createFamilyStateV2'; import { type StepOutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2'; -export const stepsOutputSchemaFamilyState = createFamilyState< +export const stepsOutputSchemaFamilyState = createFamilyStateV2< StepOutputSchemaV2 | null, string | undefined >({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts index 85e0faa444..e2e9665c98 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUp.ts @@ -1,11 +1,11 @@ import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; -import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2'; import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState'; import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion'; import { isDefined } from 'twenty-shared/utils'; export const useTidyUp = () => { - const [workflowDiagram, setWorkflowDiagram] = useRecoilComponentState( + const [workflowDiagram, setWorkflowDiagram] = useRecoilComponentStateV2( workflowDiagramComponentState, ); diff --git a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx index 81730b9555..2d5a47fc51 100644 --- a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx @@ -4,11 +4,11 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { RecordIndexContainerGater } from '@/object-record/record-index/components/RecordIndexContainerGater'; import { PageContainer } from '@/ui/layout/page/components/PageContainer'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; import { isUndefined } from '@sniptt/guards'; export const RecordIndexPage = () => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue( + const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, MAIN_CONTEXT_STORE_INSTANCE_ID, ); diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPageTitle.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPageTitle.tsx index b5de1560e4..b9325cfb08 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPageTitle.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPageTitle.tsx @@ -3,7 +3,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; -import { useRecoilValue } from 'recoil'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { isDefined } from 'twenty-shared/utils'; export const RecordShowPageTitle = ({ @@ -18,7 +18,7 @@ export const RecordShowPageTitle = ({ const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular }); - const record = useRecoilValue(recordStoreFamilyState(objectRecordId)); + const record = useFamilyRecoilValueV2(recordStoreFamilyState, objectRecordId); const pageName = isDefined(record) ? getLabelIdentifierFieldValue(record, labelIdentifierFieldMetadataItem) diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx index 7bb4a452ce..4d402146af 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx @@ -33,8 +33,9 @@ import { import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useEffect, useState } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { SettingsAgentDetailSkeletonLoader } from './components/SettingsAgentDetailSkeletonLoader'; import { SettingsAgentEvalsTab } from './components/SettingsAgentEvalsTab'; @@ -128,11 +129,17 @@ export const SettingsAgentForm = ({ mode }: { mode: 'create' | 'edit' }) => { const agent = data?.findOneAgent; - const [settingsDraftRole, setSettingsDraftRole] = useRecoilState( - settingsDraftRoleFamilyState(formValues.role || ''), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + formValues.role || '', ); - const settingsPersistedRole = useRecoilValue( - settingsPersistedRoleFamilyState(formValues.role || ''), + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + formValues.role || '', + ); + const settingsPersistedRole = useFamilyRecoilValueV2( + settingsPersistedRoleFamilyState, + formValues.role || '', ); const { saveDraftRoleToDB } = useSaveDraftRoleToDB({ diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx index 607cb5eaef..d8a8817684 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx @@ -2,12 +2,12 @@ import { getOperationName } from '@apollo/client/utilities'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; -import { useSetRecoilState } from 'recoil'; import { v4 } from 'uuid'; import { GET_ROLES } from '@/settings/roles/graphql/queries/getRolesQuery'; import { SettingsRolePermissions } from '@/settings/roles/role-permissions/components/SettingsRolePermissions'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { isNonEmptyString } from '@sniptt/guards'; import { isDefined } from 'twenty-shared/utils'; import { H2Title, IconPlus } from 'twenty-ui/display'; @@ -50,8 +50,9 @@ export const SettingsAgentRoleTab = ({ const { data: rolesData } = useGetRolesQuery(); const [createRole] = useCreateOneRoleMutation(); const [assignRoleToAgent] = useAssignRoleToAgentMutation(); - const setSettingsDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(formValues.role || ''), + const setSettingsDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + formValues.role || '', ); const selectedRole = rolesData?.getRoles?.find( diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx index 8b9b3ffdfc..aa02c6eda6 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx @@ -2,11 +2,11 @@ import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useMemo, useState } from 'react'; import Skeleton from 'react-loading-skeleton'; -import { useRecoilValue } from 'recoil'; import { useGetToolIndex } from '@/ai/hooks/useGetToolIndex'; import { usePersistLogicFunction } from '@/logic-functions/hooks/usePersistLogicFunction'; import { logicFunctionsState } from '@/settings/logic-functions/states/logicFunctionsState'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { Table } from '@/ui/layout/table/components/Table'; @@ -55,7 +55,7 @@ const StyledFooterContainer = styled.div` `; export const SettingsToolsTable = () => { - const logicFunctions = useRecoilValue(logicFunctionsState); + const logicFunctions = useRecoilValueV2(logicFunctionsState); const { toolIndex, loading: toolIndexLoading } = useGetToolIndex(); const { createLogicFunction } = usePersistLogicFunction(); diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationPermissionsTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationPermissionsTab.tsx index f4ad3275b5..54b7296b3f 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationPermissionsTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationPermissionsTab.tsx @@ -5,9 +5,9 @@ import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRo import { SettingsRolePermissions } from '@/settings/roles/role-permissions/components/SettingsRolePermissions'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { type RoleWithPartialMembers } from '@/settings/roles/types/RoleWithPartialMembers'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { t } from '@lingui/core/macro'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import { useSetRecoilState } from 'recoil'; import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; import { isDefined } from 'twenty-shared/utils'; @@ -282,8 +282,9 @@ const MarketplaceRoleEffect = ({ ) => void; }) => { const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState); - const setDraftRole = useSetRecoilState( - settingsDraftRoleFamilyState(defaultRole.id), + const setDraftRole = useSetFamilyRecoilStateV2( + settingsDraftRoleFamilyState, + defaultRole.id, ); const { resolvedRole, objectMetadataItemsFromMarketplaceApp } = 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 07fdd67456..a7e6d810b4 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx @@ -11,8 +11,8 @@ 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 { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import styled from '@emotion/styled'; -import { useRecoilState } from 'recoil'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; @@ -51,9 +51,8 @@ export const SettingsObjectDetailPage = () => { const { findObjectMetadataItemByNamePlural } = useFilteredObjectMetadataItems(); - const [updatedObjectNamePlural, setUpdatedObjectNamePlural] = useRecoilState( - updatedObjectNamePluralState, - ); + const [updatedObjectNamePlural, setUpdatedObjectNamePlural] = + useRecoilStateV2(updatedObjectNamePluralState); const objectMetadataItem = findObjectMetadataItemByNamePlural(objectNamePlural) ?? findObjectMetadataItemByNamePlural(updatedObjectNamePlural); 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 f1afd0f6b5..09bb471d5e 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx @@ -19,8 +19,9 @@ import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValu import styled from '@emotion/styled'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useEffect, useMemo, useState } from 'react'; -import { useRecoilState } from 'recoil'; import { FieldMetadataType } from 'twenty-shared/types'; import { IconArchive, @@ -98,10 +99,13 @@ export const SettingsObjectFieldTable = ({ const { mapFieldMetadataItemToSettingsObjectDetailTableItem } = useMapFieldMetadataItemToSettingsObjectDetailTableItem(objectMetadataItem); - const [settingsObjectFields, setSettingsObjectFields] = useRecoilState( - settingsObjectFieldsFamilyState({ - objectMetadataItemId: objectMetadataItem.id, - }), + const settingsObjectFields = useFamilyRecoilValueV2( + settingsObjectFieldsFamilyState, + { objectMetadataItemId: objectMetadataItem.id }, + ); + const setSettingsObjectFields = useSetFamilyRecoilStateV2( + settingsObjectFieldsFamilyState, + { objectMetadataItemId: objectMetadataItem.id }, ); useEffect(() => { diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx index ff335a68d5..1d8a2dcccc 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx @@ -12,8 +12,9 @@ import styled from '@emotion/styled'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyArray } from '@sniptt/guards'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; +import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2'; import { useEffect, useMemo, useState } from 'react'; -import { useRecoilState } from 'recoil'; import { IconSearch, IconSquareKey } from 'twenty-ui/display'; import { type SettingsObjectIndexesTableItem } from '~/pages/settings/data-model/types/SettingsObjectIndexesTableItem'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; @@ -66,10 +67,13 @@ export const SettingsObjectIndexTable = ({ }, }; - const [settingsObjectIndexes, setSettingsObjectIndexes] = useRecoilState( - settingsObjectIndexesFamilyState({ - objectMetadataItemId: objectMetadataItem.id, - }), + const settingsObjectIndexes = useFamilyRecoilValueV2( + settingsObjectIndexesFamilyState, + { objectMetadataItemId: objectMetadataItem.id }, + ); + const setSettingsObjectIndexes = useSetFamilyRecoilStateV2( + settingsObjectIndexesFamilyState, + { objectMetadataItemId: objectMetadataItem.id }, ); useEffect(() => { diff --git a/packages/twenty-front/src/pages/settings/data-model/states/updatedObjectNamePluralState.ts b/packages/twenty-front/src/pages/settings/data-model/states/updatedObjectNamePluralState.ts index 0975a175f3..3f36f790cc 100644 --- a/packages/twenty-front/src/pages/settings/data-model/states/updatedObjectNamePluralState.ts +++ b/packages/twenty-front/src/pages/settings/data-model/states/updatedObjectNamePluralState.ts @@ -1,5 +1,5 @@ -import { createState } from '@/ui/utilities/state/utils/createState'; -export const updatedObjectNamePluralState = createState({ +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; +export const updatedObjectNamePluralState = createStateV2({ key: 'updatedObjectNamePluralState', defaultValue: '', }); diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/playground/GraphQLPlayground.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/playground/GraphQLPlayground.stories.tsx index 17bc684fb7..97e02d3920 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/playground/GraphQLPlayground.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/playground/GraphQLPlayground.stories.tsx @@ -1,3 +1,5 @@ +import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { action } from 'storybook/actions'; import { @@ -10,7 +12,14 @@ import { graphqlMocks } from '~/testing/graphqlMocks'; const meta: Meta = { title: 'Pages/Settings/Playground/GraphQLPlayground', component: SettingsGraphQLPlayground, - decorators: [ComponentDecorator, ComponentWithRouterDecorator], + decorators: [ + (Story) => { + jotaiStore.set(playgroundApiKeyState.atom, 'test-api-key'); + return ; + }, + ComponentDecorator, + ComponentWithRouterDecorator, + ], parameters: { docs: { description: { diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/playground/SettingsPlayground.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/playground/SettingsPlayground.stories.tsx index 4428e12afa..510555e6d4 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/playground/SettingsPlayground.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/playground/SettingsPlayground.stories.tsx @@ -1,3 +1,5 @@ +import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { action } from 'storybook/actions'; import { @@ -10,7 +12,14 @@ import { graphqlMocks } from '~/testing/graphqlMocks'; const meta: Meta = { title: 'Pages/Settings/Playground/RestPlayground', component: SettingsRestPlayground, - decorators: [ComponentDecorator, ComponentWithRouterDecorator], + decorators: [ + (Story) => { + jotaiStore.set(playgroundApiKeyState.atom, 'test-api-key'); + return ; + }, + ComponentDecorator, + ComponentWithRouterDecorator, + ], parameters: { docs: { description: { diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index d0f5bd36ed..9603d2f528 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; import { isNonEmptyString } from '@sniptt/guards'; -import { useState } from 'react'; +import { useStore } from 'jotai'; +import { useCallback, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { useRecoilCallback, useRecoilValue } from 'recoil'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader'; @@ -10,6 +10,7 @@ import { ApiKeyInput } from '@/settings/developers/components/ApiKeyInput'; import { ApiKeyNameInput } from '@/settings/developers/components/ApiKeyNameInput'; import { SettingsDevelopersRoleSelector } from '@/settings/developers/components/SettingsDevelopersRoleSelector'; import { apiKeyTokenFamilyState } from '@/settings/developers/states/apiKeyTokenFamilyState'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { computeNewExpirationDate } from '@/settings/developers/utils/computeNewExpirationDate'; import { formatExpiration } from '@/settings/developers/utils/formatExpiration'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -59,14 +60,15 @@ export const SettingsDevelopersApiKeyDetail = () => { const navigate = useNavigateSettings(); const { apiKeyId = '' } = useParams(); - const apiKeyToken = useRecoilValue(apiKeyTokenFamilyState(apiKeyId)); + const jotaiStore = useStore(); - const setApiKeyTokenCallback = useRecoilCallback( - ({ set }) => - (apiKeyId: string, token: string) => { - set(apiKeyTokenFamilyState(apiKeyId), token); - }, - [], + const apiKeyToken = useFamilyRecoilValueV2(apiKeyTokenFamilyState, apiKeyId); + + const setApiKeyTokenCallback = useCallback( + (apiKeyId: string, token: string) => { + jotaiStore.set(apiKeyTokenFamilyState.atomFamily(apiKeyId), token); + }, + [jotaiStore], ); const [generateOneApiKeyToken] = useGenerateApiKeyTokenMutation(); diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx index e327c40460..187ca1286a 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx @@ -1,5 +1,5 @@ import { addDays } from 'date-fns'; -import { useState } from 'react'; +import { useState, useCallback } from 'react'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; @@ -11,7 +11,7 @@ import { Select } from '@/ui/input/components/Select'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; import { Key } from 'ts-key-enum'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; @@ -57,12 +57,13 @@ export const SettingsDevelopersApiKeysNew = () => { const [createApiKey] = useCreateApiKeyMutation(); - const setApiKeyTokenCallback = useRecoilCallback( - ({ set }) => - (apiKeyId: string, token: string) => { - set(apiKeyTokenFamilyState(apiKeyId), token); - }, - [], + const jotaiStore = useStore(); + + const setApiKeyTokenCallback = useCallback( + (apiKeyId: string, token: string) => { + jotaiStore.set(apiKeyTokenFamilyState.atomFamily(apiKeyId), token); + }, + [jotaiStore], ); const handleSave = async () => { diff --git a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx index bbfebd1ea8..255336c49c 100644 --- a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx +++ b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx @@ -5,14 +5,14 @@ import { SettingsListCard } from '@/settings/components/SettingsListCard'; import { SettingsEmailingDomainRowDropdownMenu } from '@/settings/emailing-domains/components/SettingsEmailingDomainRowDropdownMenu'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { IconMail, Status } from 'twenty-ui/display'; import { useGetEmailingDomainsQuery } from '~/generated-metadata/graphql'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { getColorByEmailingDomainStatus } from '~/pages/settings/emailing-domains/utils/getEmailingDomainStatusColor'; import { getTextByEmailingDomainStatus } from '~/pages/settings/emailing-domains/utils/getEmailingDomainStatusText'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; @@ -23,7 +23,7 @@ const StyledLink = styled(Link)` export const SettingsEmailingDomains = () => { const { t } = useLingui(); - const { localeCatalog } = useRecoilValue(dateLocaleState); + const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2); const navigate = useNavigate(); const { data, loading: isLoading } = useGetEmailingDomainsQuery(); diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx index 7aa5760df5..2d75d98312 100644 --- a/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx +++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx @@ -2,7 +2,6 @@ import styled from '@emotion/styled'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; -import { useSetRecoilState } from 'recoil'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util'; @@ -15,7 +14,6 @@ import { useLingui } from '@lingui/react/macro'; import { enUS } from 'date-fns/locale'; import { APP_LOCALES } from 'twenty-shared/translations'; import { isDefined } from 'twenty-shared/utils'; -import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2'; import { dynamicActivate } from '~/utils/i18n/dynamicActivate'; import { logError } from '~/utils/logError'; @@ -32,8 +30,6 @@ export const LocalePicker = () => { const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilStateV2( currentWorkspaceMemberState, ); - const setDateLocale = useSetRecoilState(dateLocaleState); - const { updateOneRecord } = useUpdateOneRecord(); const { refreshObjectMetadataItems } = @@ -71,7 +67,6 @@ export const LocalePicker = () => { locale: value, localeCatalog: dateFnsLocale || enUS, }; - setDateLocale(newDateLocale); store.set(dateLocaleStateV2.atom, newDateLocale); await dynamicActivate(value); diff --git a/packages/twenty-front/src/pages/settings/roles/SettingsRoleAddObjectLevel.tsx b/packages/twenty-front/src/pages/settings/roles/SettingsRoleAddObjectLevel.tsx index 5166e8f270..23edfa27e9 100644 --- a/packages/twenty-front/src/pages/settings/roles/SettingsRoleAddObjectLevel.tsx +++ b/packages/twenty-front/src/pages/settings/roles/SettingsRoleAddObjectLevel.tsx @@ -3,9 +3,9 @@ import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRo import { SettingsRolePermissionsObjectLevelObjectPicker } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelObjectPicker'; import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { t } from '@lingui/core/macro'; import { Navigate, useParams, useSearchParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { useFindOneAgentQuery } from '~/generated-metadata/graphql'; @@ -15,8 +15,9 @@ export const SettingsRoleAddObjectLevel = () => { const [searchParams] = useSearchParams(); const fromAgentId = searchParams.get('fromAgent'); - const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(roleId ?? ''), + const settingsDraftRole = useFamilyRecoilValueV2( + settingsDraftRoleFamilyState, + roleId ?? '', ); const { data: agentData } = useFindOneAgentQuery({ diff --git a/packages/twenty-front/src/pages/settings/roles/SettingsRoleEdit.tsx b/packages/twenty-front/src/pages/settings/roles/SettingsRoleEdit.tsx index 8bc00fc81d..5cc17f2961 100644 --- a/packages/twenty-front/src/pages/settings/roles/SettingsRoleEdit.tsx +++ b/packages/twenty-front/src/pages/settings/roles/SettingsRoleEdit.tsx @@ -1,8 +1,8 @@ import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect'; import { SettingsRole } from '@/settings/roles/role/components/SettingsRole'; import { SettingsRoleEditEffect } from '@/settings/roles/role/components/SettingsRoleEditEffect'; +import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2'; import { Navigate, useParams } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { settingsPersistedRoleFamilyState } from '~/modules/settings/roles/states/settingsPersistedRoleFamilyState'; @@ -10,8 +10,9 @@ import { settingsPersistedRoleFamilyState } from '~/modules/settings/roles/state export const SettingsRoleEdit = () => { const { roleId } = useParams(); - const persistedRole = useRecoilValue( - settingsPersistedRoleFamilyState(roleId ?? ''), + const persistedRole = useFamilyRecoilValueV2( + settingsPersistedRoleFamilyState, + roleId ?? '', ); if (!isDefined(roleId)) { diff --git a/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx b/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx index da170fa01a..08cae0db91 100644 --- a/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx +++ b/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx @@ -21,7 +21,6 @@ import { ToggleImpersonate } from '@/settings/workspace/components/ToggleImperso import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { ApolloError } from '@apollo/client'; -import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { Tag } from 'twenty-ui/components'; @@ -69,7 +68,7 @@ export const SettingsSecurity = () => { ); const isClickHouseConfigured = useRecoilValueV2(isClickHouseConfiguredState); const authProviders = useRecoilValueV2(authProvidersState); - const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState); + const SSOIdentitiesProviders = useRecoilValueV2(SSOIdentitiesProvidersState); const [currentWorkspace, setCurrentWorkspace] = useRecoilStateV2( currentWorkspaceState, ); diff --git a/packages/twenty-front/src/testing/decorators/ContextStoreDecorator.tsx b/packages/twenty-front/src/testing/decorators/ContextStoreDecorator.tsx index 6632a2ef17..c56334f6a6 100644 --- a/packages/twenty-front/src/testing/decorators/ContextStoreDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/ContextStoreDecorator.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { isUndefined } from '@sniptt/guards'; import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies'; @@ -17,7 +17,7 @@ export const ContextStoreDecorator: Decorator = (Story, context) => { componentInstanceId = MAIN_CONTEXT_STORE_INSTANCE_ID; } - const setCurrentObjectMetadataItemId = useSetRecoilComponentState( + const setCurrentObjectMetadataItemId = useSetRecoilComponentStateV2( contextStoreCurrentObjectMetadataItemIdComponentState, componentInstanceId, ); diff --git a/packages/twenty-front/src/testing/decorators/ProfilerDecorator.tsx b/packages/twenty-front/src/testing/decorators/ProfilerDecorator.tsx index 82d0a46a78..d4ba0dc566 100644 --- a/packages/twenty-front/src/testing/decorators/ProfilerDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/ProfilerDecorator.tsx @@ -1,6 +1,6 @@ import { type Decorator } from '@storybook/react-vite'; -import { useRecoilState } from 'recoil'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { ProfilerWrapper } from '~/testing/profiling/components/ProfilerWrapper'; import { ProfilingQueueEffect } from '~/testing/profiling/components/ProfilingQueueEffect'; import { ProfilingReporter } from '~/testing/profiling/components/ProfilingReporter'; @@ -14,12 +14,12 @@ export const ProfilerDecorator: Decorator = (Story, { id, parameters }) => { const numberOfRuns = parameters.numberOfRuns ?? 2; const warmUpRounds = parameters.warmUpRounds ?? 5; - const [currentProfilingRunIndex] = useRecoilState( + const currentProfilingRunIndex = useRecoilValueV2( currentProfilingRunIndexState, ); - const [profilingSessionStatus] = useRecoilState(profilingSessionStatusState); - const [profilingSessionRuns] = useRecoilState(profilingSessionRunsState); + const profilingSessionStatus = useRecoilValueV2(profilingSessionStatusState); + const profilingSessionRuns = useRecoilValueV2(profilingSessionRunsState); const skip = profilingSessionRuns.length === 0; diff --git a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx index d59d7788eb..5308db2721 100644 --- a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx @@ -3,6 +3,7 @@ import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetReco import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { labelIdentifierFieldMetadataItemSelector } from '@/object-metadata/states/labelIdentifierFieldMetadataItemSelector'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; @@ -25,8 +26,9 @@ import { useSetRecordTableData } from '@/object-record/record-table/hooks/intern import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { coreViewsState } from '@/views/states/coreViewState'; import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations'; @@ -45,12 +47,13 @@ const InternalTableStateLoaderEffect = ({ }) => { const { recordTableId } = useRecordTableContextOrThrow(); const { loadRecordIndexStates } = useLoadRecordIndexStates(); - const setCurrentRecordFields = useSetRecoilComponentState( + const setCurrentRecordFields = useSetRecoilComponentStateV2( currentRecordFieldsComponentState, ); - const setContextStoreCurrentViewId = useSetRecoilComponentState( + const setContextStoreCurrentViewId = useSetRecoilComponentStateV2( contextStoreCurrentViewIdComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const setCoreViews = useSetRecoilStateV2(coreViewsState); @@ -104,14 +107,12 @@ const InternalTableContextProviders = ({ }) => { const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); - const currentRecordFields = useRecoilComponentValue( + const currentRecordFields = useRecoilComponentValueV2( currentRecordFieldsComponentState, - 'record-index', ); - const visibleRecordFields = useRecoilComponentValue( + const visibleRecordFields = useRecoilComponentSelectorValueV2( visibleRecordFieldsComponentSelector, - 'record-index', ); const fieldMetadataItems = objectMetadataItem.fields; diff --git a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx index 519693d062..c59311d71c 100644 --- a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx @@ -10,8 +10,8 @@ import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow- import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { useStepsOutputSchema } from '@/workflow/workflow-variables/hooks/useStepsOutputSchema'; import { type Decorator } from '@storybook/react-vite'; -import { useEffect, useState } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useStore } from 'jotai'; +import { useCallback, useEffect, useState } from 'react'; import { getWorkflowMock, getWorkflowNodeIdMock, @@ -26,56 +26,59 @@ export const WorkflowStepDecorator: Decorator = (Story) => { const { loadMockedObjectMetadataItems } = useLoadMockedObjectMetadataItems(); const [ready, setReady] = useState(false); - const handleMount = useRecoilCallback( - ({ set }) => - async () => { - await loadMockedObjectMetadataItems(); + const store = useStore(); - set( - workflowVisualizerWorkflowIdComponentState.atomFamily({ - instanceId: workflowVisualizerComponentInstanceId, - }), - getWorkflowMock().id, - ); - set( - workflowVisualizerWorkflowVersionIdComponentState.atomFamily({ - instanceId: workflowVisualizerComponentInstanceId, - }), - workflowVersion.id, - ); - set( - workflowVisualizerWorkflowRunIdComponentState.atomFamily({ - instanceId: workflowVisualizerComponentInstanceId, - }), - '123', - ); - set( - workflowSelectedNodeComponentState.atomFamily({ - instanceId: workflowVisualizerComponentInstanceId, - }), - getWorkflowNodeIdMock(), - ); - set( - flowComponentState.atomFamily({ - instanceId: workflowVisualizerComponentInstanceId, - }), - { - workflowVersionId: workflowVersion.id, - trigger: workflowVersion.trigger, - steps: workflowVersion.steps, - }, - ); - set( - commandMenuWorkflowIdComponentState.atomFamily({ - instanceId: workflowVisualizerComponentInstanceId, - }), - getWorkflowMock().id, - ); - populateStepsOutputSchema(workflowVersion); - setReady(true); + const handleMount = useCallback(async () => { + await loadMockedObjectMetadataItems(); + + store.set( + workflowVisualizerWorkflowIdComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + getWorkflowMock().id, + ); + store.set( + workflowVisualizerWorkflowVersionIdComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + workflowVersion.id, + ); + store.set( + workflowVisualizerWorkflowRunIdComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + '123', + ); + store.set( + workflowSelectedNodeComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + getWorkflowNodeIdMock(), + ); + store.set( + flowComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + { + workflowVersionId: workflowVersion.id, + trigger: workflowVersion.trigger, + steps: workflowVersion.steps, }, - [loadMockedObjectMetadataItems, populateStepsOutputSchema, workflowVersion], - ); + ); + store.set( + commandMenuWorkflowIdComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + getWorkflowMock().id, + ); + populateStepsOutputSchema(workflowVersion); + setReady(true); + }, [ + loadMockedObjectMetadataItems, + populateStepsOutputSchema, + workflowVersion, + store, + ]); useEffect(() => { handleMount(); diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx index 0161519a29..d6f34f9c2e 100644 --- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -1,6 +1,5 @@ import { type Decorator } from '@storybook/react-vite'; -import { useEffect } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useCallback, useEffect } from 'react'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; @@ -8,6 +7,7 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldCont import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { CustomError, isDefined } from 'twenty-shared/utils'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people'; @@ -24,13 +24,9 @@ const RecordMockSetterEffect = ({ people: ObjectRecord[]; tasks: ObjectRecord[]; }) => { - const setRecordInStores = useRecoilCallback( - ({ set }) => - (record: ObjectRecord) => { - set(recordStoreFamilyState(record.id), record); - }, - [], - ); + const setRecordInStores = useCallback((record: ObjectRecord) => { + jotaiStore.set(recordStoreFamilyState.atomFamily(record.id), record); + }, []); useEffect(() => { for (const company of companies) { diff --git a/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx b/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx index a666d1930c..5a8755a834 100644 --- a/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx +++ b/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx @@ -1,4 +1,4 @@ -import { type PropsWithChildren, useEffect, useState } from 'react'; +import { type PropsWithChildren, useContext, useEffect, useState } from 'react'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; @@ -6,6 +6,8 @@ import { contextStoreCurrentViewTypeComponentState } from '@/context-store/state import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type ContextStoreTargetedRecordsRule, contextStoreTargetedRecordsRuleComponentState, @@ -14,7 +16,7 @@ import { type ContextStoreViewType } from '@/context-store/types/ContextStoreVie import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2'; export type JestContextStoreSetterMocks = { contextStoreTargetedRecordsRule?: ContextStoreTargetedRecordsRule; @@ -41,32 +43,47 @@ export const JestContextStoreSetter = ({ contextStoreCurrentViewType, children, }: JestContextStoreSetterProps) => { - const setContextStoreTargetedRecordsRule = useSetRecoilComponentState( + const contextStoreInstanceContext = useContext( + ContextStoreComponentInstanceContext, + ); + const instanceId = + contextStoreInstanceContext?.instanceId ?? MAIN_CONTEXT_STORE_INSTANCE_ID; + + const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2( contextStoreTargetedRecordsRuleComponentState, + instanceId, ); - const setContextStoreCurrentObjectMetadataItemId = useSetRecoilComponentState( - contextStoreCurrentObjectMetadataItemIdComponentState, - ); + const setContextStoreCurrentObjectMetadataItemId = + useSetRecoilComponentStateV2( + contextStoreCurrentObjectMetadataItemIdComponentState, + instanceId, + ); - const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentState( + const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentStateV2( contextStoreNumberOfSelectedRecordsComponentState, + instanceId, ); - const setcontextStoreFiltersComponentState = useSetRecoilComponentState( + const setContextStoreFiltersComponentState = useSetRecoilComponentStateV2( contextStoreFiltersComponentState, + instanceId, ); - const setContextStoreFilterGroupsComponentState = useSetRecoilComponentState( - contextStoreFilterGroupsComponentState, - ); + const setContextStoreFilterGroupsComponentState = + useSetRecoilComponentStateV2( + contextStoreFilterGroupsComponentState, + instanceId, + ); - const setContextStoreCurrentViewId = useSetRecoilComponentState( + const setContextStoreCurrentViewId = useSetRecoilComponentStateV2( contextStoreCurrentViewIdComponentState, + instanceId, ); - const setContextStoreCurrentViewType = useSetRecoilComponentState( + const setContextStoreCurrentViewType = useSetRecoilComponentStateV2( contextStoreCurrentViewTypeComponentState, + instanceId, ); const { objectMetadataItem } = useObjectMetadataItem({ @@ -81,7 +98,7 @@ export const JestContextStoreSetter = ({ setContextStoreTargetedRecordsRule(contextStoreTargetedRecordsRule); setContextStoreCurrentObjectMetadataItemId(objectMetadataItem.id); setContextStoreNumberOfSelectedRecords(contextStoreNumberOfSelectedRecords); - setcontextStoreFiltersComponentState(contextStoreFilters); + setContextStoreFiltersComponentState(contextStoreFilters); setContextStoreFilterGroupsComponentState(contextStoreFilterGroups); setContextStoreCurrentViewType(contextStoreCurrentViewType ?? null); setIsLoaded(true); @@ -92,7 +109,7 @@ export const JestContextStoreSetter = ({ contextStoreCurrentObjectMetadataId, setContextStoreNumberOfSelectedRecords, contextStoreNumberOfSelectedRecords, - setcontextStoreFiltersComponentState, + setContextStoreFiltersComponentState, contextStoreFilters, objectMetadataItem, setContextStoreCurrentViewId, diff --git a/packages/twenty-front/src/testing/jest/JestRecordIndexContextProviderWrapper.tsx b/packages/twenty-front/src/testing/jest/JestRecordIndexContextProviderWrapper.tsx index a74a00b88e..ef6cda27a4 100644 --- a/packages/twenty-front/src/testing/jest/JestRecordIndexContextProviderWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/JestRecordIndexContextProviderWrapper.tsx @@ -1,8 +1,13 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; +import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { type PropsWithChildren } from 'react'; +const RECORD_INDEX_ID = 'recordIndexId'; + type JestRecordIndexContextProviderWrapperProps = { objectMetadataItem: ObjectMetadataItem; } & PropsWithChildren; @@ -19,23 +24,35 @@ export const JestRecordIndexContextProviderWrapper = ({ } = useRecordIndexFieldMetadataDerivedStates(objectMetadataItem); return ( - 'indexIdentifierUrl', - onIndexRecordsLoaded: () => {}, - objectNamePlural: objectMetadataItem.namePlural, - objectNameSingular: objectMetadataItem.nameSingular, - objectMetadataItem: objectMetadataItem, - recordIndexId: 'recordIndexId', - viewBarInstanceId: 'recordIndexId', - labelIdentifierFieldMetadataItem, - recordFieldByFieldMetadataItemId, - fieldDefinitionByFieldMetadataItemId, - fieldMetadataItemByFieldMetadataItemId, - }} + - {children} - + + + 'indexIdentifierUrl', + onIndexRecordsLoaded: () => {}, + objectNamePlural: objectMetadataItem.namePlural, + objectNameSingular: objectMetadataItem.nameSingular, + objectMetadataItem: objectMetadataItem, + recordIndexId: RECORD_INDEX_ID, + viewBarInstanceId: RECORD_INDEX_ID, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + }} + > + {children} + + + + ); }; diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx index 4fbe6625d5..f41f966603 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx @@ -2,6 +2,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { type MockedResponse } from '@apollo/client/testing'; import { type ReactNode } from 'react'; +import type { Store } from 'jotai/vanilla/store'; import { type MutableSnapshot } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { @@ -17,12 +18,14 @@ export type GetJestMetadataAndApolloMocksAndActionMenuWrapperProps = { | readonly MockedResponse, Record>[] | undefined; onInitializeRecoilSnapshot?: (snapshot: MutableSnapshot) => void; + onInitializeJotaiStore?: (store: Store) => void; componentInstanceId: string; } & JestContextStoreSetterMocks; export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({ apolloMocks, onInitializeRecoilSnapshot, + onInitializeJotaiStore, contextStoreTargetedRecordsRule, contextStoreCurrentViewId, contextStoreCurrentViewType, @@ -34,6 +37,7 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({ const Wrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks, onInitializeRecoilSnapshot, + onInitializeJotaiStore, }); const mockObjectMetadataItem = getMockObjectMetadataItemOrThrow( diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx index 4de1a5669b..e5ff9bd4b0 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx @@ -18,6 +18,7 @@ export const getJestMetadataAndApolloMocksWrapper = ({ apolloMocks, cache, onInitializeRecoilSnapshot, + onInitializeJotaiStore, objectMetadataItems, }: { cache?: InMemoryCache; @@ -25,8 +26,11 @@ export const getJestMetadataAndApolloMocksWrapper = ({ | readonly MockedResponse, Record>[] | undefined; onInitializeRecoilSnapshot?: (snapshot: MutableSnapshot) => void; + onInitializeJotaiStore?: (store: typeof jotaiStore) => void; objectMetadataItems?: ObjectMetadataItem[]; }) => { + onInitializeJotaiStore?.(jotaiStore); + return ({ children }: { children: ReactNode }) => ( diff --git a/packages/twenty-front/src/testing/mock-data/roles/roles-mock.ts b/packages/twenty-front/src/testing/mock-data/roles/roles-mock.ts index 4c8237e51e..0f1e4612c7 100644 --- a/packages/twenty-front/src/testing/mock-data/roles/roles-mock.ts +++ b/packages/twenty-front/src/testing/mock-data/roles/roles-mock.ts @@ -1,4 +1,5 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState'; +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { type FieldPermission, type ObjectPermission, @@ -116,15 +117,15 @@ export const BASE_ROLE_MOCK_REVOKES_ALL: Role = { rowLevelPermissionPredicates: [], }; -export const rolesMockHookWrapper = getJestMetadataAndApolloMocksWrapper({ - onInitializeRecoilSnapshot: (snapshot) => { - snapshot.set( - settingsDraftRoleFamilyState(MOCK_ROLE_ID_GRANTS_ALL), - BASE_ROLE_MOCK_GRANTS_ALL, - ); - snapshot.set( - settingsDraftRoleFamilyState(MOCK_ROLE_ID_REVOKES_ALL), - BASE_ROLE_MOCK_REVOKES_ALL, - ); - }, -}); +export const initializeRolesMockJotaiStore = () => { + jotaiStore.set( + settingsDraftRoleFamilyState.atomFamily(MOCK_ROLE_ID_GRANTS_ALL), + BASE_ROLE_MOCK_GRANTS_ALL, + ); + jotaiStore.set( + settingsDraftRoleFamilyState.atomFamily(MOCK_ROLE_ID_REVOKES_ALL), + BASE_ROLE_MOCK_REVOKES_ALL, + ); +}; + +export const rolesMockHookWrapper = getJestMetadataAndApolloMocksWrapper({}); diff --git a/packages/twenty-front/src/testing/profiling/components/ProfilerWrapper.tsx b/packages/twenty-front/src/testing/profiling/components/ProfilerWrapper.tsx index df9328f219..dccc765f8c 100644 --- a/packages/twenty-front/src/testing/profiling/components/ProfilerWrapper.tsx +++ b/packages/twenty-front/src/testing/profiling/components/ProfilerWrapper.tsx @@ -1,5 +1,6 @@ -import { Profiler, type ProfilerOnRenderCallback } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { Profiler, type ProfilerOnRenderCallback, useCallback } from 'react'; + +import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; import { profilingQueueState } from '~/testing/profiling/states/profilingQueueState'; import { profilingSessionDataPointsState } from '~/testing/profiling/states/profilingSessionDataPointsState'; import { profilingSessionState } from '~/testing/profiling/states/profilingSessionState'; @@ -20,55 +21,52 @@ export const ProfilerWrapper = ({ runName: string; children: React.ReactNode; }) => { - const handleRender: ProfilerOnRenderCallback = useRecoilCallback( - ({ set, snapshot }) => - (id, phase, actualDurationInMs) => { - const dataPointId = getProfilingQueueIdentifier( - profilingId, - testIndex, - runName, - ); + const handleRender: ProfilerOnRenderCallback = useCallback( + (id, phase, actualDurationInMs) => { + const dataPointId = getProfilingQueueIdentifier( + profilingId, + testIndex, + runName, + ); - const newDataPoint: ProfilingDataPoint = { - componentName, - runName, - id: dataPointId, - phase, - durationInMs: actualDurationInMs, - }; + const newDataPoint: ProfilingDataPoint = { + componentName, + runName, + id: dataPointId, + phase, + durationInMs: actualDurationInMs, + }; - set( - profilingSessionDataPointsState, - (currentProfilingSessionDataPoints) => [ - ...currentProfilingSessionDataPoints, - newDataPoint, - ], - ); + jotaiStore.set( + profilingSessionDataPointsState.atom, + (currentProfilingSessionDataPoints) => [ + ...currentProfilingSessionDataPoints, + newDataPoint, + ], + ); - set(profilingSessionState, (currentProfilingSession) => ({ - ...currentProfilingSession, - [id]: [...(currentProfilingSession[id] ?? []), newDataPoint], - })); + jotaiStore.set(profilingSessionState.atom, (currentProfilingSession) => ({ + ...currentProfilingSession, + [id]: [...(currentProfilingSession[id] ?? []), newDataPoint], + })); - const queueIdentifier = dataPointId; + const queueIdentifier = dataPointId; - const currentProfilingQueue = snapshot - .getLoadable(profilingQueueState) - .getValue(); + const currentProfilingQueue = jotaiStore.get(profilingQueueState.atom); - const currentQueue = currentProfilingQueue[runName]; + const currentQueue = currentProfilingQueue[runName]; - if (!isDefined(currentQueue)) { - return; - } + if (!isDefined(currentQueue)) { + return; + } - const newQueue = currentQueue.filter((id) => id !== queueIdentifier); + const newQueue = currentQueue.filter((id) => id !== queueIdentifier); - set(profilingQueueState, (currentProfilingQueue) => ({ - ...currentProfilingQueue, - [runName]: newQueue, - })); - }, + jotaiStore.set(profilingQueueState.atom, (currentProfilingQueue) => ({ + ...currentProfilingQueue, + [runName]: newQueue, + })); + }, [profilingId, testIndex, componentName, runName], ); diff --git a/packages/twenty-front/src/testing/profiling/components/ProfilingQueueEffect.tsx b/packages/twenty-front/src/testing/profiling/components/ProfilingQueueEffect.tsx index 8da642bd76..31c062a631 100644 --- a/packages/twenty-front/src/testing/profiling/components/ProfilingQueueEffect.tsx +++ b/packages/twenty-front/src/testing/profiling/components/ProfilingQueueEffect.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; -import { useRecoilState } from 'recoil'; +import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2'; import { TIME_BETWEEN_TEST_RUNS_IN_MS } from '~/testing/profiling/constants/TimeBetweenTestRunsInMs'; import { currentProfilingRunIndexState } from '~/testing/profiling/states/currentProfilingRunIndexState'; import { profilingQueueState } from '~/testing/profiling/states/profilingQueueState'; @@ -21,18 +21,18 @@ export const ProfilingQueueEffect = ({ warmUpRounds: number; }) => { const [currentProfilingRunIndex, setCurrentProfilingRunIndex] = - useRecoilState(currentProfilingRunIndexState); + useRecoilStateV2(currentProfilingRunIndexState); - const [profilingSessionStatus, setProfilingSessionStatus] = useRecoilState( + const [profilingSessionStatus, setProfilingSessionStatus] = useRecoilStateV2( profilingSessionStatusState, ); - const [profilingSessionRuns, setProfilingSessionRuns] = useRecoilState( + const [profilingSessionRuns, setProfilingSessionRuns] = useRecoilStateV2( profilingSessionRunsState, ); const [profilingQueue, setProfilingQueue] = - useRecoilState(profilingQueueState); + useRecoilStateV2(profilingQueueState); useEffect(() => { (async () => { diff --git a/packages/twenty-front/src/testing/profiling/components/ProfilingReporter.tsx b/packages/twenty-front/src/testing/profiling/components/ProfilingReporter.tsx index 6d4ecb0149..ddf56c984d 100644 --- a/packages/twenty-front/src/testing/profiling/components/ProfilingReporter.tsx +++ b/packages/twenty-front/src/testing/profiling/components/ProfilingReporter.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; import { useMemo } from 'react'; -import { useRecoilState } from 'recoil'; +import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2'; import { PROFILING_REPORTER_DIV_ID } from '~/testing/profiling/constants/ProfilingReporterDivId'; import { currentProfilingRunIndexState } from '~/testing/profiling/states/currentProfilingRunIndexState'; import { profilingSessionDataPointsState } from '~/testing/profiling/states/profilingSessionDataPointsState'; @@ -22,15 +22,15 @@ const StyledTable = styled.table` `; export const ProfilingReporter = () => { - const [profilingSessionDataPoints] = useRecoilState( + const profilingSessionDataPoints = useRecoilValueV2( profilingSessionDataPointsState, ); - const [currentProfilingRunIndex] = useRecoilState( + const currentProfilingRunIndex = useRecoilValueV2( currentProfilingRunIndexState, ); - const [profilingSessionStatus] = useRecoilState(profilingSessionStatusState); + const profilingSessionStatus = useRecoilValueV2(profilingSessionStatusState); const profilingReport = useMemo( () => computeProfilingReport(profilingSessionDataPoints), diff --git a/packages/twenty-front/src/testing/profiling/states/currentProfilingRunIndexState.ts b/packages/twenty-front/src/testing/profiling/states/currentProfilingRunIndexState.ts index da05d73035..3a7d9f93c0 100644 --- a/packages/twenty-front/src/testing/profiling/states/currentProfilingRunIndexState.ts +++ b/packages/twenty-front/src/testing/profiling/states/currentProfilingRunIndexState.ts @@ -1,6 +1,6 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const currentProfilingRunIndexState = atom({ +export const currentProfilingRunIndexState = createStateV2({ key: 'currentProfilingRunIndexState', - default: 0, + defaultValue: 0, }); diff --git a/packages/twenty-front/src/testing/profiling/states/currentProfilingRunState.ts b/packages/twenty-front/src/testing/profiling/states/currentProfilingRunState.ts index da05d73035..3a7d9f93c0 100644 --- a/packages/twenty-front/src/testing/profiling/states/currentProfilingRunState.ts +++ b/packages/twenty-front/src/testing/profiling/states/currentProfilingRunState.ts @@ -1,6 +1,6 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const currentProfilingRunIndexState = atom({ +export const currentProfilingRunIndexState = createStateV2({ key: 'currentProfilingRunIndexState', - default: 0, + defaultValue: 0, }); diff --git a/packages/twenty-front/src/testing/profiling/states/profilingQueueState.ts b/packages/twenty-front/src/testing/profiling/states/profilingQueueState.ts index f38449cbb9..cad4798097 100644 --- a/packages/twenty-front/src/testing/profiling/states/profilingQueueState.ts +++ b/packages/twenty-front/src/testing/profiling/states/profilingQueueState.ts @@ -1,10 +1,10 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; export type ProfilingQueue = { [runName: string]: string[]; }; -export const profilingQueueState = atom({ +export const profilingQueueState = createStateV2({ key: 'profilingQueueState', - default: {}, + defaultValue: {}, }); diff --git a/packages/twenty-front/src/testing/profiling/states/profilingSessionDataPointsState.ts b/packages/twenty-front/src/testing/profiling/states/profilingSessionDataPointsState.ts index 232d687791..bf91d49a88 100644 --- a/packages/twenty-front/src/testing/profiling/states/profilingSessionDataPointsState.ts +++ b/packages/twenty-front/src/testing/profiling/states/profilingSessionDataPointsState.ts @@ -1,8 +1,10 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type ProfilingDataPoint } from '~/testing/profiling/types/ProfilingDataPoint'; -export const profilingSessionDataPointsState = atom({ +export const profilingSessionDataPointsState = createStateV2< + ProfilingDataPoint[] +>({ key: 'profilingSessionDataPointsState', - default: [], + defaultValue: [], }); diff --git a/packages/twenty-front/src/testing/profiling/states/profilingSessionRunsState.ts b/packages/twenty-front/src/testing/profiling/states/profilingSessionRunsState.ts index ebfd3ab3fb..eb2fe577cd 100644 --- a/packages/twenty-front/src/testing/profiling/states/profilingSessionRunsState.ts +++ b/packages/twenty-front/src/testing/profiling/states/profilingSessionRunsState.ts @@ -1,6 +1,6 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; -export const profilingSessionRunsState = atom({ +export const profilingSessionRunsState = createStateV2({ key: 'profilingSessionRunsState', - default: [], + defaultValue: [], }); diff --git a/packages/twenty-front/src/testing/profiling/states/profilingSessionState.ts b/packages/twenty-front/src/testing/profiling/states/profilingSessionState.ts index 461de1d772..2d47ac3eb0 100644 --- a/packages/twenty-front/src/testing/profiling/states/profilingSessionState.ts +++ b/packages/twenty-front/src/testing/profiling/states/profilingSessionState.ts @@ -1,10 +1,10 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; import { type ProfilingDataPoint } from '~/testing/profiling/types/ProfilingDataPoint'; -export const profilingSessionState = atom>( - { - key: 'profilingSessionState', - default: {}, - }, -); +export const profilingSessionState = createStateV2< + Record +>({ + key: 'profilingSessionState', + defaultValue: {}, +}); diff --git a/packages/twenty-front/src/testing/profiling/states/profilingSessionStatusState.ts b/packages/twenty-front/src/testing/profiling/states/profilingSessionStatusState.ts index 25d8acaebf..a22c5baeb4 100644 --- a/packages/twenty-front/src/testing/profiling/states/profilingSessionStatusState.ts +++ b/packages/twenty-front/src/testing/profiling/states/profilingSessionStatusState.ts @@ -1,8 +1,9 @@ -import { atom } from 'recoil'; +import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2'; export type ProfilingSessionStatus = 'running' | 'finished' | 'not_started'; -export const profilingSessionStatusState = atom({ - key: 'profilingSessionStatusState', - default: 'not_started', -}); +export const profilingSessionStatusState = + createStateV2({ + key: 'profilingSessionStatusState', + defaultValue: 'not_started', + });