@@ -3,9 +3,11 @@ import React, {useEffect, useState} from 'react';
33import { usePersonalDetails } from '@components/OnyxListItemProvider' ;
44import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMemberListItem' ;
55import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections' ;
6+ import type { Section } from '@components/SelectionList/SelectionListWithSections/types' ;
67import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' ;
78import useDebouncedState from '@hooks/useDebouncedState' ;
89import useFilteredOptions from '@hooks/useFilteredOptions' ;
10+ import useFrozenPreSelection from '@hooks/useFrozenPreSelection' ;
911import useLocalize from '@hooks/useLocalize' ;
1012import useOnyx from '@hooks/useOnyx' ;
1113import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap' ;
@@ -14,9 +16,9 @@ import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionS
1416import useSortedActions from '@hooks/useSortedActions' ;
1517import { canUseTouchScreen } from '@libs/DeviceCapabilities' ;
1618import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID' ;
17- import { createOptionFromReport , filterAndOrderOptions , formatSectionsFromSearchTerm , getAlternateText , getSearchOptions } from '@libs/OptionsListUtils' ;
19+ import { createOptionFromReport , filterAndOrderOptions , filterReports , getAlternateText , getSearchOptions } from '@libs/OptionsListUtils' ;
1820import type { Option } from '@libs/OptionsListUtils' ;
19- import type { OptionWithKey , SelectionListSections } from '@libs/OptionsListUtils/types' ;
21+ import type { OptionWithKey , SearchOptionData } from '@libs/OptionsListUtils/types' ;
2022import type { OptionData } from '@libs/ReportUtils' ;
2123import Navigation from '@navigation/Navigation' ;
2224import { searchInServer } from '@userActions/Report' ;
@@ -105,35 +107,27 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
105107 excludeLogins : CONST . EXPENSIFY_EMAILS_OBJECT ,
106108 } ) ;
107109
108- const sections : SelectionListSections = [ ] ;
110+ const selectedReportIDsSet = new Set ( selectedReportIDs ) ;
111+ // Mark selected rows in place so the checkmark moves with the toggle without reordering the list.
112+ const recentReportsWithSelection = chatOptions . recentReports . map ( ( report ) => ( selectedReportIDsSet . has ( report . reportID ) ? getSelectedOptionData ( report ) : report ) ) ;
109113
114+ // Selected reports that don't show up in Recents — surface them but respect the search term.
115+ const visibleReportIDsSet = new Set ( chatOptions . recentReports . map ( ( report ) => report . reportID ) ) ;
116+ const reportIDsMatchingSearch = cleanSearchTerm === '' ? null : new Set ( filterReports ( selectedOptions as SearchOptionData [ ] , [ cleanSearchTerm ] ) . map ( ( report ) => report . reportID ) ) ;
117+ const matchesSearchTerm = ( report : OptionData ) => reportIDsMatchingSearch === null || reportIDsMatchingSearch . has ( report . reportID ) ;
118+ const extraSelectedReports = selectedOptions . filter ( ( report ) => ! visibleReportIDsSet . has ( report . reportID ) && matchesSearchTerm ( report ) ) ;
119+
120+ const baseSections : Array < Section < OptionData > > = [ ] ;
110121 if ( ! isLoading ) {
111- const formattedResults = formatSectionsFromSearchTerm (
112- cleanSearchTerm ,
113- selectedOptions ,
114- chatOptions . recentReports ,
115- chatOptions . personalDetails ,
116- privateIsArchivedMap ,
117- currentUserAccountID ,
118- allPolicies ,
119- personalDetails ,
120- false ,
121- undefined ,
122- reportAttributesDerived ,
123- ) ;
124-
125- sections . push ( formattedResults . section ) ;
126-
127- const visibleReportsWhenSearchTermNonEmpty = chatOptions . recentReports . map ( ( report ) => ( selectedReportIDs . includes ( report . reportID ) ? getSelectedOptionData ( report ) : report ) ) ;
128- const visibleReportsWhenSearchTermEmpty = chatOptions . recentReports . filter ( ( report ) => ! selectedReportIDs . includes ( report . reportID ) ) ;
129- const reportsFiltered = cleanSearchTerm === '' ? visibleReportsWhenSearchTermEmpty : visibleReportsWhenSearchTermNonEmpty ;
130-
131- sections . push ( {
132- data : reportsFiltered ,
133- sectionIndex : 1 ,
134- } ) ;
122+ if ( extraSelectedReports . length > 0 ) {
123+ baseSections . push ( { data : extraSelectedReports , sectionIndex : 1 } ) ;
124+ }
125+ baseSections . push ( { data : recentReportsWithSelection , sectionIndex : 2 } ) ;
135126 }
136- const noResultsFound = didScreenTransitionEnd && sections . at ( 0 ) ?. data . length === 0 && sections . at ( 1 ) ?. data . length === 0 ;
127+
128+ const sections = useFrozenPreSelection < OptionData > ( baseSections , { initialSelectedValues : initialReportIDs , canCapture : ! isLoading } ) ;
129+
130+ const noResultsFound = didScreenTransitionEnd && ! isLoading && sections . every ( ( section ) => section . data . length === 0 ) ;
137131 const headerMessage = noResultsFound ? translate ( 'common.noResultsFound' ) : undefined ;
138132
139133 useEffect ( ( ) => {
@@ -191,6 +185,9 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
191185 footerContent = { footerContent }
192186 canSelectMultiple
193187 shouldPreventDefaultFocusOnSelectRow = { ! canUseTouchScreen ( ) }
188+ shouldUpdateFocusedIndex
189+ shouldPreventAutoScrollOnSelect
190+ shouldClearInputOnSelect = { false }
194191 textInputOptions = { textInputOptions }
195192 isLoadingNewOptions = { isLoadingNewOptions }
196193 shouldShowLoadingPlaceholder = { shouldShowLoadingPlaceholder }
0 commit comments