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 9a550ea9d..e8fa38cbe 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 6a90b16f0..a7a061bdf 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 0e465e572..649032fe0 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 c364bb90e..9dbd2d110 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 84f9addb4..d933f2f27 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 38246cf53..5222e6156 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 3dfd6d620..ba59dc97e 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 c409cdf00..0eb803525 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 95af2de52..598279705 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 1bfb234f5..1c5046a30 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 cb46def5c..b0fac7b09 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 b6508323b..9f7c13af7 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 a3007acdc..1433c9763 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 000000000..cc19f836a --- /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 df5acd676..fe36bb119 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 af287141e..d919c7b20 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, }; };