@@ -15,7 +15,6 @@ import type {PopoverComponentProps} from '@components/Search/FilterDropdowns/Dro
1515import DropdownButton from '@components/Search/FilterDropdowns/DropdownButton' ;
1616import type { MultiSelectItem } from '@components/Search/FilterDropdowns/MultiSelectPopup' ;
1717import MultiSelectPopup from '@components/Search/FilterDropdowns/MultiSelectPopup' ;
18- import type { SingleSelectItem } from '@components/Search/FilterDropdowns/SingleSelectPopup' ;
1918import SingleSelectPopup from '@components/Search/FilterDropdowns/SingleSelectPopup' ;
2019import UserSelectPopup from '@components/Search/FilterDropdowns/UserSelectPopup' ;
2120import { useSearchContext } from '@components/Search/SearchContext' ;
@@ -36,7 +35,7 @@ import {getStatusOptions, getTypeOptions} from '@libs/SearchUIUtils';
3635import CONST from '@src/CONST' ;
3736import ONYXKEYS from '@src/ONYXKEYS' ;
3837import ROUTES from '@src/ROUTES' ;
39- import type { SearchDataTypes } from '@src/types/onyx/SearchResults ' ;
38+ import type { SearchAdvancedFiltersForm } from '@src/types/form ' ;
4039import type { SearchHeaderOptionValue } from './SearchPageHeader' ;
4140
4241type SearchFiltersBarProps = {
@@ -81,45 +80,47 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions}: SearchFiltersBarPro
8180 return buildFilterFormValuesFromQuery ( queryJSON , policyCategories , policyTagsLists , currencyList , personalDetails , allCards , reports , taxRates ) ;
8281 } , [ allCards , currencyList , personalDetails , policyCategories , policyTagsLists , queryJSON , reports , taxRates ] ) ;
8382
84- // We need to create a stable key for filterFormValues so that we don't infinitely
85- // re-render components that access all of the filterFormValues. This is due to the way
86- // that react calculates diffs (it doesn't know how to compare objects).
87- const filterFormValuesKey = JSON . stringify ( filterFormValues ) ;
83+ const updateFilterForm = useCallback (
84+ ( values : Partial < SearchAdvancedFiltersForm > ) => {
85+ const updatedFilterFormValues : Partial < SearchAdvancedFiltersForm > = {
86+ ...filterFormValues ,
87+ ...values ,
88+ } ;
89+
90+ // If the type has changed, reset the status so we dont have an invalid status selected
91+ if ( updatedFilterFormValues . type !== filterFormValues . type ) {
92+ updatedFilterFormValues . status = CONST . SEARCH . STATUS . EXPENSE . ALL ;
93+ }
94+
95+ const filterString = buildQueryStringFromFilterFormValues ( updatedFilterFormValues ) ;
96+ const searchQueryJSON = buildSearchQueryJSON ( filterString ) ;
97+ const queryString = buildSearchQueryString ( searchQueryJSON ) ;
98+
99+ Navigation . setParams ( { q : queryString } ) ;
100+ } ,
101+ [ filterFormValues ] ,
102+ ) ;
88103
89104 const openAdvancedFilters = useCallback ( ( ) => {
90105 updateAdvancedFilters ( filterFormValues ) ;
91106 Navigation . navigate ( ROUTES . SEARCH_ADVANCED_FILTERS ) ;
92-
93- // Disable exhaustive deps because we use filterFormValuesKey as the dependency, which is a stable key based on filterFormValues
94- // eslint-disable-next-line react-compiler/react-compiler
95- // eslint-disable-next-line react-hooks/exhaustive-deps
96- } , [ filterFormValuesKey ] ) ;
107+ } , [ filterFormValues ] ) ;
97108
98109 const typeComponent = useCallback (
99110 ( { closeOverlay} : PopoverComponentProps ) => {
100111 const value = typeOptions . find ( ( option ) => option . value === type ) ?? null ;
101112
102- const onChange = ( item : SingleSelectItem < SearchDataTypes > | null ) => {
103- const hasTypeChanged = item ?. value !== type ;
104- const newType = item ?. value ?? CONST . SEARCH . DATA_TYPES . EXPENSE ;
105- // If the type has changed, reset the status so we dont have an invalid status selected
106- const newStatus = hasTypeChanged ? CONST . SEARCH . STATUS . EXPENSE . ALL : status ;
107- const newGroupBy = hasTypeChanged ? undefined : groupBy ;
108- const query = buildSearchQueryString ( { ...queryJSON , type : newType , status : newStatus , groupBy : newGroupBy } ) ;
109- Navigation . setParams ( { q : query } ) ;
110- } ;
111-
112113 return (
113114 < SingleSelectPopup
114115 label = { translate ( 'common.type' ) }
115116 value = { value }
116117 items = { typeOptions }
117118 closeOverlay = { closeOverlay }
118- onChange = { onChange }
119+ onChange = { ( item ) => updateFilterForm ( { type : item ?. value ?? CONST . SEARCH . DATA_TYPES . EXPENSE } ) }
119120 />
120121 ) ;
121122 } ,
122- [ groupBy , queryJSON , status , translate , type , typeOptions ] ,
123+ [ translate , type , typeOptions , updateFilterForm ] ,
123124 ) ;
124125
125126 const statusComponent = useCallback (
@@ -130,8 +131,7 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions}: SearchFiltersBarPro
130131
131132 const onChange = ( selectedItems : Array < MultiSelectItem < SingularSearchStatus > > ) => {
132133 const newStatus = selectedItems . length ? selectedItems . map ( ( i ) => i . value ) : CONST . SEARCH . STATUS . EXPENSE . ALL ;
133- const query = buildSearchQueryString ( { ...queryJSON , status : newStatus } ) ;
134- Navigation . setParams ( { q : query } ) ;
134+ updateFilterForm ( { status : newStatus } ) ;
135135 } ;
136136
137137 return (
@@ -144,7 +144,7 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions}: SearchFiltersBarPro
144144 />
145145 ) ;
146146 } ,
147- [ groupBy , queryJSON , status , translate , type ] ,
147+ [ groupBy , status , translate , type , updateFilterForm ] ,
148148 ) ;
149149
150150 const datePickerComponent = useCallback (
@@ -156,19 +156,13 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions}: SearchFiltersBarPro
156156 } ;
157157
158158 const onChange = ( selectedDates : DateSelectPopupValue ) => {
159- const newFilterFormValues = {
160- ...filterFormValues ,
161- ...queryJSON ,
159+ const dateFormValues = {
162160 dateAfter : selectedDates [ CONST . SEARCH . DATE_MODIFIERS . AFTER ] ?? undefined ,
163161 dateBefore : selectedDates [ CONST . SEARCH . DATE_MODIFIERS . BEFORE ] ?? undefined ,
164162 dateOn : selectedDates [ CONST . SEARCH . DATE_MODIFIERS . ON ] ?? undefined ,
165163 } ;
166164
167- const filterString = buildQueryStringFromFilterFormValues ( newFilterFormValues ) ;
168- const newJSON = buildSearchQueryJSON ( filterString ) ;
169- const queryString = buildSearchQueryString ( newJSON ) ;
170-
171- Navigation . setParams ( { q : queryString } ) ;
165+ updateFilterForm ( dateFormValues ) ;
172166 } ;
173167
174168 return (
@@ -179,10 +173,7 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions}: SearchFiltersBarPro
179173 />
180174 ) ;
181175 } ,
182- // Disable exhaustive deps because we use filterFormValuesKey as the dependency, which is a stable key based on filterFormValues
183- // eslint-disable-next-line react-compiler/react-compiler
184- // eslint-disable-next-line react-hooks/exhaustive-deps
185- [ filterFormValuesKey , queryJSON ] ,
176+ [ filterFormValues . dateAfter , filterFormValues . dateBefore , filterFormValues . dateOn , updateFilterForm ] ,
186177 ) ;
187178
188179 const userPickerComponent = useCallback (
@@ -193,18 +184,11 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions}: SearchFiltersBarPro
193184 < UserSelectPopup
194185 value = { value }
195186 closeOverlay = { closeOverlay }
196- onChange = { ( selectedUsers ) => {
197- const newFilterFormValues = { ...filterFormValues , from : selectedUsers } ;
198- const queryString = buildQueryStringFromFilterFormValues ( newFilterFormValues ) ;
199- Navigation . setParams ( { q : queryString } ) ;
200- } }
187+ onChange = { ( selectedUsers ) => updateFilterForm ( { from : selectedUsers } ) }
201188 />
202189 ) ;
203190 } ,
204- // Disable exhaustive deps because we use filterFormValuesKey as the dependency, which is a stable key based on filterFormValues
205- // eslint-disable-next-line react-compiler/react-compiler
206- // eslint-disable-next-line react-hooks/exhaustive-deps
207- [ filterFormValuesKey ] ,
191+ [ filterFormValues . from , updateFilterForm ] ,
208192 ) ;
209193
210194 /**
0 commit comments