diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditButton.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditButton.tsx index 90080ef4a7..236c4719e2 100644 --- a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditButton.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditButton.tsx @@ -1,5 +1,4 @@ import { AnimatedIconCrossfade } from 'twenty-ui/utilities'; -import { commandMenuItemEditSelectionModeState } from '@/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState'; import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState'; import { useNavigateSidePanel } from '@/side-panel/hooks/useNavigateSidePanel'; import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu'; @@ -7,14 +6,12 @@ import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedSta import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useLingui } from '@lingui/react/macro'; -import { useStore } from 'jotai'; import { SidePanelPages } from 'twenty-shared/types'; import { IconPencil, IconX } from 'twenty-ui/display'; import { AnimatedButton } from 'twenty-ui/input'; export const CommandMenuItemEditButton = () => { const { t } = useLingui(); - const store = useStore(); const { navigateSidePanel } = useNavigateSidePanel(); const { closeSidePanelMenu } = useSidePanelMenu(); @@ -38,8 +35,6 @@ export const CommandMenuItemEditButton = () => { return; } - store.set(commandMenuItemEditSelectionModeState.atom, 'selection'); - navigateSidePanel({ page: SidePanelPages.CommandMenuEdit, pageTitle: t`Edit actions`, diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditRecordSelectionDropdown.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditRecordSelectionDropdown.tsx index ec89582c90..9fac580da4 100644 --- a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditRecordSelectionDropdown.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditRecordSelectionDropdown.tsx @@ -1,12 +1,14 @@ import { COMMAND_MENU_DROPDOWN_CLICK_OUTSIDE_ID } from '@/command-menu-item/constants/CommandMenuDropdownClickOutsideId'; -import { commandMenuItemEditSelectionModeState } from '@/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState'; +import { useSelectFirstRecordForEditMode } from '@/command-menu-item/server-items/edit/hooks/useSelectFirstRecordForEditMode'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { mainContextStoreHasSelectedRecordsSelector } from '@/context-store/states/selectors/mainContextStoreHasSelectedRecordsSelector'; +import { useResetRecordIndexSelection } from '@/object-record/record-index/hooks/useResetRecordIndexSelection'; 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 { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { @@ -55,19 +57,24 @@ export const CommandMenuItemEditRecordSelectionDropdown = ({ const { t } = useLingui(); const { closeDropdown } = useCloseDropdown(); - const commandMenuItemEditSelectionMode = useAtomStateValue( - commandMenuItemEditSelectionModeState, - ); - const setCommandMenuItemEditSelectionMode = useSetAtomState( - commandMenuItemEditSelectionModeState, + const mainContextStoreHasSelectedRecords = useAtomStateValue( + mainContextStoreHasSelectedRecordsSelector, ); - const isNoneSelected = isRecordPage - ? false - : commandMenuItemEditSelectionMode === 'none'; + const { selectFirstRecordForEditMode } = useSelectFirstRecordForEditMode(); + const { resetRecordIndexSelection } = useResetRecordIndexSelection( + MAIN_CONTEXT_STORE_INSTANCE_ID, + ); + + const isNoneSelected = !mainContextStoreHasSelectedRecords; const handleSelectMode = (mode: 'none' | 'selection') => { - setCommandMenuItemEditSelectionMode(mode); + if (mode === 'selection' && isNoneSelected) { + selectFirstRecordForEditMode(); + } else if (mode === 'none') { + resetRecordIndexSelection(); + } + closeDropdown(DROPDOWN_ID); }; diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/PinnedCommandMenuItemButtonsEditMode.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/PinnedCommandMenuItemButtonsEditMode.tsx index a2428ecd5d..9942c59152 100644 --- a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/PinnedCommandMenuItemButtonsEditMode.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/PinnedCommandMenuItemButtonsEditMode.tsx @@ -1,14 +1,14 @@ -import { CommandMenuButton } from '@/command-menu/components/CommandMenuButton'; import { useCommandMenuContextApi } from '@/command-menu-item/server-items/common/hooks/useCommandMenuContextApi'; import { doesCommandMenuItemMatchObjectMetadataId } from '@/command-menu-item/server-items/common/utils/doesCommandMenuItemMatchObjectMetadataId'; import { PinnedCommandMenuItemsInlineMeasurements } from '@/command-menu-item/server-items/display/components/PinnedCommandMenuItemsInlineMeasurements'; import { PINNED_COMMAND_MENU_ITEMS_GAP } from '@/command-menu-item/server-items/display/constants/PinnedCommandMenuItemsGap'; import { usePinnedCommandMenuItemsInlineLayout } from '@/command-menu-item/server-items/display/hooks/usePinnedCommandMenuItemsInlineLayout'; -import { commandMenuItemEditSelectionModeState } from '@/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState'; +import { mainContextStoreHasSelectedRecordsSelector } from '@/context-store/states/selectors/mainContextStoreHasSelectedRecordsSelector'; import { commandMenuItemsDraftState } from '@/command-menu-item/server-items/edit/states/commandMenuItemsDraftState'; -import { CommandMenuItemScope } from '@/command-menu-item/types/CommandMenuItemScope'; import { type CommandMenuItemConfig } from '@/command-menu-item/types/CommandMenuItemConfig'; +import { CommandMenuItemScope } from '@/command-menu-item/types/CommandMenuItemScope'; import { CommandMenuItemType } from '@/command-menu-item/types/CommandMenuItemType'; +import { CommandMenuButton } from '@/command-menu/components/CommandMenuButton'; import { NodeDimension } from '@/ui/utilities/dimensions/components/NodeDimension'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants/CommandMenuDefaultIcon'; @@ -18,10 +18,7 @@ import { useContext, useMemo } from 'react'; import { interpolateCommandMenuItemLabel } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; import { ThemeContext } from 'twenty-ui/theme-constants'; -import { - CommandMenuItemAvailabilityType, - type CommandMenuItemFieldsFragment, -} from '~/generated-metadata/graphql'; +import { CommandMenuItemAvailabilityType } from '~/generated-metadata/graphql'; const StyledActionContainer = styled(motion.div)` align-items: center; @@ -59,19 +56,20 @@ export const PinnedCommandMenuItemButtonsEditMode = () => { const commandMenuItemsDraft = useAtomStateValue(commandMenuItemsDraftState) ?? []; - const commandMenuItemEditSelectionMode = useAtomStateValue( - commandMenuItemEditSelectionModeState, + + const mainContextStoreHasSelectedRecords = useAtomStateValue( + mainContextStoreHasSelectedRecordsSelector, ); const allowedAvailabilityTypes = useMemo( () => new Set([ CommandMenuItemAvailabilityType.GLOBAL, - commandMenuItemEditSelectionMode === 'selection' + mainContextStoreHasSelectedRecords ? CommandMenuItemAvailabilityType.RECORD_SELECTION : CommandMenuItemAvailabilityType.FALLBACK, ]), - [commandMenuItemEditSelectionMode], + [mainContextStoreHasSelectedRecords], ); const interpolateLabel = (rawLabel: string | null | undefined) => @@ -114,7 +112,6 @@ export const PinnedCommandMenuItemButtonsEditMode = () => { }), // eslint-disable-next-line react-hooks/exhaustive-deps [ - commandMenuItemsDraft, currentObjectMetadataItemId, allowedAvailabilityTypes, commandMenuContextApi, diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx index 5d01b8e0b5..7bc6bce0f3 100644 --- a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/SidePanelCommandMenuItemEditPage.tsx @@ -1,16 +1,13 @@ import { useCommandMenuContextApi } from '@/command-menu-item/server-items/common/hooks/useCommandMenuContextApi'; import { commandMenuItemsSelector } from '@/command-menu-item/server-items/common/states/commandMenuItemsSelector'; import { doesCommandMenuItemMatchObjectMetadataId } from '@/command-menu-item/server-items/common/utils/doesCommandMenuItemMatchObjectMetadataId'; -import { commandMenuItemsDraftState } from '@/command-menu-item/server-items/edit/states/commandMenuItemsDraftState'; import { CommandMenuItemEditRecordSelectionDropdown } from '@/command-menu-item/server-items/edit/components/CommandMenuItemEditRecordSelectionDropdown'; import { CommandMenuItemOptionsDropdown } from '@/command-menu-item/server-items/edit/components/CommandMenuItemOptionsDropdown'; import { useReorderCommandMenuItemsInDraft } from '@/command-menu-item/server-items/edit/hooks/useReorderCommandMenuItemsInDraft'; import { useResetCommandMenuItemsDraft } from '@/command-menu-item/server-items/edit/hooks/useResetCommandMenuItemsDraft'; -import { - type CommandMenuItemEditSelectionMode, - commandMenuItemEditSelectionModeState, -} from '@/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState'; import { useUpdateCommandMenuItemInDraft } from '@/command-menu-item/server-items/edit/hooks/useUpdateCommandMenuItemInDraft'; +import { commandMenuItemsDraftState } from '@/command-menu-item/server-items/edit/states/commandMenuItemsDraftState'; +import { mainContextStoreHasSelectedRecordsSelector } from '@/context-store/states/selectors/mainContextStoreHasSelectedRecordsSelector'; import { COMMAND_MENU_CLICK_OUTSIDE_ID } from '@/command-menu/constants/CommandMenuClickOutsideId'; import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { SidePanelList } from '@/side-panel/components/SidePanelList'; @@ -88,14 +85,10 @@ export const SidePanelCommandMenuItemEditPage = () => { commandMenuContextApi.pageType === CommandMenuContextApiPageType.RECORD_PAGE; - const commandMenuItemEditSelectionMode = useAtomStateValue( - commandMenuItemEditSelectionModeState, + const mainContextStoreHasSelectedRecords = useAtomStateValue( + mainContextStoreHasSelectedRecordsSelector, ); - const effectiveSelectionMode: CommandMenuItemEditSelectionMode = isRecordPage - ? 'selection' - : commandMenuItemEditSelectionMode; - const sidePanelSearch = useAtomStateValue(sidePanelSearchState); const commandMenuItems = useAtomStateValue(commandMenuItemsSelector); @@ -110,7 +103,7 @@ export const SidePanelCommandMenuItemEditPage = () => { const allowedAvailabilityTypes = new Set([ CommandMenuItemAvailabilityType.GLOBAL, - effectiveSelectionMode === 'selection' + mainContextStoreHasSelectedRecords ? CommandMenuItemAvailabilityType.RECORD_SELECTION : CommandMenuItemAvailabilityType.FALLBACK, ]); diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useSelectFirstRecordForEditMode.ts b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useSelectFirstRecordForEditMode.ts new file mode 100644 index 0000000000..7a65f304b4 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/hooks/useSelectFirstRecordForEditMode.ts @@ -0,0 +1,67 @@ +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { getRecordIndexId } from '@/command-menu-item/server-items/edit/utils/getRecordIndexId'; +import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; +import { useResetRecordIndexSelection } from '@/object-record/record-index/hooks/useResetRecordIndexSelection'; +import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; +import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; +import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; +import { ViewType } from '@/views/types/ViewType'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; +import { isDefined } from 'twenty-shared/utils'; + +export const useSelectFirstRecordForEditMode = () => { + const store = useStore(); + const { resetRecordIndexSelection } = useResetRecordIndexSelection( + MAIN_CONTEXT_STORE_INSTANCE_ID, + ); + + const selectFirstRecordForEditMode = useCallback(() => { + const recordIndexId = getRecordIndexId(store); + + if (!isDefined(recordIndexId)) { + return; + } + + resetRecordIndexSelection(); + + const allRecordIds = store.get( + recordIndexAllRecordIdsComponentSelector.selectorFamily({ + instanceId: recordIndexId, + }), + ); + + const firstRecordId = allRecordIds[0]; + + if (!isDefined(firstRecordId)) { + return; + } + + const viewType = store.get(recordIndexViewTypeState.atom); + + switch (viewType) { + case ViewType.TABLE: { + store.set( + isRowSelectedComponentFamilyState.atomFamily({ + instanceId: recordIndexId, + familyKey: firstRecordId, + }), + true, + ); + break; + } + case ViewType.KANBAN: { + store.set( + isRecordBoardCardSelectedComponentFamilyState.atomFamily({ + instanceId: recordIndexId, + familyKey: firstRecordId, + }), + true, + ); + break; + } + } + }, [store, resetRecordIndexSelection]); + + return { selectFirstRecordForEditMode }; +}; diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState.ts b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState.ts deleted file mode 100644 index 5ee29846bc..0000000000 --- a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState'; - -export type CommandMenuItemEditSelectionMode = 'none' | 'selection'; - -export const commandMenuItemEditSelectionModeState = - createAtomState({ - key: 'commandMenuItemEditSelectionModeState', - defaultValue: 'selection', - }); diff --git a/packages/twenty-front/src/modules/command-menu-item/server-items/edit/utils/getRecordIndexId.ts b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/utils/getRecordIndexId.ts new file mode 100644 index 0000000000..1299342829 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu-item/server-items/edit/utils/getRecordIndexId.ts @@ -0,0 +1,42 @@ +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; +import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; +import type { useStore } from 'jotai'; +import { isDefined } from 'twenty-shared/utils'; + +export const getRecordIndexId = ( + store: ReturnType, +): string | null => { + const objectMetadataItemId = store.get( + contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + ); + + const viewId = store.get( + contextStoreCurrentViewIdComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + ); + + if (!isDefined(objectMetadataItemId) || !isDefined(viewId)) { + return null; + } + + const objectMetadataItems = store.get(objectMetadataItemsSelector.atom); + + const objectMetadataItem = objectMetadataItems.find( + (item) => item.id === objectMetadataItemId, + ); + + if (!isDefined(objectMetadataItem)) { + return null; + } + + return getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + viewId, + ); +}; diff --git a/packages/twenty-front/src/modules/context-store/states/selectors/mainContextStoreHasSelectedRecordsSelector.ts b/packages/twenty-front/src/modules/context-store/states/selectors/mainContextStoreHasSelectedRecordsSelector.ts new file mode 100644 index 0000000000..1819d9bde2 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/selectors/mainContextStoreHasSelectedRecordsSelector.ts @@ -0,0 +1,16 @@ +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector'; + +export const mainContextStoreHasSelectedRecordsSelector = + createAtomSelector({ + key: 'mainContextStoreHasSelectedRecordsSelector', + get: ({ get }) => { + const numberOfSelectedRecords = get( + contextStoreNumberOfSelectedRecordsComponentState, + { instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }, + ); + + return numberOfSelectedRecords > 0; + }, + }); diff --git a/packages/twenty-front/src/modules/layout-customization/hooks/useEnterLayoutCustomizationMode.ts b/packages/twenty-front/src/modules/layout-customization/hooks/useEnterLayoutCustomizationMode.ts index 43565809f7..b412d36ed0 100644 --- a/packages/twenty-front/src/modules/layout-customization/hooks/useEnterLayoutCustomizationMode.ts +++ b/packages/twenty-front/src/modules/layout-customization/hooks/useEnterLayoutCustomizationMode.ts @@ -4,7 +4,6 @@ import { useCallback } from 'react'; import { SidePanelPages } from 'twenty-shared/types'; import { IconPencil } from 'twenty-ui/display'; -import { commandMenuItemEditSelectionModeState } from '@/command-menu-item/server-items/edit/states/commandMenuItemEditSelectionModeState'; import { commandMenuItemsDraftState } from '@/command-menu-item/server-items/edit/states/commandMenuItemsDraftState'; import { commandMenuItemsSelector } from '@/command-menu-item/server-items/common/states/commandMenuItemsSelector'; import { activeCustomizationPageLayoutIdsState } from '@/layout-customization/states/activeCustomizationPageLayoutIdsState'; @@ -51,8 +50,6 @@ export const useEnterLayoutCustomizationMode = () => { isSidePanelOpened && currentSidePanelPage === SidePanelPages.CommandMenuDisplay ) { - store.set(commandMenuItemEditSelectionModeState.atom, 'selection'); - navigateSidePanel({ page: SidePanelPages.CommandMenuEdit, pageTitle: t`Edit actions`, diff --git a/packages/twenty-front/src/modules/layout-customization/hooks/useExitLayoutCustomizationMode.ts b/packages/twenty-front/src/modules/layout-customization/hooks/useExitLayoutCustomizationMode.ts index 60076e728c..adc969ddda 100644 --- a/packages/twenty-front/src/modules/layout-customization/hooks/useExitLayoutCustomizationMode.ts +++ b/packages/twenty-front/src/modules/layout-customization/hooks/useExitLayoutCustomizationMode.ts @@ -1,5 +1,7 @@ import { commandMenuItemsDraftState } from '@/command-menu-item/server-items/edit/states/commandMenuItemsDraftState'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState'; +import { useResetRecordIndexSelection } from '@/object-record/record-index/hooks/useResetRecordIndexSelection'; import { navigationMenuItemsDraftState } from '@/navigation-menu-item/common/states/navigationMenuItemsDraftState'; import { selectedNavigationMenuItemIdInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemIdInEditModeState'; import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu'; @@ -11,6 +13,9 @@ export const useExitLayoutCustomizationMode = () => { const store = useStore(); const { closeSidePanelMenu } = useSidePanelMenu(); + const { resetRecordIndexSelection } = useResetRecordIndexSelection( + MAIN_CONTEXT_STORE_INSTANCE_ID, + ); const setNavigationMenuItemsDraft = useSetAtomState( navigationMenuItemsDraftState, @@ -23,12 +28,14 @@ export const useExitLayoutCustomizationMode = () => { ); const exitLayoutCustomizationMode = useCallback(() => { + resetRecordIndexSelection(); setNavigationMenuItemsDraft(null); setSelectedNavigationMenuItemIdInEditMode(null); store.set(commandMenuItemsDraftState.atom, null); setIsLayoutCustomizationModeEnabled(false); closeSidePanelMenu(); }, [ + resetRecordIndexSelection, setNavigationMenuItemsDraft, setSelectedNavigationMenuItemIdInEditMode, setIsLayoutCustomizationModeEnabled, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useResetRecordIndexSelection.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useResetRecordIndexSelection.ts new file mode 100644 index 0000000000..136916dc85 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useResetRecordIndexSelection.ts @@ -0,0 +1,77 @@ +import { useContextStoreObjectMetadataItem } from '@/context-store/hooks/useContextStoreObjectMetadataItem'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; +import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; +import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; +import { useResetRecordBoardSelection } from '@/object-record/record-board/hooks/useResetRecordBoardSelection'; +import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; +import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState'; +import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; +import { useStore } from 'jotai'; +import { useCallback } from 'react'; +import { isDefined } from 'twenty-shared/utils'; + +const PLACEHOLDER_RECORD_INDEX_ID = 'placeholder-record-index-id'; + +export const useResetRecordIndexSelection = ( + contextStoreInstanceId?: string, +) => { + const store = useStore(); + + const { objectMetadataItem } = useContextStoreObjectMetadataItem( + contextStoreInstanceId, + ); + + const contextStoreCurrentViewId = useAtomComponentStateValue( + contextStoreCurrentViewIdComponentState, + contextStoreInstanceId, + ); + + const contextStoreCurrentViewTypeAtom = useAtomComponentStateCallbackState( + contextStoreCurrentViewTypeComponentState, + contextStoreInstanceId, + ); + + const objectNamePlural = objectMetadataItem?.namePlural; + + const hasValidContext = isDefined(objectNamePlural); + + const recordIndexId = hasValidContext + ? getRecordIndexIdFromObjectNamePluralAndViewId( + objectNamePlural, + contextStoreCurrentViewId ?? '', + ) + : PLACEHOLDER_RECORD_INDEX_ID; + + const { resetTableRowSelection } = useResetTableRowSelection(recordIndexId); + + const { resetRecordBoardSelection } = + useResetRecordBoardSelection(recordIndexId); + + const resetRecordIndexSelection = useCallback(() => { + if (!hasValidContext) { + return; + } + + const contextStoreCurrentViewType = store.get( + contextStoreCurrentViewTypeAtom, + ); + + switch (contextStoreCurrentViewType) { + case ContextStoreViewType.Table: + resetTableRowSelection(); + break; + case ContextStoreViewType.Kanban: + resetRecordBoardSelection(); + break; + } + }, [ + hasValidContext, + store, + contextStoreCurrentViewTypeAtom, + resetTableRowSelection, + resetRecordBoardSelection, + ]); + + return { resetRecordIndexSelection }; +}; diff --git a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelMenu.ts b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelMenu.ts index 4a6ff8f544..f4c0b4a81d 100644 --- a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelMenu.ts +++ b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelMenu.ts @@ -1,4 +1,6 @@ +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState'; +import { useResetRecordIndexSelection } from '@/object-record/record-index/hooks/useResetRecordIndexSelection'; import { selectedNavigationMenuItemIdInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemIdInEditModeState'; import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; import { useNavigateSidePanel } from '@/side-panel/hooks/useNavigateSidePanel'; @@ -21,6 +23,9 @@ export const useSidePanelMenu = () => { const store = useStore(); const { navigateSidePanel } = useNavigateSidePanel(); const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown(); + const { resetRecordIndexSelection } = useResetRecordIndexSelection( + MAIN_CONTEXT_STORE_INSTANCE_ID, + ); const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); @@ -29,6 +34,14 @@ export const useSidePanelMenu = () => { const isSidePanelOpened = store.get(isSidePanelOpenedState.atom); if (isSidePanelOpened) { + const isLayoutCustomizationModeEnabled = store.get( + isLayoutCustomizationModeEnabledState.atom, + ); + + if (isLayoutCustomizationModeEnabled) { + resetRecordIndexSelection(); + } + store.set(sidePanelNavigationStackState.atom, []); store.set(isSidePanelOpenedState.atom, false); store.set(isSidePanelClosingState.atom, true); @@ -37,7 +50,12 @@ export const useSidePanelMenu = () => { focusId: SIDE_PANEL_FOCUS_ID, }); } - }, [closeAnyOpenDropdown, removeFocusItemFromFocusStackById, store]); + }, [ + closeAnyOpenDropdown, + removeFocusItemFromFocusStackById, + store, + resetRecordIndexSelection, + ]); const openSidePanelMenu = useCallback(() => { emitSidePanelOpenEvent(); @@ -45,6 +63,7 @@ export const useSidePanelMenu = () => { const isLayoutCustomizationModeEnabled = store.get( isLayoutCustomizationModeEnabledState.atom, ); + const selectedNavigationItemId = store.get( selectedNavigationMenuItemIdInEditModeState.atom, );