From 6b48f197d4a742020966455d128da2d72301e51f Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Fri, 13 Mar 2026 19:45:40 +0100 Subject: [PATCH] feat: deprecate WorkspaceFavorite in favor of NavigationMenuItem (#18624) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - **Removes the entire `modules/favorites/` directory** (~66 files, ~5000 lines deleted) — components, hooks, states, types, utils, tests, and the favorite-folder-picker sub-module - **Eliminates the dual-write pattern** where creating a favorite also created a NavigationMenuItem — all consumers now use `useCreateNavigationMenuItem` directly - **Removes `IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED` feature flag checks** from ~12 files, always taking the NavigationMenuItem code path - **Cleans up backend dual-writes** in `object-metadata.service.ts` and `twenty-standard-application.service.ts` that were creating Favorite records alongside NavigationMenuItems - **Updates prefetch system** to only load NavigationMenuItems (removes favorites prefetch effects and states) - **Cleans up test infrastructure** — updates Storybook decorators, mock data, and graphql mocks to remove favorites references ### What was intentionally kept - **Backend entity definitions** (`FavoriteWorkspaceEntity`, `FavoriteFolderWorkspaceEntity`) — these define the database schema and need a proper database migration to remove - **Cascade deletion listeners** — still needed to clean up existing Favorite data in workspaces that haven't been fully migrated - **v1.18 migration commands** — needed for workspaces upgrading from older versions --------- Co-authored-by: Claude Opus 4.6 --- packages/twenty-front/jest.config.mjs | 4 +- ...oading.stories.tsx => Loading.stories.tsx} | 8 +- .../app/components/AppRouterProviders.tsx | 52 +- ...ShouldCommandMenuItemBeRegisteredParams.ts | 39 +- .../RecordAgnosticCommandMenuItemsConfig.tsx | 6 +- .../AddToFavoritesSingleRecordCommand.tsx | 6 +- .../components/DeleteSingleRecordCommand.tsx | 17 +- ...RemoveFromFavoritesSingleRecordCommand.tsx | 15 +- .../hooks/useCommandMenuContextApi.ts | 30 +- .../CurrentWorkspaceMemberFavorites.tsx | 283 --------- ...CurrentWorkspaceMemberFavoritesFolders.tsx | 91 --- .../CurrentWorkspaceMemberOrphanFavorites.tsx | 85 --- ...riteFolderNavigationDrawerItemDropdown.tsx | 62 -- .../favorites/components/FavoriteIcon.tsx | 28 - .../components/FavoritesBackButton.tsx | 59 -- .../components/FavoritesDragProvider.tsx | 37 -- .../components/FavoritesDroppable.tsx | 72 --- .../components/FavoritesFolderContent.tsx | 77 --- .../favorites/components/FavoritesFolders.tsx | 76 --- .../components/FavoritesSkeletonLoader.tsx | 47 -- .../components/PageFavoriteButton.tsx | 28 - .../components/WorkspaceFavorites.tsx | 24 - .../constants/FavoriteDroppableIds.ts | 7 - .../constants/FavoriteFolderDeleteModalId.ts | 1 - .../contexts/FavoritesDragContext.tsx | 9 - .../components/FavoriteFolderPicker.tsx | 111 ---- .../components/FavoriteFolderPickerEffect.tsx | 82 --- .../components/FavoriteFolderPickerFooter.tsx | 44 -- .../components/FavoriteFolderPickerList.tsx | 79 --- .../FavoriteFolderPickerSearchInput.tsx | 31 - .../FavoriteFolderPickerDropdownId.ts | 2 - .../hooks/useFavoriteFolderPicker.ts | 108 ---- .../FavoriteFolderPickerInstanceContext.ts | 4 - .../favoriteFolderIdPickerComponentState.ts | 10 - ...voriteFolderPickerCheckedComponentState.ts | 9 - ...avoriteFolderPickerComponentFamilyState.ts | 10 - ...voriteFoldersSearchFilterComponentState.ts | 9 - .../favoriteFoldersComponentSelector.ts | 30 - .../favorites/hooks/__mocks__/useFavorites.ts | 290 --------- .../__tests__/useCreateFavorite.test.tsx | 71 --- .../__tests__/useDeleteFavorite.test.tsx | 45 -- .../hooks/__tests__/useFavorites.test.tsx | 39 -- .../useHandleFavoriteDragAndDrop.test.tsx | 172 ------ .../favorites/hooks/useCreateFavorite.ts | 124 ---- .../hooks/useCreateFavoriteFolder.ts | 71 --- .../favorites/hooks/useDeleteFavorite.ts | 14 - .../hooks/useDeleteFavoriteFolder.ts | 16 - .../modules/favorites/hooks/useFavorites.ts | 60 -- .../favorites/hooks/useFavoritesByFolder.ts | 36 -- .../favorites/hooks/useFavoritesMetadata.ts | 34 -- .../hooks/useHandleFavoriteDragAndDrop.ts | 133 ----- .../hooks/usePrefetchedFavoritesData.ts | 30 - .../usePrefetchedFavoritesFoldersData.ts | 26 - .../hooks/useRenameFavoriteFolder.ts | 27 - .../favorites/hooks/useSortedFavorites.ts | 59 -- .../favorites/hooks/useWorkspaceFavorites.ts | 86 --- .../states/isFavoriteFolderCreatingState.ts | 6 - .../states/openFavoriteFolderIdsState.ts | 6 - .../favoriteViewsWithMinimalDataSelector.ts | 20 - .../src/modules/favorites/types/Favorite.ts | 14 - .../favorites/types/FavoriteDroppableId.ts | 6 - .../modules/favorites/types/FavoriteFolder.ts | 9 - .../__tests__/createFolderDroppableId.test.ts | 17 - .../createFolderHeaderDroppableId.test.ts | 19 - .../getFavoriteSecondaryLabel.test.ts | 31 - ...ObjectMetadataNamePluralFromViewId.test.ts | 37 -- .../isLocationMatchingFavorite.test.ts | 55 -- .../utils/__tests__/sortFavorites.test.ts | 233 -------- .../validateAndExtractFolderId.test.ts | 63 -- .../utils/createFolderDroppableId.ts | 6 - .../utils/createFolderHeaderDroppableId.ts | 7 - .../utils/getFavoriteSecondaryLabel.ts | 23 - .../getObjectMetadataNamePluralFromViewId.ts | 30 - .../utils/isLocationMatchingFavorite.ts | 12 - .../modules/favorites/utils/sortFavorites.ts | 98 --- .../NavigationMenuItemSSEEffect.tsx | 6 +- .../ObjectMetadataItemSSEEffect.tsx | 6 +- ...rkspaceMemberNavigationMenuItemFolders.tsx | 12 - ...berNavigationMenuItemFoldersDispatcher.tsx | 19 +- .../components/NavigationMenuEditModeBar.tsx | 8 +- ...igationMenuItemFolderContentDispatcher.tsx | 22 +- .../components/NavigationMenuItemIcon.tsx | 10 +- .../WorkspaceNavigationMenuItems.tsx | 58 +- ...WorkspaceNavigationMenuItemsDispatcher.tsx | 14 +- .../hooks/useCreateNavigationMenuItem.ts | 4 +- .../useCreateNavigationMenuItemFolder.ts | 4 +- .../useHandleNavigationMenuItemDragAndDrop.ts | 4 +- ...eWorkspaceNavigationMenuItemDragAndDrop.ts | 5 +- .../hooks/useNavigationMenuItemsByFolder.ts | 4 +- .../hooks/useNavigationMenuItemsData.ts | 45 ++ .../hooks/useNavigationMenuItemsDraftState.ts | 14 +- .../usePrefetchedNavigationMenuItemsData.ts | 50 -- ...emoveNavigationMenuItemByTargetRecordId.ts | 12 +- .../hooks/useSaveNavigationMenuItemsDraft.ts | 27 +- .../hooks/useSortedNavigationMenuItems.ts | 4 +- .../hooks/useWorkspaceNavigationMenuItems.ts | 4 +- .../hooks/useWorkspaceSectionItems.ts | 5 +- .../states/navigationMenuItemsState.ts} | 6 +- .../__tests__/sortNavigationMenuItems.test.ts | 12 - .../FavoritesDragDropProviderContent.tsx | 48 +- .../MainNavigationDrawerNavigationContent.tsx | 63 +- .../components/NavbarDragProvider.tsx | 38 +- ...igationDrawerItemForObjectMetadataItem.tsx | 91 +-- .../NavigationDrawerOpenedSection.tsx | 31 +- .../RemoteNavigationDrawerSection.tsx | 11 - .../components/RecordFieldList.tsx | 252 ++++---- .../components/RecordIndexPageHeaderIcon.tsx | 17 +- .../hooks/useHandleRecordGroupField.ts | 12 +- .../record-show/components/SummaryCard.tsx | 6 +- .../hooks/useRecordShowContainerData.ts | 4 - .../widgets/field/components/FieldWidget.tsx | 16 - .../components/FieldsWidgetFieldList.tsx | 7 +- .../components/PrefetchDataProvider.tsx | 13 - .../PrefetchRunFavoriteQueriesEffect.tsx | 135 ----- ...etchRunNavigationMenuItemQueriesEffect.tsx | 78 --- ...avoritesFolderOperationSignatureFactory.ts | 18 - ...ndAllFavoritesOperationSignatureFactory.ts | 26 - .../prefetch/hooks/useIsPrefetchLoading.ts | 23 - .../states/prefetchFavoriteFoldersState.ts | 7 - .../prefetch/states/prefetchFavoritesState.ts | 7 - .../states/prefetchIsLoadedFamilyState.ts | 10 - .../src/modules/prefetch/types/PrefetchKey.ts | 5 - .../hooks/useInstantiateSupportChat.ts | 5 +- .../components/NavigationDrawerItem.tsx | 9 +- .../NavigationDrawerSectionTitle.tsx | 9 - .../__stories__/NavigationDrawer.stories.tsx | 7 +- .../states/currentFavoriteFolderIdState.ts | 6 - .../components/LazyMetadataLoadEffect.tsx | 39 ++ .../src/modules/views/components/ViewBar.tsx | 7 +- ...refetchState.ts => useGetViewFromState.ts} | 6 +- .../views/hooks/useSaveCurrentViewFields.ts | 8 +- .../views/hooks/useSaveCurrentViewGroups.ts | 12 +- ...etchedViews.ts => useViewOrDefaultView.ts} | 2 +- .../components/ViewPickerDropdown.tsx | 3 - .../ViewPickerFavoriteFoldersDropdown.tsx | 31 - .../components/ViewPickerOptionDropdown.tsx | 40 +- .../views/view-picker/types/ViewPickerMode.ts | 3 +- .../WorkflowEditActionCreateRecord.tsx | 4 +- .../WorkflowEditActionUpsertRecord.tsx | 4 +- .../testing/decorators/LoadedDecorator.tsx | 5 + .../testing/decorators/LoadingDecorator.tsx | 5 + .../src/testing/decorators/PageDecorator.tsx | 9 +- .../decorators/PrefetchLoadedDecorator.tsx | 22 - .../decorators/PrefetchLoadingDecorator.tsx | 45 -- .../twenty-front/src/testing/graphqlMocks.ts | 32 - .../src/testing/mock-data/favorite-folders.ts | 11 - .../mock-favoriteFolders-data.ts | 9 - .../data/favorites/mock-favorites-data.ts | 560 ------------------ .../object-metadata.service.ts | 32 - .../utils/should-seed-workspace-favorite.ts | 20 - .../prefill-workspace-favorites.ts | 23 - .../twenty-standard-application.service.ts | 61 -- 152 files changed, 444 insertions(+), 5575 deletions(-) rename packages/twenty-front/src/loading/components/__stories__/{PrefetchLoading.stories.tsx => Loading.stories.tsx} (82%) delete mode 100644 packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberOrphanFavorites.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoriteFolderNavigationDrawerItemDropdown.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoriteIcon.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoritesBackButton.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoritesDroppable.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoritesFolderContent.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoritesFolders.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/PageFavoriteButton.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/components/WorkspaceFavorites.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/constants/FavoriteDroppableIds.ts delete mode 100644 packages/twenty-front/src/modules/favorites/constants/FavoriteFolderDeleteModalId.ts delete mode 100644 packages/twenty-front/src/modules/favorites/contexts/FavoritesDragContext.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPicker.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerFooter.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerSearchInput.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/constants/FavoriteFolderPickerDropdownId.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/hooks/useFavoriteFolderPicker.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderIdPickerComponentState.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerCheckedComponentState.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFolderPickerComponentFamilyState.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/favoriteFoldersSearchFilterComponentState.ts delete mode 100644 packages/twenty-front/src/modules/favorites/favorite-folder-picker/states/selectors/favoriteFoldersComponentSelector.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/__tests__/useCreateFavorite.test.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/__tests__/useDeleteFavorite.test.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/__tests__/useFavorites.test.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/__tests__/useHandleFavoriteDragAndDrop.test.tsx delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useCreateFavorite.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useCreateFavoriteFolder.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useDeleteFavorite.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useDeleteFavoriteFolder.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useFavorites.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useFavoritesByFolder.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useFavoritesMetadata.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useHandleFavoriteDragAndDrop.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/usePrefetchedFavoritesData.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/usePrefetchedFavoritesFoldersData.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useRenameFavoriteFolder.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useSortedFavorites.ts delete mode 100644 packages/twenty-front/src/modules/favorites/hooks/useWorkspaceFavorites.ts delete mode 100644 packages/twenty-front/src/modules/favorites/states/isFavoriteFolderCreatingState.ts delete mode 100644 packages/twenty-front/src/modules/favorites/states/openFavoriteFolderIdsState.ts delete mode 100644 packages/twenty-front/src/modules/favorites/states/selectors/favoriteViewsWithMinimalDataSelector.ts delete mode 100644 packages/twenty-front/src/modules/favorites/types/Favorite.ts delete mode 100644 packages/twenty-front/src/modules/favorites/types/FavoriteDroppableId.ts delete mode 100644 packages/twenty-front/src/modules/favorites/types/FavoriteFolder.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/createFolderDroppableId.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/createFolderHeaderDroppableId.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/getFavoriteSecondaryLabel.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/getObjectMetadataNamePluralFromViewId.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/isLocationMatchingFavorite.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/sortFavorites.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/__tests__/validateAndExtractFolderId.test.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/createFolderDroppableId.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/createFolderHeaderDroppableId.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/getFavoriteSecondaryLabel.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/getObjectMetadataNamePluralFromViewId.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/isLocationMatchingFavorite.ts delete mode 100644 packages/twenty-front/src/modules/favorites/utils/sortFavorites.ts create mode 100644 packages/twenty-front/src/modules/navigation-menu-item/hooks/useNavigationMenuItemsData.ts delete mode 100644 packages/twenty-front/src/modules/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData.ts rename packages/twenty-front/src/modules/{prefetch/states/prefetchNavigationMenuItemsState.ts => navigation-menu-item/states/navigationMenuItemsState.ts} (57%) delete mode 100644 packages/twenty-front/src/modules/prefetch/components/PrefetchDataProvider.tsx delete mode 100644 packages/twenty-front/src/modules/prefetch/components/PrefetchRunFavoriteQueriesEffect.tsx delete mode 100644 packages/twenty-front/src/modules/prefetch/components/PrefetchRunNavigationMenuItemQueriesEffect.tsx delete mode 100644 packages/twenty-front/src/modules/prefetch/graphql/operation-signatures/factories/findAllFavoritesFolderOperationSignatureFactory.ts delete mode 100644 packages/twenty-front/src/modules/prefetch/graphql/operation-signatures/factories/findAllFavoritesOperationSignatureFactory.ts delete mode 100644 packages/twenty-front/src/modules/prefetch/hooks/useIsPrefetchLoading.ts delete mode 100644 packages/twenty-front/src/modules/prefetch/states/prefetchFavoriteFoldersState.ts delete mode 100644 packages/twenty-front/src/modules/prefetch/states/prefetchFavoritesState.ts delete mode 100644 packages/twenty-front/src/modules/prefetch/states/prefetchIsLoadedFamilyState.ts delete mode 100644 packages/twenty-front/src/modules/prefetch/types/PrefetchKey.ts delete mode 100644 packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/currentFavoriteFolderIdState.ts rename packages/twenty-front/src/modules/views/hooks/{useGetViewFromPrefetchState.ts => useGetViewFromState.ts} (74%) rename packages/twenty-front/src/modules/views/hooks/{useViewOrDefaultViewFromPrefetchedViews.ts => useViewOrDefaultView.ts} (92%) delete mode 100644 packages/twenty-front/src/modules/views/view-picker/components/ViewPickerFavoriteFoldersDropdown.tsx create mode 100644 packages/twenty-front/src/testing/decorators/LoadedDecorator.tsx create mode 100644 packages/twenty-front/src/testing/decorators/LoadingDecorator.tsx delete mode 100644 packages/twenty-front/src/testing/decorators/PrefetchLoadedDecorator.tsx delete mode 100644 packages/twenty-front/src/testing/decorators/PrefetchLoadingDecorator.tsx delete mode 100644 packages/twenty-front/src/testing/mock-data/favorite-folders.ts delete mode 100644 packages/twenty-front/src/testing/mock-data/generated/data/favoriteFolders/mock-favoriteFolders-data.ts delete mode 100644 packages/twenty-front/src/testing/mock-data/generated/data/favorites/mock-favorites-data.ts delete mode 100644 packages/twenty-server/src/engine/utils/should-seed-workspace-favorite.ts delete mode 100644 packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites.ts diff --git a/packages/twenty-front/jest.config.mjs b/packages/twenty-front/jest.config.mjs index 5e70a8800f..ded5c4f426 100644 --- a/packages/twenty-front/jest.config.mjs +++ b/packages/twenty-front/jest.config.mjs @@ -61,8 +61,8 @@ const jestConfig = { extensionsToTreatAsEsm: ['.ts', '.tsx'], coverageThreshold: { global: { - statements: 49, - lines: 47.6, + statements: 48.8, + lines: 47.5, functions: 39.5, }, }, diff --git a/packages/twenty-front/src/loading/components/__stories__/PrefetchLoading.stories.tsx b/packages/twenty-front/src/loading/components/__stories__/Loading.stories.tsx similarity index 82% rename from packages/twenty-front/src/loading/components/__stories__/PrefetchLoading.stories.tsx rename to packages/twenty-front/src/loading/components/__stories__/Loading.stories.tsx index 7ba6004312..cf04d11b65 100644 --- a/packages/twenty-front/src/loading/components/__stories__/PrefetchLoading.stories.tsx +++ b/packages/twenty-front/src/loading/components/__stories__/Loading.stories.tsx @@ -6,11 +6,11 @@ import { PageDecorator, type PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; -import { PrefetchLoadingDecorator } from '~/testing/decorators/PrefetchLoadingDecorator'; +import { LoadingDecorator } from '~/testing/decorators/LoadingDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; const meta: Meta = { - title: 'App/Loading/PrefetchLoading', + title: 'App/Loading', component: RecordIndexPage, args: { routePath: '/objects/:objectNamePlural', @@ -20,7 +20,7 @@ const meta: Meta = { }, parameters: { msw: graphqlMocks, - prefetchLoadingSetDelay: 1000, + loadingSetDelay: 1000, }, tags: ['no-tests'], }; @@ -32,7 +32,7 @@ export type Story = StoryObj; export const Default: Story = { // oxlint-disable-next-line @typescripttypescript/ban-ts-comment // @ts-ignore - decorators: [PrefetchLoadingDecorator, PageDecorator], + decorators: [LoadingDecorator, PageDecorator], play: async ({ canvasElement }) => { const canvas = within(canvasElement); diff --git a/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx b/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx index 229610887c..3b7da864ab 100644 --- a/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx +++ b/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx @@ -18,7 +18,7 @@ import { PromiseRejectionEffect } from '@/error-handler/components/PromiseReject import { HeadlessFrontComponentMountRoot } from '@/front-components/components/HeadlessFrontComponentMountRoot'; import { ApolloCoreProvider } from '@/object-metadata/components/ApolloCoreProvider'; import { PreComputedChipGeneratorsProvider } from '@/object-metadata/components/PreComputedChipGeneratorsProvider'; -import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider'; + import { SSEProvider } from '@/sse-db-event/components/SSEProvider'; import { SupportChatEffect } from '@/support/components/SupportChatEffect'; import { DialogManager } from '@/ui/feedback/dialog-manager/components/DialogManager'; @@ -56,32 +56,30 @@ export const AppRouterProviders = () => { - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/twenty-front/src/modules/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams.ts b/packages/twenty-front/src/modules/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams.ts index efad4feef3..d42d0e1359 100644 --- a/packages/twenty-front/src/modules/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams.ts +++ b/packages/twenty-front/src/modules/command-menu-item/hooks/useShouldCommandMenuItemBeRegisteredParams.ts @@ -7,8 +7,7 @@ import { contextStoreCurrentViewTypeComponentState } from '@/context-store/state import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData'; +import { useNavigationMenuItemsData } from '@/navigation-menu-item/hooks/useNavigationMenuItemsData'; import { CoreObjectNameSingular } from 'twenty-shared/types'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; @@ -19,11 +18,10 @@ import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useStore } from 'jotai'; import { useCallback, useContext, useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; +import type { FeatureFlagKey } from '~/generated-metadata/graphql'; export const useShouldCommandMenuItemBeRegisteredParams = ({ objectMetadataItem, @@ -31,11 +29,7 @@ export const useShouldCommandMenuItemBeRegisteredParams = ({ objectMetadataItem?: ObjectMetadataItem; }): ShouldBeRegisteredFunctionParams => { const store = useStore(); - const { sortedFavorites: favorites } = useFavorites(); - const { navigationMenuItems } = usePrefetchedNavigationMenuItemsData(); - const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED, - ); + const { navigationMenuItems } = useNavigationMenuItemsData(); const contextStoreTargetedRecordsRule = useAtomComponentStateValue( contextStoreTargetedRecordsRuleComponentState, @@ -47,30 +41,17 @@ export const useShouldCommandMenuItemBeRegisteredParams = ({ : undefined; const isFavorite = useMemo(() => { - if (!isDefined(recordId)) { + if (!isDefined(recordId) || !isDefined(objectMetadataItem)) { return false; } - if (isNavigationMenuItemEditingEnabled && isDefined(objectMetadataItem)) { - const foundNavigationMenuItem = navigationMenuItems?.find( - (item) => - item.targetRecordId === recordId && - item.targetObjectMetadataId === objectMetadataItem.id, - ); - return !!foundNavigationMenuItem; - } - - const foundFavorite = favorites?.find( - (favorite) => favorite.recordId === recordId, + const foundNavigationMenuItem = navigationMenuItems?.find( + (item) => + item.targetRecordId === recordId && + item.targetObjectMetadataId === objectMetadataItem.id, ); - return !!foundFavorite; - }, [ - recordId, - isNavigationMenuItemEditingEnabled, - objectMetadataItem, - navigationMenuItems, - favorites, - ]); + return !!foundNavigationMenuItem; + }, [recordId, objectMetadataItem, navigationMenuItems]); const selectedRecord = useAtomFamilyStateValue(recordStoreFamilyState, recordId ?? '') || diff --git a/packages/twenty-front/src/modules/command-menu-item/record-agnostic/constants/RecordAgnosticCommandMenuItemsConfig.tsx b/packages/twenty-front/src/modules/command-menu-item/record-agnostic/constants/RecordAgnosticCommandMenuItemsConfig.tsx index f2a6cb34e0..55cd9654a6 100644 --- a/packages/twenty-front/src/modules/command-menu-item/record-agnostic/constants/RecordAgnosticCommandMenuItemsConfig.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/record-agnostic/constants/RecordAgnosticCommandMenuItemsConfig.tsx @@ -12,7 +12,6 @@ import { IconSearch, IconSparkles, } from 'twenty-ui/display'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; export const RECORD_AGNOSTIC_COMMAND_MENU_ITEMS_CONFIG: Record< string, @@ -108,10 +107,7 @@ export const RECORD_AGNOSTIC_COMMAND_MENU_ITEMS_CONFIG: Record< Icon: IconLayout, isPinned: false, availableOn: [CommandMenuItemViewType.GLOBAL], - shouldBeRegistered: ({ isFeatureFlagEnabled }) => - isFeatureFlagEnabled( - FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED, - ), + shouldBeRegistered: () => true, component: , }, }; diff --git a/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/AddToFavoritesSingleRecordCommand.tsx b/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/AddToFavoritesSingleRecordCommand.tsx index c8222f8024..72ec78f57d 100644 --- a/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/AddToFavoritesSingleRecordCommand.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/AddToFavoritesSingleRecordCommand.tsx @@ -1,7 +1,7 @@ import { Command } from '@/command-menu-item/display/components/Command'; import { useSelectedRecordIdOrThrow } from '@/command-menu-item/record/single-record/hooks/useSelectedRecordIdOrThrow'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; -import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite'; +import { useCreateNavigationMenuItem } from '@/navigation-menu-item/hooks/useCreateNavigationMenuItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; import { isDefined } from 'twenty-shared/utils'; @@ -11,7 +11,7 @@ export const AddToFavoritesSingleRecordCommand = () => { const recordId = useSelectedRecordIdOrThrow(); - const { createFavorite } = useCreateFavorite(); + const { createNavigationMenuItem } = useCreateNavigationMenuItem(); const recordStore = useAtomFamilyStateValue(recordStoreFamilyState, recordId); @@ -20,7 +20,7 @@ export const AddToFavoritesSingleRecordCommand = () => { return; } - createFavorite(recordStore, objectMetadataItem.nameSingular); + createNavigationMenuItem(recordStore, objectMetadataItem.nameSingular); }; return ; diff --git a/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/DeleteSingleRecordCommand.tsx b/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/DeleteSingleRecordCommand.tsx index 7811e6f4d1..3766da74c7 100644 --- a/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/DeleteSingleRecordCommand.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/DeleteSingleRecordCommand.tsx @@ -1,8 +1,6 @@ import { Command } from '@/command-menu-item/display/components/Command'; import { useSelectedRecordIdOrThrow } from '@/command-menu-item/record/single-record/hooks/useSelectedRecordIdOrThrow'; -import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; -import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData'; +import { useNavigationMenuItemsData } from '@/navigation-menu-item/hooks/useNavigationMenuItemsData'; import { useRemoveNavigationMenuItemByTargetRecordId } from '@/navigation-menu-item/hooks/useRemoveNavigationMenuItemByTargetRecordId'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { useRemoveSelectedRecordsFromRecordBoard } from '@/object-record/record-board/hooks/useRemoveSelectedRecordsFromRecordBoard'; @@ -25,11 +23,8 @@ export const DeleteSingleRecordCommand = () => { objectNameSingular: objectMetadataItem.nameSingular, }); - const { sortedFavorites: favorites } = useFavorites(); - const { deleteFavorite } = useDeleteFavorite(); - const { navigationMenuItems, workspaceNavigationMenuItems } = - usePrefetchedNavigationMenuItemsData(); + useNavigationMenuItemsData(); const { removeNavigationMenuItemsByTargetRecordIds } = useRemoveNavigationMenuItemByTargetRecordId(); @@ -38,14 +33,6 @@ export const DeleteSingleRecordCommand = () => { resetTableRowSelection(); - const foundFavorite = favorites?.find( - (favorite) => favorite.recordId === recordId, - ); - - if (isDefined(foundFavorite)) { - deleteFavorite(foundFavorite.id); - } - const foundNavigationMenuItem = [ ...navigationMenuItems, ...workspaceNavigationMenuItems, diff --git a/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/RemoveFromFavoritesSingleRecordCommand.tsx b/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/RemoveFromFavoritesSingleRecordCommand.tsx index a3e4d540c7..3b996db0a4 100644 --- a/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/RemoveFromFavoritesSingleRecordCommand.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/record/single-record/components/RemoveFromFavoritesSingleRecordCommand.tsx @@ -1,27 +1,19 @@ import { Command } from '@/command-menu-item/display/components/Command'; import { useSelectedRecordIdOrThrow } from '@/command-menu-item/record/single-record/hooks/useSelectedRecordIdOrThrow'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; -import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; -import { useFavorites } from '@/favorites/hooks/useFavorites'; import { useDeleteNavigationMenuItem } from '@/navigation-menu-item/hooks/useDeleteNavigationMenuItem'; -import { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData'; +import { useNavigationMenuItemsData } from '@/navigation-menu-item/hooks/useNavigationMenuItemsData'; import { isDefined } from 'twenty-shared/utils'; export const RemoveFromFavoritesSingleRecordCommand = () => { const recordId = useSelectedRecordIdOrThrow(); const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const { sortedFavorites: favorites } = useFavorites(); const { navigationMenuItems, workspaceNavigationMenuItems } = - usePrefetchedNavigationMenuItemsData(); + useNavigationMenuItemsData(); - const { deleteFavorite } = useDeleteFavorite(); const { deleteNavigationMenuItem } = useDeleteNavigationMenuItem(); - const foundFavorite = favorites?.find( - (favorite) => favorite.recordId === recordId, - ); - const foundNavigationMenuItem = [ ...navigationMenuItems, ...workspaceNavigationMenuItems, @@ -32,12 +24,11 @@ export const RemoveFromFavoritesSingleRecordCommand = () => { ); const handleClick = () => { - if (!isDefined(foundNavigationMenuItem) || !isDefined(foundFavorite)) { + if (!isDefined(foundNavigationMenuItem)) { return; } deleteNavigationMenuItem(foundNavigationMenuItem.id); - deleteFavorite(foundFavorite.id); }; return ; diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts index 8aec0ec12b..5e86caf85b 100644 --- a/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/hooks/useCommandMenuContextApi.ts @@ -7,8 +7,7 @@ import { contextStoreIsPageInEditModeComponentState } from '@/context-store/stat import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData'; +import { useNavigationMenuItemsData } from '@/navigation-menu-item/hooks/useNavigationMenuItemsData'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; @@ -18,7 +17,6 @@ import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isNonEmptyArray } from '@sniptt/guards'; import { useStore } from 'jotai'; import { useContext } from 'react'; @@ -27,7 +25,6 @@ import { type CommandMenuContextApi, } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; export const useCommandMenuContextApi = (): CommandMenuContextApi => { const store = useStore(); @@ -42,18 +39,13 @@ export const useCommandMenuContextApi = (): CommandMenuContextApi => { contextStoreTargetedRecordsRuleComponentState, ); - const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED, - ); - const { objectMetadataItems } = useObjectMetadataItems(); const objectMetadataItem = objectMetadataItems.find( (item) => item.id === contextStoreCurrentObjectMetadataItemId, ); - const { sortedFavorites: favorites } = useFavorites(); - const { navigationMenuItems } = usePrefetchedNavigationMenuItemsData(); + const { navigationMenuItems } = useNavigationMenuItemsData(); const recordIds = contextStoreTargetedRecordsRule.mode === 'selection' @@ -61,22 +53,16 @@ export const useCommandMenuContextApi = (): CommandMenuContextApi => { : undefined; const favoriteRecordIds = (() => { - if (!isNonEmptyArray(recordIds)) { + if (!isNonEmptyArray(recordIds) || !isDefined(objectMetadataItem)) { return []; } - if (isNavigationMenuItemEditingEnabled && isDefined(objectMetadataItem)) { - return recordIds.filter((recordId) => - navigationMenuItems?.some( - (item) => - item.targetRecordId === recordId && - item.targetObjectMetadataId === objectMetadataItem.id, - ), - ); - } - return recordIds.filter((recordId) => - favorites?.some((favorite) => favorite.recordId === recordId), + navigationMenuItems?.some( + (item) => + item.targetRecordId === recordId && + item.targetObjectMetadataId === objectMetadataItem.id, + ), ); })(); diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx deleted file mode 100644 index d0d1f3b686..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import { FavoriteFolderNavigationDrawerItemDropdown } from '@/favorites/components/FavoriteFolderNavigationDrawerItemDropdown'; -import { FavoriteIcon } from '@/favorites/components/FavoriteIcon'; -import { FavoritesDroppable } from '@/favorites/components/FavoritesDroppable'; -import { FAVORITE_FOLDER_DELETE_MODAL_ID } from '@/favorites/constants/FavoriteFolderDeleteModalId'; -import { FavoritesDragContext } from '@/favorites/contexts/FavoritesDragContext'; -import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; -import { useDeleteFavoriteFolder } from '@/favorites/hooks/useDeleteFavoriteFolder'; -import { useRenameFavoriteFolder } from '@/favorites/hooks/useRenameFavoriteFolder'; -import { openFavoriteFolderIdsState } from '@/favorites/states/openFavoriteFolderIdsState'; -import { getFavoriteSecondaryLabel } from '@/favorites/utils/getFavoriteSecondaryLabel'; -import { isLocationMatchingFavorite } from '@/favorites/utils/isLocationMatchingFavorite'; -import { type ProcessedFavorite } from '@/favorites/utils/sortFavorites'; -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; -import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; -import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState'; -import { NavigationDrawerInput } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerInput'; -import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; -import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer'; -import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem'; -import { currentFavoriteFolderIdState } from '@/ui/navigation/navigation-drawer/states/currentFavoriteFolderIdState'; -import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; -import { Droppable } from '@hello-pangea/dnd'; -import { useLingui } from '@lingui/react/macro'; -import { useContext, useState } from 'react'; -import { createPortal } from 'react-dom'; -import { useLocation } from 'react-router-dom'; -import { IconFolder, IconFolderOpen, IconHeartOff } from 'twenty-ui/display'; -import { LightIconButton } from 'twenty-ui/input'; -import { AnimatedExpandableContainer } from 'twenty-ui/layout'; -import { useIsMobile } from 'twenty-ui/utilities'; - -type CurrentWorkspaceMemberFavoritesProps = { - folder: { - folderId: string; - folderName: string; - favorites: ProcessedFavorite[]; - }; - isGroup: boolean; -}; - -export const CurrentWorkspaceMemberFavorites = ({ - folder, - isGroup, -}: CurrentWorkspaceMemberFavoritesProps) => { - const { t } = useLingui(); - const objectMetadataItems = useAtomStateValue(objectMetadataItemsState); - const currentPath = useLocation().pathname; - const currentViewPath = useLocation().pathname + useLocation().search; - const { isDragging } = useContext(FavoritesDragContext); - const [isFavoriteFolderRenaming, setIsFavoriteFolderRenaming] = - useState(false); - const [favoriteFolderName, setFavoriteFolderName] = useState( - folder.folderName, - ); - const { openModal } = useModal(); - - const isMobile = useIsMobile(); - - const [openFavoriteFolderIds, setOpenFavoriteFolderIds] = useAtomState( - openFavoriteFolderIdsState, - ); - - const setCurrentFavoriteFolderId = useSetAtomState( - currentFavoriteFolderIdState, - ); - - const isOpen = openFavoriteFolderIds.includes(folder.folderId); - - const handleToggle = () => { - if (isMobile) { - setCurrentFavoriteFolderId((prev) => - prev === folder.folderId ? null : folder.folderId, - ); - } else { - setOpenFavoriteFolderIds((currentOpenFolders) => { - if (isOpen) { - return currentOpenFolders.filter((id) => id !== folder.folderId); - } else { - return [...currentOpenFolders, folder.folderId]; - } - }); - } - }; - - const { renameFavoriteFolder } = useRenameFavoriteFolder(); - const { deleteFavoriteFolder } = useDeleteFavoriteFolder(); - - const dropdownId = `favorite-folder-edit-${folder.folderId}`; - - const isDropdownOpen = useAtomComponentStateValue( - isDropdownOpenComponentState, - dropdownId, - ); - - const { closeDropdown } = useCloseDropdown(); - - const selectedFavoriteIndex = folder.favorites.findIndex((favorite) => - isLocationMatchingFavorite(currentPath, currentViewPath, favorite), - ); - - const { deleteFavorite } = useDeleteFavorite(); - - const favoriteFolderContentLength = folder.favorites.length; - - const handleSubmitRename = async (value: string) => { - if (value === '') return; - await renameFavoriteFolder(folder.folderId, value); - setIsFavoriteFolderRenaming(false); - return true; - }; - - const handleCancelRename = () => { - setFavoriteFolderName(folder.folderName); - setIsFavoriteFolderRenaming(false); - }; - - const handleClickOutside = async ( - event: MouseEvent | TouchEvent, - value: string, - ) => { - if (!value) { - setIsFavoriteFolderRenaming(false); - return; - } - - await renameFavoriteFolder(folder.folderId, value); - setIsFavoriteFolderRenaming(false); - }; - - const modalId = `${FAVORITE_FOLDER_DELETE_MODAL_ID}-${folder.folderId}`; - - const handleFavoriteFolderDelete = async () => { - if (folder.favorites.length > 0) { - openModal(modalId); - closeDropdown(dropdownId); - } else { - await deleteFavoriteFolder(folder.folderId); - closeDropdown(dropdownId); - } - }; - - const handleConfirmDelete = async () => { - await deleteFavoriteFolder(folder.folderId); - }; - - const rightOptions = ( - setIsFavoriteFolderRenaming(true)} - onDelete={handleFavoriteFolderDelete} - closeDropdown={() => { - closeDropdown(dropdownId); - }} - /> - ); - - const isModalOpened = useAtomComponentStateValue( - isModalOpenedComponentState, - modalId, - ); - - const favoriteCount = folder.favorites.length; - - return ( - <> - - {isFavoriteFolderRenaming ? ( - - ) : ( - - - - )} - - - - {(provided) => ( -
- {folder.favorites.map((favorite, index) => ( - } - to={isDragging ? undefined : favorite.link} - active={index === selectedFavoriteIndex} - subItemState={getNavigationSubItemLeftAdornment({ - index, - arrayLength: favoriteFolderContentLength, - selectedIndex: selectedFavoriteIndex, - })} - rightOptions={ - { - e.stopPropagation(); - deleteFavorite(favorite.id); - }} - accent="tertiary" - /> - } - isDragging={isDragging} - triggerEvent="CLICK" - /> - } - /> - ))} - {provided.placeholder} -
- )} -
-
-
- - {isModalOpened && - createPortal( - 1 - ? t`Remove ${favoriteCount} favorites?` - : t`Remove ${favoriteCount} favorite?` - } - subtitle={ - folder.favorites.length > 1 - ? t`This action will delete this favorite folder and all ${favoriteCount} favorites inside. Do you want to continue?` - : t`This action will delete this favorite folder and the favorite inside. Do you want to continue?` - } - onConfirmClick={handleConfirmDelete} - confirmButtonText={t`Delete Folder`} - />, - document.body, - )} - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx deleted file mode 100644 index 2476039371..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { CurrentWorkspaceMemberOrphanFavorites } from '@/favorites/components/CurrentWorkspaceMemberOrphanFavorites'; -import { FavoritesDragProvider } from '@/favorites/components/FavoritesDragProvider'; -import { FavoriteFolders } from '@/favorites/components/FavoritesFolders'; -import { FavoritesSkeletonLoader } from '@/favorites/components/FavoritesSkeletonLoader'; -import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { useFavoritesByFolder } from '@/favorites/hooks/useFavoritesByFolder'; -import { isFavoriteFolderCreatingState } from '@/favorites/states/isFavoriteFolderCreatingState'; -import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading'; -import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper'; -import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; -import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; -import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; -import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState'; -import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; -import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useLingui } from '@lingui/react/macro'; -import { isDefined } from 'twenty-shared/utils'; -import { IconFolderPlus } from 'twenty-ui/display'; -import { LightIconButton } from 'twenty-ui/input'; -import { AnimatedExpandableContainer } from 'twenty-ui/layout'; - -export const CurrentWorkspaceMemberFavoritesFolders = () => { - const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); - const { sortedFavorites: favorites } = useFavorites(); - const { favoritesByFolder } = useFavoritesByFolder(); - - const [isFavoriteFolderCreating, setIsFavoriteFolderCreating] = useAtomState( - isFavoriteFolderCreatingState, - ); - - const loading = useIsPrefetchLoading(); - - const { t } = useLingui(); - - const { toggleNavigationSection, openNavigationSection } = - useNavigationSection('Favorites'); - const isNavigationSectionOpen = useAtomFamilyStateValue( - isNavigationSectionOpenFamilyState, - 'Favorites', - ); - - const toggleNewFolder = () => { - openNavigationSection(); - setIsFavoriteFolderCreating((current) => !current); - }; - - if (loading && isDefined(currentWorkspaceMember)) { - return ; - } - - if ( - favorites.length === 0 && - !isFavoriteFolderCreating && - favoritesByFolder.length === 0 - ) { - return null; - } - - return ( - - - - } - isOpen={isNavigationSectionOpen} - /> - - - - - - - - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberOrphanFavorites.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberOrphanFavorites.tsx deleted file mode 100644 index bdb0fbde39..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberOrphanFavorites.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { FavoriteIcon } from '@/favorites/components/FavoriteIcon'; -import { FavoritesDroppable } from '@/favorites/components/FavoritesDroppable'; -import { FavoritesDragContext } from '@/favorites/contexts/FavoritesDragContext'; -import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; -import { useFavorites } from '@/favorites/hooks/useFavorites'; -import { getFavoriteSecondaryLabel } from '@/favorites/utils/getFavoriteSecondaryLabel'; -import { isLocationMatchingFavorite } from '@/favorites/utils/isLocationMatchingFavorite'; -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; -import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { styled } from '@linaria/react'; -import { useContext } from 'react'; -import { useLocation } from 'react-router-dom'; -import { IconHeartOff } from 'twenty-ui/display'; -import { LightIconButton } from 'twenty-ui/input'; -import { themeCssVariables } from 'twenty-ui/theme-constants'; - -const StyledEmptyContainer = styled.div` - width: 100%; -`; - -const StyledOrphanFavoritesContainer = styled.div` - margin-bottom: ${themeCssVariables.betweenSiblingsGap}; -`; - -export const CurrentWorkspaceMemberOrphanFavorites = () => { - const objectMetadataItems = useAtomStateValue(objectMetadataItemsState); - const { sortedFavorites: favorites } = useFavorites(); - const { deleteFavorite } = useDeleteFavorite(); - const currentPath = useLocation().pathname; - const currentViewPath = useLocation().pathname + useLocation().search; - const { isDragging } = useContext(FavoritesDragContext); - - const orphanFavorites = favorites.filter( - (favorite) => !favorite.favoriteFolderId, - ); - - return ( - - {orphanFavorites.length > 0 ? ( - orphanFavorites.map((favorite, index) => ( - - } - active={isLocationMatchingFavorite( - currentPath, - currentViewPath, - favorite, - )} - to={isDragging ? undefined : favorite.link} - rightOptions={ - { - e.stopPropagation(); - deleteFavorite(favorite.id); - }} - accent="tertiary" - /> - } - isDragging={isDragging} - triggerEvent="CLICK" - /> - - } - /> - )) - ) : ( - - )} - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoriteFolderNavigationDrawerItemDropdown.tsx b/packages/twenty-front/src/modules/favorites/components/FavoriteFolderNavigationDrawerItemDropdown.tsx deleted file mode 100644 index 04f8e0781b..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoriteFolderNavigationDrawerItemDropdown.tsx +++ /dev/null @@ -1,62 +0,0 @@ -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 { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useLingui } from '@lingui/react/macro'; -import { IconDotsVertical, IconPencil, IconTrash } from 'twenty-ui/display'; -import { LightIconButton } from 'twenty-ui/input'; -import { MenuItem } from 'twenty-ui/navigation'; - -type FavoriteFolderNavigationDrawerItemDropdownProps = { - folderId: string; - onRename: () => void; - onDelete: () => void; - closeDropdown: () => void; -}; - -export const FavoriteFolderNavigationDrawerItemDropdown = ({ - folderId, - onRename, - onDelete, - closeDropdown, -}: FavoriteFolderNavigationDrawerItemDropdownProps) => { - const { t } = useLingui(); - const handleRename = () => { - closeDropdown(); - onRename(); - }; - - const handleDelete = () => { - closeDropdown(); - onDelete(); - }; - - return ( - - } - dropdownPlacement="bottom-start" - dropdownComponents={ - - - - - - - } - /> - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoriteIcon.tsx b/packages/twenty-front/src/modules/favorites/components/FavoriteIcon.tsx deleted file mode 100644 index 90f5294a0c..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoriteIcon.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { type ProcessedFavorite } from '@/favorites/utils/sortFavorites'; -import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon'; -import { useContext } from 'react'; -import { Avatar, useIcons } from 'twenty-ui/display'; -import { ThemeContext } from 'twenty-ui/theme-constants'; - -export const FavoriteIcon = ({ favorite }: { favorite: ProcessedFavorite }) => { - const { theme } = useContext(ThemeContext); - const { getIcon } = useIcons(); - const { Icon: StandardIcon, IconColor } = useGetStandardObjectIcon( - favorite.objectNameSingular || '', - ); - const IconToUse = - StandardIcon || (favorite.Icon ? getIcon(favorite.Icon) : undefined); - const iconColorToUse = StandardIcon ? IconColor : theme.font.color.secondary; - - return ( - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesBackButton.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesBackButton.tsx deleted file mode 100644 index 4064f6875a..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesBackButton.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { currentFavoriteFolderIdState } from '@/ui/navigation/navigation-drawer/states/currentFavoriteFolderIdState'; -import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; -import { styled } from '@linaria/react'; -import { IconX } from 'twenty-ui/display'; -import { useContext } from 'react'; -import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants'; - -const StyledBackButton = styled.button` - align-items: center; - background: transparent; - border: none; - color: ${themeCssVariables.font.color.secondary}; - cursor: pointer; - display: flex; - font-family: ${themeCssVariables.font.family}; - font-weight: ${themeCssVariables.font.weight.medium}; - gap: ${themeCssVariables.spacing[2]}; - padding-bottom: ${themeCssVariables.spacing[1]}; - padding-left: ${themeCssVariables.spacing[1]}; - padding-right: ${themeCssVariables.spacing[0.5]}; - padding-top: ${themeCssVariables.spacing[1]}; - text-align: left; - width: 100%; - - &:hover { - background: ${themeCssVariables.background.transparent.light}; - border-radius: ${themeCssVariables.border.radius.sm}; - } -`; - -type FavoritesBackButtonProps = { - folderName: string; -}; - -export const FavoritesBackButton = ({ - folderName, -}: FavoritesBackButtonProps) => { - const { theme } = useContext(ThemeContext); - const setCurrentFavoriteFolderId = useSetAtomState( - currentFavoriteFolderIdState, - ); - - const handleClick = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - setCurrentFavoriteFolderId(null); - }; - - return ( - - - {folderName} - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx deleted file mode 100644 index 696b81df07..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesDragProvider.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { FavoritesDragContext } from '@/favorites/contexts/FavoritesDragContext'; -import { useHandleFavoriteDragAndDrop } from '@/favorites/hooks/useHandleFavoriteDragAndDrop'; -import { - DragDropContext, - type DragStart, - type DropResult, - type ResponderProvided, -} from '@hello-pangea/dnd'; -import { type ReactNode, useState } from 'react'; - -type FavoritesDragProviderProps = { - children: ReactNode; -}; - -export const FavoritesDragProvider = ({ - children, -}: FavoritesDragProviderProps) => { - const [isDragging, setIsDragging] = useState(false); - const { handleFavoriteDragAndDrop } = useHandleFavoriteDragAndDrop(); - - const handleDragStart = (_: DragStart) => { - setIsDragging(true); - }; - - const handleDragEnd = (result: DropResult, provided: ResponderProvided) => { - setIsDragging(false); - handleFavoriteDragAndDrop(result, provided); - }; - - return ( - - - {children} - - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesDroppable.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesDroppable.tsx deleted file mode 100644 index 8b119bd66b..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesDroppable.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { styled } from '@linaria/react'; -import { Droppable } from '@hello-pangea/dnd'; -import { themeCssVariables } from 'twenty-ui/theme-constants'; - -type FavoritesDroppableProps = { - droppableId: string; - children: React.ReactNode; - isDragIndicatorVisible?: boolean; - showDropLine?: boolean; -}; - -const StyledDroppableWrapper = styled.div<{ - isDraggingOver: boolean; - isDragIndicatorVisible: boolean; - showDropLine: boolean; -}>` - position: relative; - transition: all 150ms ease-in-out; - width: 100%; - - ${({ isDraggingOver, isDragIndicatorVisible, showDropLine }) => - isDraggingOver && isDragIndicatorVisible - ? ` - background-color: ${themeCssVariables.background.transparent.blue}; - - ${ - showDropLine - ? ` - &::before { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 2px; - background-color: ${themeCssVariables.color.blue}; - border-radius: ${themeCssVariables.border.radius.sm} ${themeCssVariables.border.radius.sm} 0 0; - } - ` - : '' - } - ` - : ''} -`; - -export const FavoritesDroppable = ({ - droppableId, - children, - isDragIndicatorVisible = true, - showDropLine = true, -}: FavoritesDroppableProps) => { - return ( - - {(provided, snapshot) => ( - -
- {children} - {provided.placeholder} -
-
- )} -
- ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesFolderContent.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesFolderContent.tsx deleted file mode 100644 index e262a57cb8..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesFolderContent.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { FavoriteIcon } from '@/favorites/components/FavoriteIcon'; -import { FavoritesBackButton } from '@/favorites/components/FavoritesBackButton'; -import { FavoritesDragProvider } from '@/favorites/components/FavoritesDragProvider'; -import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; -import { getFavoriteSecondaryLabel } from '@/favorites/utils/getFavoriteSecondaryLabel'; -import { type ProcessedFavorite } from '@/favorites/utils/sortFavorites'; -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem'; -import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { Droppable } from '@hello-pangea/dnd'; -import { IconHeartOff } from 'twenty-ui/display'; -import { LightIconButton } from 'twenty-ui/input'; - -type FavoritesFolderContentProps = { - folderId: string; - folderName: string; - favorites: ProcessedFavorite[]; -}; - -export const FavoritesFolderContent = ({ - folderName, - folderId, - favorites, -}: FavoritesFolderContentProps) => { - const objectMetadataItems = useAtomStateValue(objectMetadataItemsState); - const { deleteFavorite } = useDeleteFavorite(); - - return ( - <> - - - - {(provided) => ( -
- {favorites.map((favorite, index) => ( - } - rightOptions={ - { - e.stopPropagation(); - deleteFavorite(favorite.id); - }} - accent="tertiary" - /> - } - triggerEvent="CLICK" - to={favorite.link} - /> - } - /> - ))} - {provided.placeholder} -
- )} -
-
- - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesFolders.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesFolders.tsx deleted file mode 100644 index 84701b4444..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesFolders.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { CurrentWorkspaceMemberFavorites } from '@/favorites/components/CurrentWorkspaceMemberFavorites'; -import { useCreateFavoriteFolder } from '@/favorites/hooks/useCreateFavoriteFolder'; -import { useFavoritesByFolder } from '@/favorites/hooks/useFavoritesByFolder'; -import { isFavoriteFolderCreatingState } from '@/favorites/states/isFavoriteFolderCreatingState'; -import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper'; -import { NavigationDrawerInput } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerInput'; -import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; -import { useState } from 'react'; -import { IconFolder } from 'twenty-ui/display'; - -export const FavoriteFolders = () => { - const [newFolderName, setNewFolderName] = useState(''); - - const { favoritesByFolder } = useFavoritesByFolder(); - const { createNewFavoriteFolder } = useCreateFavoriteFolder(); - - const [isFavoriteFolderCreating, setIsFavoriteFolderCreating] = useAtomState( - isFavoriteFolderCreatingState, - ); - - const handleFavoriteFolderNameChange = (value: string) => { - setNewFolderName(value); - }; - - const handleSubmitFavoriteFolderCreation = async (value: string) => { - if (value === '') return; - - setIsFavoriteFolderCreating(false); - setNewFolderName(''); - await createNewFavoriteFolder(value); - return true; - }; - - const handleClickOutside = async ( - _event: MouseEvent | TouchEvent, - value: string, - ) => { - if (!value) { - setIsFavoriteFolderCreating(false); - return; - } - - setIsFavoriteFolderCreating(false); - setNewFolderName(''); - await createNewFavoriteFolder(value); - }; - - const handleCancelFavoriteFolderCreation = () => { - setNewFolderName(''); - setIsFavoriteFolderCreating(false); - }; - - return ( - <> - {isFavoriteFolderCreating && ( - - - - )} - {favoritesByFolder.map((folder) => ( - 1} - /> - ))} - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx b/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx deleted file mode 100644 index aaf023afd1..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/FavoritesSkeletonLoader.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; -import { styled } from '@linaria/react'; -import { useContext } from 'react'; -import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; -import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants'; - -const StyledSkeletonContainer = styled.div` - display: flex; - flex-direction: column; - gap: ${themeCssVariables.spacing[2]}; - height: 71px; - padding-left: ${themeCssVariables.spacing[1]}; -`; - -const StyledSkeletonColumn = styled.div` - display: flex; - flex-direction: column; - gap: ${themeCssVariables.spacing[1]}; -`; - -export const FavoritesSkeletonLoader = () => { - const { theme } = useContext(ThemeContext); - return ( - - - - - - - - - - ); -}; diff --git a/packages/twenty-front/src/modules/favorites/components/PageFavoriteButton.tsx b/packages/twenty-front/src/modules/favorites/components/PageFavoriteButton.tsx deleted file mode 100644 index ec6e2319f6..0000000000 --- a/packages/twenty-front/src/modules/favorites/components/PageFavoriteButton.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { t } from '@lingui/core/macro'; -import { IconHeart, IconHeartOff } from 'twenty-ui/display'; -import { Button } from 'twenty-ui/input'; - -type PageFavoriteButtonProps = { - isFavorite: boolean; - onClick?: () => void; -}; - -export const PageFavoriteButton = ({ - isFavorite, - onClick, -}: PageFavoriteButtonProps) => { - const title = isFavorite ? t`Remove from favorites` : t`Add to favorites`; - - return ( -