Skip to content
Closed
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
722464c
Fix sorting to move pre-selected items to the top of lists
marufsharifi Jan 18, 2026
79913be
Fix sorting to move pre-selected items to the top of lists second lists
marufsharifi Jan 18, 2026
82578b6
fixed for the attendees selector
marufsharifi Jan 18, 2026
3c359bc
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Jan 23, 2026
6a442af
revert changes for SearchColumnsPage
marufsharifi Jan 23, 2026
05b5547
removed unnecessary props
marufsharifi Jan 23, 2026
8f88a11
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Jan 24, 2026
9d36163
applied ai optimization suggestions.
marufsharifi Jan 25, 2026
673dce1
moving the loop outside of searchOptions
marufsharifi Jan 25, 2026
c230c97
fixed the attendees issues.
marufsharifi Jan 25, 2026
4cb6618
fixed workspaces dropdown in reports
marufsharifi Jan 25, 2026
f85c1cc
fixed InviteReportParticipantsPage to works
marufsharifi Jan 25, 2026
5d4f1e6
fixed Country selection
marufsharifi Jan 25, 2026
0db9c28
fixed type errors.
marufsharifi Jan 25, 2026
f7b80f5
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Feb 8, 2026
3d5b365
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Feb 10, 2026
1261ff0
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 3, 2026
6c2077f
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 3, 2026
7cc43c6
removed unintentional changes.
marufsharifi Mar 3, 2026
b9845c9
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 5, 2026
a4c653a
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 5, 2026
1c6a028
feat: add shared helper for initial-selected ordering
marufsharifi Mar 5, 2026
dd9f4ca
fix: show selected currency on top in debug constant picker
marufsharifi Mar 5, 2026
2577041
feat: capture initial selection on open/focus
marufsharifi Mar 5, 2026
3bf295e
feat: allow disabling scroll-to-top on select
marufsharifi Mar 5, 2026
6c8657c
fix: stabilize selected ordering in search filter popups
marufsharifi Mar 5, 2026
df0ed51
fix: refresh initial selection snapshot on focus in search pickers
marufsharifi Mar 5, 2026
65b1e8a
refactor: use shared initial-selected ordering across common pickers
marufsharifi Mar 5, 2026
da409d5
feat: allow useSearchSelector to freeze ordering while toggling
marufsharifi Mar 5, 2026
3214915
fix: stabilize selection ordering in rules selectors
marufsharifi Mar 5, 2026
88b920a
fix: stabilize selection ordering in chat invite flows
marufsharifi Mar 5, 2026
c024773
fix: stabilize selection ordering in chat invite flows
marufsharifi Mar 5, 2026
39950e4
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 7, 2026
e4a9b40
fix: stabilize selected-item ordering and focus across pickers
marufsharifi Mar 8, 2026
d589240
fix(rule-picker): keep stale selected option visible
marufsharifi Mar 8, 2026
fedb58c
fix(search-filters): preserve unresolved participant IDs
marufsharifi Mar 8, 2026
8431576
fix(rule-picker): show empty state instead of loading
marufsharifi Mar 8, 2026
30fa6f6
fix: restore selection list focus-sync hook contract
marufsharifi Mar 8, 2026
6f99134
fix: use full empty options shape in search selectors
marufsharifi Mar 8, 2026
51716ac
fix: narrow unresolved participant selections to search option data
marufsharifi Mar 8, 2026
d7011e2
fix: preserve user filter selections through popup hydration
marufsharifi Mar 8, 2026
02ee08b
fix: clean up selection picker and test type regressions
marufsharifi Mar 9, 2026
fcdb19c
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 9, 2026
a1194a3
Fix test failures.
marufsharifi Mar 9, 2026
4b40000
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 9, 2026
ba32165
fix: stabilize CurrencySelectionList initial selection snapshot
marufsharifi Mar 9, 2026
f56de6f
refactor: stabilize initial-selection ordering in selectors
marufsharifi Mar 9, 2026
ba473bb
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 9, 2026
2813d0d
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 10, 2026
e63216b
fixed unit test failure
marufsharifi Mar 10, 2026
3876e3a
Merge branch 'main' into fix/move-preselected-items-to-top
marufsharifi Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,8 @@ const CONST = {
GLOBAL_CREATE: '\uE100',
},

MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD: 8,

INVISIBLE_CODEPOINTS: ['fe0f', '200d', '2066'],

UNICODE: {
Expand Down
23 changes: 20 additions & 3 deletions src/components/ApproverSelectionList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, {useMemo} from 'react';
import useDebouncedState from '@hooks/useDebouncedState';
import useInitialSelectionRef from '@hooks/useInitialSelectionRef';
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import {getSearchValueForPhoneOrEmail, sortAlphabetically} from '@libs/OptionsListUtils';
import {goBackFromInvalidPolicy, isPendingDeletePolicy, isPolicyAdmin} from '@libs/PolicyUtils';
import {reorderItemsByInitialSelection} from '@libs/SelectionListOrderUtils';
import tokenizedSearch from '@libs/tokenizedSearch';
import variables from '@styles/variables';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -76,6 +78,14 @@ function ApproverSelectionList({
const lazyIllustrations = useMemoizedLazyIllustrations(['TurtleInShell']);

const selectedMembers = useMemo(() => allApprovers.filter((approver) => approver.isSelected), [allApprovers]);
const initialSelectedApproverKeys = useInitialSelectionRef(
allApprovers
.filter((approver) => approver.isSelected)
.map((approver) => approver.keyForList?.toString() ?? '')
.filter(Boolean),
{resetDeps: [allApprovers.length], resetOnFocus: true},
);
const initialFocusedApproverKey = useInitialSelectionRef(initiallyFocusedOptionKey, {resetDeps: [allApprovers.length], resetOnFocus: true});

// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundView = (isEmptyObject(policy) && !isLoadingReportData) || !isPolicyAdmin(policy) || isPendingDeletePolicy(policy) || shouldShowNotFoundViewProp;
Expand All @@ -86,8 +96,14 @@ function ApproverSelectionList({
? tokenizedSearch(allApprovers, getSearchValueForPhoneOrEmail(debouncedSearchTerm, countryCode), (option) => [option.text ?? '', option.login ?? ''])
: allApprovers;

return sortAlphabetically(filteredApprovers, 'text', localeCompare);
}, [allApprovers, debouncedSearchTerm, countryCode, localeCompare]);
const sortedApprovers = sortAlphabetically(filteredApprovers, 'text', localeCompare);

if (debouncedSearchTerm || initialSelectedApproverKeys.length === 0) {
return sortedApprovers;
}

return reorderItemsByInitialSelection(sortedApprovers, initialSelectedApproverKeys);
}, [allApprovers, countryCode, debouncedSearchTerm, initialSelectedApproverKeys, localeCompare]);

const shouldShowListEmptyContent = !debouncedSearchTerm && !data.length && shouldShowListEmptyContentProp;

Expand Down Expand Up @@ -160,14 +176,15 @@ function ApproverSelectionList({
shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
listEmptyContent={listEmptyContent}
shouldShowListEmptyContent={shouldShowListEmptyContent}
initiallyFocusedItemKey={initiallyFocusedOptionKey}
initiallyFocusedItemKey={initialFocusedApproverKey}
shouldShowTextInput={shouldShowTextInput}
shouldShowLoadingPlaceholder={shouldShowLoadingPlaceholder}
footerContent={footerContent}
addBottomSafeAreaPadding
shouldUpdateFocusedIndex={shouldUpdateFocusedIndex}
showScrollIndicator
isRowMultilineSupported
shouldScrollToTopOnSelect={false}
/>
</FullPageNotFoundView>
</ScreenWrapper>
Expand Down
21 changes: 18 additions & 3 deletions src/components/CountryPicker/CountrySelectorModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/ListItem/RadioListItem';
import useDebouncedState from '@hooks/useDebouncedState';
import useInitialSelectionRef from '@hooks/useInitialSelectionRef';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import searchOptions from '@libs/searchOptions';
import type {Option} from '@libs/searchOptions';
import {moveInitialSelectionToTopByValue} from '@libs/SelectionListOrderUtils';
import StringUtils from '@libs/StringUtils';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
Expand Down Expand Up @@ -36,10 +38,13 @@ type CountrySelectorModalProps = {
function CountrySelectorModal({isVisible, currentCountry, onCountrySelected, onClose, label, onBackdropPress}: CountrySelectorModalProps) {
const {translate} = useLocalize();
const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState('');
const initialSelectedValues = useInitialSelectionRef(currentCountry ? [currentCountry] : [], {resetDeps: [isVisible]});

const countryKeys = useMemo(() => Object.keys(CONST.ALL_COUNTRIES), []);

const countries = useMemo(
() =>
Object.keys(CONST.ALL_COUNTRIES).map((countryISO) => {
countryKeys.map((countryISO) => {
const countryName = translate(`allCountries.${countryISO}` as TranslationPaths);
return {
value: countryISO,
Expand All @@ -49,10 +54,20 @@ function CountrySelectorModal({isVisible, currentCountry, onCountrySelected, onC
searchValue: StringUtils.sanitizeString(`${countryISO}${countryName}`),
};
}),
[translate, currentCountry],
[translate, countryKeys, currentCountry],
);

const searchResults = searchOptions(debouncedSearchValue, countries);
const orderedCountries = useMemo(() => {
const shouldReorderInitialSelection = !debouncedSearchValue && initialSelectedValues.length > 0 && countries.length > CONST.MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD;

if (!shouldReorderInitialSelection) {
return countries;
}

return moveInitialSelectionToTopByValue(countries, initialSelectedValues);
}, [countries, debouncedSearchValue, initialSelectedValues]);

const searchResults = useMemo(() => searchOptions(debouncedSearchValue, orderedCountries), [orderedCountries, debouncedSearchValue]);
const headerMessage = debouncedSearchValue.trim() && !searchResults.length ? translate('common.noResultsFound') : '';

const styles = useThemeStyles();
Expand Down
33 changes: 27 additions & 6 deletions src/components/CurrencySelectionList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {Str} from 'expensify-common';
import React, {useState} from 'react';
import React, {useMemo, useState} from 'react';
import RadioListItem from '@components/SelectionList/ListItem/RadioListItem';
import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections';
import {useCurrencyListActions, useCurrencyListState} from '@hooks/useCurrencyList';
import useInitialSelectionRef from '@hooks/useInitialSelectionRef';
import useLocalize from '@hooks/useLocalize';
import getMatchScore from '@libs/getMatchScore';
import {moveInitialSelectionToTopByValue} from '@libs/SelectionListOrderUtils';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {CurrencyListItem, CurrencySelectionListProps} from './types';

Expand All @@ -23,6 +25,17 @@ function CurrencySelectionList({
const [searchValue, setSearchValue] = useState('');
const {translate} = useLocalize();
const getUnselectedOptions = (options: CurrencyListItem[]) => options.filter((option) => !option.isSelected);
const initialSelectedCurrencyCodes = useMemo(() => {
const codes = new Set<string>();
if (initiallySelectedCurrencyCode) {
codes.add(initiallySelectedCurrencyCode);
}
for (const currencyCode of selectedCurrencies) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: selectedCurrencies is no longer used, so we can safely remove this prop and all related logic

codes.add(currencyCode);
}
return Array.from(codes);
}, [initiallySelectedCurrencyCode, selectedCurrencies]);
const initialSelectedCurrencySnapshot = useInitialSelectionRef(initialSelectedCurrencyCodes, {resetDeps: [initialSelectedCurrencyCodes], resetOnFocus: true});

const currencyOptions: CurrencyListItem[] = Object.entries(currencyList).reduce((acc, [currencyCode, currencyInfo]) => {
const isSelectedCurrency = currencyCode === initiallySelectedCurrencyCode || selectedCurrencies.includes(currencyCode);
Expand Down Expand Up @@ -57,11 +70,19 @@ function CurrencySelectionList({
.filter((currencyOption) => searchRegex.test(currencyOption.text ?? '') || searchRegex.test(currencyOption.currencyName))
.sort((currency1, currency2) => getMatchScore(currency2.text ?? '', searchValue) - getMatchScore(currency1.text ?? '', searchValue));

const isEmpty = searchValue.trim() && !filteredCurrencies.length;
const shouldReorderInitialSelection = !searchValue && initialSelectedCurrencySnapshot.length > 0;
const displayCurrencies = shouldReorderInitialSelection
? moveInitialSelectionToTopByValue(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just use reorderItemsByInitialSelection instead of moveInitialSelectionToTopByValue. That way we don't need an extra .map() to create a new list

filteredCurrencies.map((currency) => ({...currency, value: currency.currencyCode})),
initialSelectedCurrencySnapshot,
)
: filteredCurrencies;

const isEmpty = searchValue.trim() && !displayCurrencies.length;
const shouldDisplayRecentlyOptions = !isEmptyObject(recentlyUsedCurrencyOptions) && !searchValue;
const selectedOptions = filteredCurrencies.filter((option) => option.isSelected);
const selectedOptions = displayCurrencies.filter((option) => option.isSelected);
const shouldDisplaySelectedOptionOnTop = selectedOptions.length > 0;
const unselectedOptions = getUnselectedOptions(filteredCurrencies);
const unselectedOptions = getUnselectedOptions(displayCurrencies);
const sections = [];

if (shouldDisplaySelectedOptionOnTop) {
Expand All @@ -80,12 +101,12 @@ function CurrencySelectionList({
data: shouldDisplaySelectedOptionOnTop ? getUnselectedOptions(recentlyUsedCurrencyOptions) : recentlyUsedCurrencyOptions,
sectionIndex: 1,
},
{title: translate('common.all'), data: shouldDisplayRecentlyOptions ? unselectedOptions : filteredCurrencies, sectionIndex: 2},
{title: translate('common.all'), data: shouldDisplayRecentlyOptions ? unselectedOptions : displayCurrencies, sectionIndex: 2},
);
}
} else if (!isEmpty) {
sections.push({
data: shouldDisplaySelectedOptionOnTop ? unselectedOptions : filteredCurrencies,
data: shouldDisplaySelectedOptionOnTop ? unselectedOptions : displayCurrencies,
sectionIndex: 3,
});
}
Expand Down
19 changes: 14 additions & 5 deletions src/components/DatePicker/CalendarPicker/YearPickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import Modal from '@components/Modal';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/ListItem/RadioListItem';
import useInitialSelectionRef from '@hooks/useInitialSelectionRef';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import {reorderItemsByInitialSelection} from '@libs/SelectionListOrderUtils';
import CONST from '@src/CONST';
import type CalendarPickerListItem from './types';

Expand All @@ -31,13 +33,18 @@ function YearPickerModal({isVisible, years, currentYear = new Date().getFullYear
const styles = useThemeStyles();
const {translate} = useLocalize();
const [searchText, setSearchText] = useState('');
const initialSelectedValues = useInitialSelectionRef([currentYear.toString()], {resetDeps: [isVisible]});
const initiallyFocusedYear = initialSelectedValues.at(0);
const {data, headerMessage} = useMemo(() => {
const yearsList = searchText === '' ? years : years.filter((year) => year.text?.includes(searchText));
const sortedYears = [...yearsList].sort((a, b) => b.value - a.value);
const orderedYears =
searchText || sortedYears.length <= CONST.MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD ? sortedYears : reorderItemsByInitialSelection(sortedYears, initialSelectedValues);
return {
headerMessage: !yearsList.length ? translate('common.noResultsFound') : '',
data: yearsList.sort((a, b) => b.value - a.value),
headerMessage: !orderedYears.length ? translate('common.noResultsFound') : '',
data: orderedYears,
};
}, [years, searchText, translate]);
}, [initialSelectedValues, searchText, translate, years]);

useEffect(() => {
if (isVisible) {
Expand Down Expand Up @@ -84,11 +91,13 @@ function YearPickerModal({isVisible, years, currentYear = new Date().getFullYear
ListItem={RadioListItem}
onSelectRow={(option) => {
Keyboard.dismiss();
onYearChange?.(option.value);
onYearChange?.(Number(option.keyForList));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to update this?
I tried using option.value and it seems to work fine, no problems

}}
textInputOptions={textInputOptions}
initiallyFocusedItemKey={currentYear.toString()}
initiallyFocusedItemKey={initiallyFocusedYear}
disableMaintainingScrollPosition
shouldScrollToFocusedIndex={false}
shouldScrollToFocusedIndexOnMount={false}
addBottomSafeAreaPadding
shouldStopPropagation
showScrollIndicator
Expand Down
28 changes: 21 additions & 7 deletions src/components/PushRowWithModal/PushRowModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/ListItem/RadioListItem';
import useDebouncedState from '@hooks/useDebouncedState';
import useInitialSelectionRef from '@hooks/useInitialSelectionRef';
import useLocalize from '@hooks/useLocalize';
import searchOptions from '@libs/searchOptions';
import {moveInitialSelectionToTopByValue} from '@libs/SelectionListOrderUtils';
import StringUtils from '@libs/StringUtils';
import CONST from '@src/CONST';

Expand Down Expand Up @@ -44,18 +46,30 @@ function PushRowModal({isVisible, selectedOption, onOptionChange, onClose, optio
const {translate} = useLocalize();

const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState('');
const initialSelectedValues = useInitialSelectionRef(selectedOption ? [selectedOption] : [], {resetDeps: [isVisible]});

const options = useMemo(
() =>
Object.entries(optionsList).map(([key, value]) => ({
const optionKeys = useMemo(() => Object.keys(optionsList), [optionsList]);

const options = useMemo(() => {
const baseOptions = optionKeys.map((key) => {
const value = optionsList[key];
return {
value: key,
text: value,
keyForList: key,
isSelected: key === selectedOption,
searchValue: StringUtils.sanitizeString(value),
})),
[optionsList, selectedOption],
);
};
});

const shouldReorderInitialSelection = !debouncedSearchValue && initialSelectedValues.length > 0 && baseOptions.length > CONST.MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD;

if (!shouldReorderInitialSelection) {
return baseOptions;
}

return moveInitialSelectionToTopByValue(baseOptions, initialSelectedValues);
}, [debouncedSearchValue, initialSelectedValues, optionKeys, optionsList, selectedOption]);

const handleSelectRow = (option: ListItemType) => {
onOptionChange(option.value);
Expand All @@ -67,7 +81,7 @@ function PushRowModal({isVisible, selectedOption, onOptionChange, onClose, optio
setSearchValue('');
};

const searchResults = searchOptions(debouncedSearchValue, options);
const searchResults = useMemo(() => searchOptions(debouncedSearchValue, options), [debouncedSearchValue, options]);

const textInputOptions = useMemo(
() => ({
Expand Down
7 changes: 3 additions & 4 deletions src/components/Rule/RuleSelectionBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React from 'react';
import {View} from 'react-native';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import SearchSingleSelectionPicker from '@components/Search/SearchSingleSelectionPicker';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import type {TranslationPaths} from '@src/languages/types';
import type {Route} from '@src/ROUTES';
import RuleNotFoundPageWrapper from './RuleNotFoundPageWrapper';
import RuleSelectionPicker from './RuleSelectionPicker';

type SelectionItem = {
name: string;
Expand Down Expand Up @@ -59,12 +59,11 @@ function RuleSelectionBase({titleKey, title, testID, selectedItem, items, onSave
onBackButtonPress={onBack}
/>
<View style={[styles.flex1]}>
<SearchSingleSelectionPicker
<RuleSelectionPicker
backToRoute={backToRoute}
initiallySelectedItem={selectedItem}
items={items}
initiallySelectedItem={selectedItem}
onSaveSelection={onSave}
shouldAutoSave
/>
</View>
</ScreenWrapper>
Expand Down
61 changes: 61 additions & 0 deletions src/components/Rule/RuleSelectionPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, {useCallback} from 'react';
import SingleSelectListItem from '@components/SelectionList/ListItem/SingleSelectListItem';
import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections';
import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
import type {Route} from '@src/ROUTES';
import type {RuleSelectionListItem, SelectionItem} from './hooks/useRuleSelectionList';
import useRuleSelectionList from './hooks/useRuleSelectionList';

type RuleSelectionPickerProps = {
items: SelectionItem[];
initiallySelectedItem?: SelectionItem;
onSaveSelection: (value?: string) => void;
backToRoute: Route;
};

function RuleSelectionPicker({items, initiallySelectedItem, onSaveSelection, backToRoute}: RuleSelectionPickerProps) {
const {translate} = useLocalize();
const {sections, noResultsFound, searchTerm, setSearchTerm, initiallyFocusedItemKey} = useRuleSelectionList({
items,
initiallySelectedItem,
});

const onSelectRow = useCallback(
(item: {text?: string; keyForList?: string; isSelected?: boolean}) => {
if (!item.text || !item.keyForList) {
return;
}

const isRemovingSelection = !!item.isSelected;
const newValue = isRemovingSelection ? '' : item.keyForList;

onSaveSelection(newValue);
Navigation.goBack(backToRoute);
},
[backToRoute, onSaveSelection],
);

const textInputOptions = {
value: searchTerm,
label: translate('common.search'),
onChangeText: setSearchTerm,
headerMessage: noResultsFound ? translate('common.noResultsFound') : undefined,
};

return (
<SelectionListWithSections<RuleSelectionListItem>
sections={sections}
ListItem={SingleSelectListItem}
onSelectRow={onSelectRow}
shouldShowTextInput
textInputOptions={textInputOptions}
shouldShowLoadingPlaceholder={false}
initiallyFocusedItemKey={initiallyFocusedItemKey}
shouldStopPropagation
shouldScrollToTopOnSelect={false}
/>
);
}

export default RuleSelectionPicker;
Loading
Loading