From 17e2e38812021a67300b08321e384ec3a938010a Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Thu, 9 Jan 2025 18:54:34 +0100 Subject: [PATCH] Refactored select filter and select filter definition logic (#9519) This PR extracts the logic to manage filter and filter definition setting. Previously it was ambiguous, we had the same "selectFilter" naming used for setting filter definition in filter dropdown and for setting the actual filter value and saving to view filter states. This is another incremental refactor, which will allow to remove useFilterDropdown hook. --- .../ObjectFilterDropdownBooleanSelect.tsx | 6 ++- .../ObjectFilterDropdownDateInput.tsx | 8 ++-- .../ObjectFilterDropdownFilterSelect.tsx | 11 +++-- ...pdownFilterSelectCompositeFieldSubMenu.tsx | 7 ++- ...jectFilterDropdownFilterSelectMenuItem.tsx | 26 +++++----- .../ObjectFilterDropdownNumberInput.tsx | 9 +++- .../ObjectFilterDropdownOperandSelect.tsx | 8 ++-- .../ObjectFilterDropdownOptionSelect.tsx | 6 ++- .../ObjectFilterDropdownRatingInput.tsx | 6 ++- .../ObjectFilterDropdownRecordSelect.tsx | 6 ++- .../ObjectFilterDropdownSourceSelect.tsx | 6 ++- .../ObjectFilterDropdownTextSearchInput.tsx | 6 ++- .../__tests__/useFilterDropdown.test.tsx | 21 +++++--- .../hooks/useApplyRecordFilter.ts | 48 +++++++++++++++++++ .../hooks/useFilterDropdown.ts | 22 --------- ...seSelectFilterDefinitionUsedInDropdown.ts} | 14 ++++-- 16 files changed, 138 insertions(+), 72 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyRecordFilter.ts rename packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/{useSelectFilter.ts => useSelectFilterDefinitionUsedInDropdown.ts} (85%) diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx index 9a550ea9d55..e8fa38cbedf 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { BooleanDisplay } from '@/ui/field/display/components/BooleanDisplay'; @@ -40,9 +41,10 @@ export const ObjectFilterDropdownBooleanSelect = () => { filterDefinitionUsedInDropdownState, selectedOperandInDropdownState, selectedFilterState, - selectFilter, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(); + const { closeDropdown } = useDropdown(); const filterDefinitionUsedInDropdown = useRecoilValue( @@ -69,7 +71,7 @@ export const ObjectFilterDropdownBooleanSelect = () => { return; } - selectFilter({ + applyRecordFilter({ id: selectedFilter?.id ?? v4(), definition: filterDefinitionUsedInDropdown, operand: selectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index 6a90b16f0ce..a7a061bdfb5 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -1,6 +1,7 @@ import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue'; @@ -21,9 +22,10 @@ export const ObjectFilterDropdownDateInput = () => { filterDefinitionUsedInDropdownState, selectedOperandInDropdownState, selectedFilterState, - selectFilter, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(); + const filterDefinitionUsedInDropdown = useRecoilValue( filterDefinitionUsedInDropdownState, ); @@ -51,7 +53,7 @@ export const ObjectFilterDropdownDateInput = () => { if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; - selectFilter?.({ + applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: newDate?.toISOString() ?? '', @@ -83,7 +85,7 @@ export const ObjectFilterDropdownDateInput = () => { ) : ''; - selectFilter?.({ + applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx index 0e465e57220..649032fe0b2 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx @@ -7,7 +7,7 @@ import { AdvancedFilterButton } from '@/object-record/object-filter-dropdown/com import { ObjectFilterDropdownFilterSelectMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem'; import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; -import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter'; +import { useSelectFilterDefinitionUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown'; import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector'; @@ -121,7 +121,8 @@ export const ObjectFilterDropdownFilterSelect = ({ (item) => item.fieldMetadataId, ); - const { selectFilter } = useSelectFilter(); + const { selectFilterDefinitionUsedInDropdown } = + useSelectFilterDefinitionUsedInDropdown(); const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID); @@ -135,7 +136,11 @@ export const ObjectFilterDropdownFilterSelect = ({ } resetSelectedItem(); - selectFilter({ filterDefinition: selectedFilterDefinition }); + + selectFilterDefinitionUsedInDropdown({ + filterDefinition: selectedFilterDefinition, + }); + closeAdvancedFilterDropdown(); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx index c364bb90eb6..9dbd2d110db 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx @@ -1,4 +1,5 @@ import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState'; @@ -55,11 +56,12 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => { setFilterDefinitionUsedInDropdown, setSelectedOperandInDropdown, setObjectFilterDropdownSearchInput, - selectFilter, advancedFilterViewFilterIdState, advancedFilterViewFilterGroupIdState, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(); + const advancedFilterViewFilterId = useRecoilValue( advancedFilterViewFilterIdState, ); @@ -84,7 +86,8 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => { definition.type, operand, ); - selectFilter({ + + applyRecordFilter({ id: advancedFilterViewFilterId, fieldMetadataId: definition.fieldMetadataId, value, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx index 84f9addb447..d933f2f2730 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx @@ -1,7 +1,7 @@ import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown'; import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; -import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter'; +import { useSelectFilterDefinitionUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState'; import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; @@ -25,7 +25,8 @@ export type ObjectFilterDropdownFilterSelectMenuItemProps = { export const ObjectFilterDropdownFilterSelectMenuItem = ({ filterDefinition, }: ObjectFilterDropdownFilterSelectMenuItemProps) => { - const { selectFilter } = useSelectFilter(); + const { selectFilterDefinitionUsedInDropdown } = + useSelectFilterDefinitionUsedInDropdown(); const [, setObjectFilterDropdownFirstLevelFilterDefinition] = useRecoilComponentStateV2( @@ -55,12 +56,8 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({ const isACompositeField = isCompositeField(filterDefinition.type); - const { - setFilterDefinitionUsedInDropdown, - setSelectedOperandInDropdown, - setObjectFilterDropdownSearchInput, - advancedFilterViewFilterIdState, - } = useFilterDropdown(); + const { setSelectedOperandInDropdown, advancedFilterViewFilterIdState } = + useFilterDropdown(); const setHotkeyScope = useSetHotkeyScope(); @@ -72,11 +69,14 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({ advancedFilterViewFilterId, ); - const handleSelectFilter = (availableFilterDefinition: FilterDefinition) => { + const handleSelectFilterDefinition = ( + availableFilterDefinition: FilterDefinition, + ) => { closeAdvancedFilterDropdown(); - selectFilter({ filterDefinition: availableFilterDefinition }); - setFilterDefinitionUsedInDropdown(availableFilterDefinition); + selectFilterDefinitionUsedInDropdown({ + filterDefinition: availableFilterDefinition, + }); if ( availableFilterDefinition.type === 'RELATION' || @@ -89,8 +89,6 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({ getOperandsForFilterDefinition(availableFilterDefinition)[0], ); - setObjectFilterDropdownSearchInput(''); - setObjectFilterDropdownFilterIsSelected(true); }; @@ -107,7 +105,7 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({ setObjectFilterDropdownFirstLevelFilterDefinition(filterDefinition); setObjectFilterDropdownIsSelectingCompositeField(true); } else { - handleSelectFilter(filterDefinition); + handleSelectFilterDefinition(filterDefinition); } }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx index 38246cf53df..5222e615699 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx @@ -2,6 +2,7 @@ import { ChangeEvent, useCallback, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; @@ -10,8 +11,10 @@ export const ObjectFilterDropdownNumberInput = () => { selectedOperandInDropdownState, filterDefinitionUsedInDropdownState, selectedFilterState, - selectFilter, } = useFilterDropdown(); + + const { applyRecordFilter } = useApplyRecordFilter(); + const [hasFocused, setHasFocused] = useState(false); const filterDefinitionUsedInDropdown = useRecoilValue( @@ -48,8 +51,10 @@ export const ObjectFilterDropdownNumberInput = () => { placeholder={filterDefinitionUsedInDropdown.label} onChange={(event: ChangeEvent) => { const newValue = event.target.value; + setInputValue(newValue); - selectFilter?.({ + + applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: newValue, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx index 3dfd6d6203e..ba59dc97ea2 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx @@ -1,6 +1,7 @@ import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -22,9 +23,10 @@ export const ObjectFilterDropdownOperandSelect = () => { filterDefinitionUsedInDropdownState, setSelectedOperandInDropdown, selectedFilterState, - selectFilter, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(); + const { closeDropdown } = useDropdown(); const filterDefinitionUsedInDropdown = useRecoilValue( @@ -49,7 +51,7 @@ export const ObjectFilterDropdownOperandSelect = () => { setSelectedOperandInDropdown(newOperand); if (isValuelessOperand && isDefined(filterDefinitionUsedInDropdown)) { - selectFilter?.({ + applyRecordFilter({ id: v4(), fieldMetadataId: filterDefinitionUsedInDropdown?.fieldMetadataId ?? '', displayValue: '', @@ -71,7 +73,7 @@ export const ObjectFilterDropdownOperandSelect = () => { selectedFilter.displayValue, ); - selectFilter?.({ + applyRecordFilter({ id: selectedFilter.id ? selectedFilter.id : v4(), fieldMetadataId: selectedFilter.fieldMetadataId, displayValue, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx index c409cdf0063..0eb8035254c 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx @@ -14,6 +14,7 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { MenuItem, MenuItemMultiSelect } from 'twenty-ui'; import { isDefined } from '~/utils/isDefined'; @@ -32,9 +33,10 @@ export const ObjectFilterDropdownOptionSelect = () => { selectedOperandInDropdownState, objectFilterDropdownSelectedOptionValuesState, selectedFilterState, - selectFilter, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(); + const { closeDropdown } = useDropdown(); const { selectedItemIdState } = useSelectableListStates({ @@ -128,7 +130,7 @@ export const ObjectFilterDropdownOptionSelect = () => { ? JSON.stringify(selectedOptions.map((option) => option.value)) : EMPTY_FILTER_VALUE; - selectFilter({ + applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : v4(), definition: filterDefinitionUsedInDropdown, operand: selectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx index 95af2de52e4..5982797053c 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx @@ -1,6 +1,7 @@ import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues'; import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata'; @@ -34,7 +35,6 @@ export const ObjectFilterDropdownRatingInput = () => { selectedOperandInDropdownState, filterDefinitionUsedInDropdownState, selectedFilterState, - selectFilter, } = useFilterDropdown(); const filterDefinitionUsedInDropdown = useRecoilValue( @@ -46,6 +46,8 @@ export const ObjectFilterDropdownRatingInput = () => { const selectedFilter = useRecoilValue(selectedFilterState); + const { applyRecordFilter } = useApplyRecordFilter(); + return ( filterDefinitionUsedInDropdown && selectedOperandInDropdown && ( @@ -57,7 +59,7 @@ export const ObjectFilterDropdownRatingInput = () => { return; } - selectFilter?.({ + applyRecordFilter?.({ id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: convertFieldRatingValueToNumber(newValue), diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 1bfb234f593..1c5046a30e9 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -5,6 +5,7 @@ import { v4 } from 'uuid'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectFilterDropdownRecordPinnedItems } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordPinnedItems'; import { CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID } from '@/object-record/object-filter-dropdown/constants/CurrentWorkspaceMemberSelectableItemId'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown'; @@ -37,9 +38,10 @@ export const ObjectFilterDropdownRecordSelect = ({ selectedOperandInDropdownState, selectedFilterState, objectFilterDropdownSelectedRecordIdsState, - selectFilter, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(viewComponentId); + const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(viewComponentId); @@ -187,7 +189,7 @@ export const ObjectFilterDropdownRecordSelect = ({ const filterId = viewFilter?.id ?? fieldId; - selectFilter({ + applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : filterId, definition: filterDefinitionUsedInDropdown, operand: selectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx index cb46def5c76..b0fac7b0949 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { getActorSourceMultiSelectOptions } from '@/object-record/object-filter-dropdown/utils/getActorSourceMultiSelectOptions'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; @@ -29,10 +30,11 @@ export const ObjectFilterDropdownSourceSelect = ({ selectedFilterState, setObjectFilterDropdownSelectedRecordIds, objectFilterDropdownSelectedRecordIdsState, - selectFilter, emptyFilterButKeepDefinition, } = useFilterDropdown(); + const { applyRecordFilter } = useApplyRecordFilter(viewComponentId); + const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters(viewComponentId); @@ -108,7 +110,7 @@ export const ObjectFilterDropdownSourceSelect = ({ const filterId = viewFilter?.id ?? fieldId; - selectFilter({ + applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : filterId, definition: filterDefinitionUsedInDropdown, operand: selectedOperandInDropdown || ViewFilterOperand.Is, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx index b6508323bbe..9f7c13af76e 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx @@ -2,6 +2,7 @@ import { ChangeEvent, useCallback, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { v4 } from 'uuid'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; @@ -12,7 +13,6 @@ export const ObjectFilterDropdownTextSearchInput = () => { objectFilterDropdownSearchInputState, setObjectFilterDropdownSearchInput, selectedFilterState, - selectFilter, } = useFilterDropdown(); const [filterId] = useState(v4()); @@ -29,6 +29,8 @@ export const ObjectFilterDropdownTextSearchInput = () => { ); const selectedFilter = useRecoilValue(selectedFilterState); + const { applyRecordFilter } = useApplyRecordFilter(); + const handleInputRef = useCallback( (node: HTMLInputElement | null) => { if (Boolean(node) && !hasFocused) { @@ -51,7 +53,7 @@ export const ObjectFilterDropdownTextSearchInput = () => { onChange={(event: ChangeEvent) => { setObjectFilterDropdownSearchInput(event.target.value); - selectFilter?.({ + applyRecordFilter({ id: selectedFilter?.id ?? filterId, fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: event.target.value, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx index a3007acdccc..1433c976311 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/__tests__/useFilterDropdown.test.tsx @@ -2,6 +2,7 @@ import { expect } from '@storybook/test'; import { act, renderHook, waitFor } from '@testing-library/react'; import { RecoilRoot, useRecoilState } from 'recoil'; +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { useFilterDropdownStates } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownStates'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; @@ -261,19 +262,26 @@ describe('useFilterDropdown', () => { it('should reset filter', async () => { const { result } = renderHook(() => { - const { resetFilter, selectFilter } = useFilterDropdown({ + const { resetFilter } = useFilterDropdown({ filterDropdownId, }); + const { applyRecordFilter } = useApplyRecordFilter(filterDropdownId); + const { selectedFilterState } = useFilterDropdownStates(filterDropdownId); const [selectedFilter, setSelectedFilter] = useRecoilState(selectedFilterState); - return { selectedFilter, setSelectedFilter, selectFilter, resetFilter }; + return { + selectedFilter, + setSelectedFilter, + applyRecordFilter, + resetFilter, + }; }, renderHookConfig); act(() => { - result.current.selectFilter(mockFilter); + result.current.applyRecordFilter(mockFilter); }); await waitFor(() => { @@ -291,12 +299,13 @@ describe('useFilterDropdown', () => { it('should call onFilterSelect when a filter option is set', async () => { const { result } = renderHook(() => { - const { selectFilter } = useFilterDropdown({ filterDropdownId }); + const { applyRecordFilter } = useApplyRecordFilter(filterDropdownId); + const { onFilterSelectState } = useFilterDropdownStates(filterDropdownId); const [onFilterSelect, setOnFilterSelect] = useRecoilState(onFilterSelectState); - return { onFilterSelect, setOnFilterSelect, selectFilter }; + return { onFilterSelect, setOnFilterSelect, applyRecordFilter }; }, renderHookConfig); const onFilterSelectMock = jest.fn(); @@ -304,7 +313,7 @@ describe('useFilterDropdown', () => { act(() => { result.current.setOnFilterSelect(onFilterSelectMock); - result.current.selectFilter(mockFilter); + result.current.applyRecordFilter(mockFilter); }); await waitFor(() => { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyRecordFilter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyRecordFilter.ts new file mode 100644 index 00000000000..cc19f836a5c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyRecordFilter.ts @@ -0,0 +1,48 @@ +import { onFilterSelectComponentState } from '@/object-record/object-filter-dropdown/states/onFilterSelectComponentState'; +import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; +import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; +import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; +import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-ui'; + +export const useApplyRecordFilter = (componentInstanceId?: string) => { + const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters(); + const selectedFilterCallbackState = useRecoilComponentCallbackStateV2( + selectedFilterComponentState, + componentInstanceId, + ); + + const onFilterSelectCallbackState = useRecoilComponentCallbackStateV2( + onFilterSelectComponentState, + componentInstanceId, + ); + + const applyRecordFilter = useRecoilCallback( + ({ set, snapshot }) => + (filter: Filter | null) => { + set(selectedFilterCallbackState, filter); + + const onFilterSelect = getSnapshotValue( + snapshot, + onFilterSelectCallbackState, + ); + + if (isDefined(filter)) { + upsertCombinedViewFilter(filter); + } + + onFilterSelect?.(filter); + }, + [ + selectedFilterCallbackState, + onFilterSelectCallbackState, + upsertCombinedViewFilter, + ], + ); + + return { + applyRecordFilter, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts index df5acd6765a..fe36bb1191b 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useFilterDropdown.ts @@ -1,16 +1,12 @@ import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { useFilterDropdownStates } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownStates'; -import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; -import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters'; -import { isDefined } from 'twenty-ui'; -import { Filter } from '../types/Filter'; type UseFilterDropdownProps = { filterDropdownId?: string; @@ -34,23 +30,6 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => { advancedFilterViewFilterIdState, } = useFilterDropdownStates(componentInstanceId); - const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters(); - - const selectFilter = useRecoilCallback( - ({ set, snapshot }) => - (filter: Filter | null) => { - set(selectedFilterState, filter); - const onFilterSelect = getSnapshotValue(snapshot, onFilterSelectState); - - if (isDefined(filter)) { - upsertCombinedViewFilter(filter); - } - - onFilterSelect?.(filter); - }, - [selectedFilterState, onFilterSelectState, upsertCombinedViewFilter], - ); - const emptyFilterButKeepDefinition = useRecoilCallback( ({ set }) => () => { @@ -129,7 +108,6 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => { return { componentInstanceId, - selectFilter, resetFilter, setSelectedFilter, setSelectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts similarity index 85% rename from packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilter.ts rename to packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts index af287141ea3..d919c7b2036 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilter.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts @@ -1,3 +1,4 @@ +import { useApplyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useApplyRecordFilter'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue'; @@ -12,12 +13,11 @@ type SelectFilterParams = { filterDefinition: FilterDefinition; }; -export const useSelectFilter = () => { +export const useSelectFilterDefinitionUsedInDropdown = () => { const { setFilterDefinitionUsedInDropdown, setSelectedOperandInDropdown, setObjectFilterDropdownSearchInput, - selectFilter: filterDropdownSelectFilter, advancedFilterViewFilterGroupIdState, advancedFilterViewFilterIdState, } = useFilterDropdown(); @@ -31,7 +31,11 @@ export const useSelectFilter = () => { const setHotkeyScope = useSetHotkeyScope(); - const selectFilter = ({ filterDefinition }: SelectFilterParams) => { + const { applyRecordFilter } = useApplyRecordFilter(); + + const selectFilterDefinitionUsedInDropdown = ({ + filterDefinition, + }: SelectFilterParams) => { setFilterDefinitionUsedInDropdown(filterDefinition); if ( @@ -53,7 +57,7 @@ export const useSelectFilter = () => { const isAdvancedFilter = isDefined(advancedFilterViewFilterId); if (isAdvancedFilter || value !== '') { - filterDropdownSelectFilter({ + applyRecordFilter({ id: advancedFilterViewFilterId ?? v4(), fieldMetadataId: filterDefinition.fieldMetadataId, displayValue, @@ -68,6 +72,6 @@ export const useSelectFilter = () => { }; return { - selectFilter, + selectFilterDefinitionUsedInDropdown, }; };