From 79f02bc6e6b80c799649d3d83bb085f4c4eeb89b Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 22 Feb 2024 13:20:33 +0100 Subject: [PATCH 01/13] Fix bug with Item in report list is not highlighted and list cannot be navigated and refactore code --- .../CalendarPicker/YearPickerModal.tsx | 2 +- .../MoneyRequestConfirmationList.js | 3 -- ...oraryForRefactorRequestConfirmationList.js | 3 -- .../OptionsList/BaseOptionsList.tsx | 7 +++- src/components/OptionsList/types.ts | 3 -- .../optionsSelectorPropTypes.js | 3 -- .../SelectionList/BaseSelectionList.tsx | 7 +++- .../SelectionList/selectionListPropTypes.js | 3 -- .../StatePicker/StateSelectorModal.tsx | 2 +- src/libs/OptionsListUtils.ts | 39 ------------------- src/pages/EditReportFieldDropdownPage.tsx | 1 + src/pages/NewChatPage.tsx | 10 +---- .../BusinessTypeSelectorModal.tsx | 2 +- src/pages/ReportParticipantsPage.tsx | 1 - src/pages/RoomInvitePage.tsx | 6 --- src/pages/RoomMembersPage.tsx | 2 +- src/pages/SearchPage/index.js | 6 --- src/pages/WorkspaceSwitcherPage.tsx | 1 - src/pages/iou/IOUCurrencySelection.js | 1 - ...yForRefactorRequestParticipantsSelector.js | 8 ---- .../request/step/IOURequestStepCurrency.js | 1 - .../MoneyRequestParticipantsSelector.js | 8 ---- .../ShareLogList/BaseShareLogList.tsx | 6 --- .../PersonalDetails/CountrySelectionPage.js | 2 +- src/pages/settings/Profile/PronounsPage.js | 2 +- .../settings/Profile/TimezoneSelectPage.js | 2 +- src/pages/tasks/TaskAssigneeSelectorModal.js | 8 ---- .../TaskShareDestinationSelectorModal.js | 3 -- src/pages/workspace/WorkspaceInvitePage.tsx | 6 --- src/pages/workspace/WorkspaceMembersPage.js | 2 +- .../workspace/WorkspaceProfileCurrencyPage.js | 2 +- 31 files changed, 23 insertions(+), 129 deletions(-) diff --git a/src/components/DatePicker/CalendarPicker/YearPickerModal.tsx b/src/components/DatePicker/CalendarPicker/YearPickerModal.tsx index f8c4a12ec188..29beedb92714 100644 --- a/src/components/DatePicker/CalendarPicker/YearPickerModal.tsx +++ b/src/components/DatePicker/CalendarPicker/YearPickerModal.tsx @@ -34,7 +34,7 @@ function YearPickerModal({isVisible, years, currentYear = new Date().getFullYear const yearsList = searchText === '' ? years : years.filter((year) => year.text.includes(searchText)); return { headerMessage: !yearsList.length ? translate('common.noResultsFound') : '', - sections: [{data: yearsList.sort((a, b) => b.value - a.value), indexOffset: 0}], + sections: [{data: yearsList.sort((a, b) => b.value - a.value)}], }; }, [years, searchText, translate]); diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 0de601bc9f61..5db353a01830 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -377,14 +377,12 @@ function MoneyRequestConfirmationList(props) { title: translate('moneyRequestConfirmationList.paidBy'), data: [formattedPayeeOption], shouldShow: true, - indexOffset: 0, isDisabled: shouldDisablePaidBySection, }, { title: translate('moneyRequestConfirmationList.splitWith'), data: formattedParticipantsList, shouldShow: true, - indexOffset: 1, }, ); } else { @@ -396,7 +394,6 @@ function MoneyRequestConfirmationList(props) { title: translate('common.to'), data: formattedSelectedParticipants, shouldShow: true, - indexOffset: 0, }); } return sections; diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 3939e847707d..a2efb01a5e76 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -422,14 +422,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ title: translate('moneyRequestConfirmationList.paidBy'), data: [formattedPayeeOption], shouldShow: true, - indexOffset: 0, isDisabled: shouldDisablePaidBySection, }, { title: translate('moneyRequestConfirmationList.splitWith'), data: formattedParticipantsList, shouldShow: true, - indexOffset: 1, }, ); } else { @@ -441,7 +439,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ title: translate('common.to'), data: formattedSelectedParticipants, shouldShow: true, - indexOffset: 0, }); } return sections; diff --git a/src/components/OptionsList/BaseOptionsList.tsx b/src/components/OptionsList/BaseOptionsList.tsx index 575df128894a..928308c73bfe 100644 --- a/src/components/OptionsList/BaseOptionsList.tsx +++ b/src/components/OptionsList/BaseOptionsList.tsx @@ -223,6 +223,11 @@ function BaseOptionsList( return ; }; + const sectionsWithIndexOffset = sections.map((section, index) => { + const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + curr.data.length, 0); + return {...section, indexOffset}; + }); + return ( {isLoading ? ( @@ -248,7 +253,7 @@ function BaseOptionsList( onScroll={onScroll} contentContainerStyle={contentContainerStyles} showsVerticalScrollIndicator={showScrollIndicator} - sections={sections} + sections={sectionsWithIndexOffset} keyExtractor={extractKey} stickySectionHeadersEnabled={false} renderItem={renderItem} diff --git a/src/components/OptionsList/types.ts b/src/components/OptionsList/types.ts index fa3ef8df56f6..dc455a53690d 100644 --- a/src/components/OptionsList/types.ts +++ b/src/components/OptionsList/types.ts @@ -9,9 +9,6 @@ type Section = { /** Title of the section */ title: string; - /** The initial index of this section given the total number of options in each section's data array */ - indexOffset: number; - /** Array of options */ data: OptionData[]; diff --git a/src/components/OptionsSelector/optionsSelectorPropTypes.js b/src/components/OptionsSelector/optionsSelectorPropTypes.js index 8e58a7ffdb86..b430ce8a4933 100644 --- a/src/components/OptionsSelector/optionsSelectorPropTypes.js +++ b/src/components/OptionsSelector/optionsSelectorPropTypes.js @@ -14,9 +14,6 @@ const propTypes = { /** Title of the section */ title: PropTypes.string, - /** The initial index of this section given the total number of options in each section's data array */ - indexOffset: PropTypes.number, - /** Array of options */ data: PropTypes.arrayOf(optionPropTypes), diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index b0996a08895a..9c2998a0f868 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -375,6 +375,11 @@ function BaseSelectionList( isActive: !disableKeyboardShortcuts && isFocused, }); + const sectionsWithIndexOffset = sections.map((section, index) => { + const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + curr.data.length, 0); + return {...section, indexOffset}; + }); + return ( ( )} {}, onStat // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing textInputLabel={label || translate('common.state')} textInputValue={searchValue} - sections={[{data: searchResults, indexOffset: 0}]} + sections={[{data: searchResults}]} onSelectRow={onStateSelected} onChangeText={setSearchValue} initiallyFocusedOptionKey={currentState} diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 97b4fc0144c8..e655740eca95 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -71,7 +71,6 @@ type PayeePersonalDetails = { type CategorySection = { title: string | undefined; shouldShow: boolean; - indexOffset: number; data: Option[]; }; @@ -131,7 +130,6 @@ type MemberForList = { type SectionForSearchTerm = { section: CategorySection; - newIndexOffset: number; }; type GetOptions = { @@ -946,14 +944,11 @@ function getCategoryListSections( const categorySections: CategorySection[] = []; const numberOfCategories = enabledCategories.length; - let indexOffset = 0; - if (numberOfCategories === 0 && selectedOptions.length > 0) { categorySections.push({ // "Selected" section title: '', shouldShow: false, - indexOffset, data: getCategoryOptionTree(selectedOptions, true), }); @@ -967,7 +962,6 @@ function getCategoryListSections( // "Search" section title: '', shouldShow: true, - indexOffset, data: getCategoryOptionTree(searchCategories, true), }); @@ -983,7 +977,6 @@ function getCategoryListSections( // "All" section when items amount less than the threshold title: '', shouldShow: false, - indexOffset, data: getCategoryOptionTree(enabledAndSelectedCategories), }); @@ -995,11 +988,8 @@ function getCategoryListSections( // "Selected" section title: '', shouldShow: false, - indexOffset, data: getCategoryOptionTree(selectedOptions, true), }); - - indexOffset += selectedOptions.length; } const filteredRecentlyUsedCategories = recentlyUsedCategories @@ -1016,11 +1006,8 @@ function getCategoryListSections( // "Recent" section title: Localize.translateLocal('common.recent'), shouldShow: true, - indexOffset, data: getCategoryOptionTree(cutRecentlyUsedCategories, true), }); - - indexOffset += filteredRecentlyUsedCategories.length; } const filteredCategories = enabledCategories.filter((category) => !selectedOptionNames.includes(category.name)); @@ -1029,7 +1016,6 @@ function getCategoryListSections( // "All" section when items amount more than the threshold title: Localize.translateLocal('common.all'), shouldShow: true, - indexOffset, data: getCategoryOptionTree(filteredCategories), }); @@ -1063,7 +1049,6 @@ function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOpt const sortedTags = sortTags(tags); const enabledTags = sortedTags.filter((tag) => tag.enabled); const numberOfTags = enabledTags.length; - let indexOffset = 0; // If all tags are disabled but there's a previously selected tag, show only the selected tag if (numberOfTags === 0 && selectedOptions.length > 0) { @@ -1076,7 +1061,6 @@ function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOpt // "Selected" section title: '', shouldShow: false, - indexOffset, data: getTagsOptions(selectedTagOptions), }); @@ -1090,7 +1074,6 @@ function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOpt // "Search" section title: '', shouldShow: true, - indexOffset, data: getTagsOptions(searchTags), }); @@ -1102,7 +1085,6 @@ function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOpt // "All" section when items amount less than the threshold title: '', shouldShow: false, - indexOffset, data: getTagsOptions(enabledTags), }); @@ -1131,11 +1113,8 @@ function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOpt // "Selected" section title: '', shouldShow: true, - indexOffset, data: getTagsOptions(selectedTagOptions), }); - - indexOffset += selectedOptions.length; } if (filteredRecentlyUsedTags.length > 0) { @@ -1145,18 +1124,14 @@ function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOpt // "Recent" section title: Localize.translateLocal('common.recent'), shouldShow: true, - indexOffset, data: getTagsOptions(cutRecentlyUsedTags), }); - - indexOffset += filteredRecentlyUsedTags.length; } tagSections.push({ // "All" section when items amount more than the threshold title: Localize.translateLocal('common.all'), shouldShow: true, - indexOffset, data: getTagsOptions(filteredTags), }); @@ -1227,8 +1202,6 @@ function getTaxRatesSection(policyTaxRates: PolicyTaxRateWithDefault | undefined const enabledTaxRates = sortedTaxRates.filter((taxRate) => !taxRate.isDisabled); const numberOfTaxRates = enabledTaxRates.length; - let indexOffset = 0; - // If all tax are disabled but there's a previously selected tag, show only the selected tag if (numberOfTaxRates === 0 && selectedOptions.length > 0) { const selectedTaxRateOptions = selectedOptions.map((option) => ({ @@ -1240,7 +1213,6 @@ function getTaxRatesSection(policyTaxRates: PolicyTaxRateWithDefault | undefined // "Selected" sectiong title: '', shouldShow: false, - indexOffset, data: getTaxRatesOptions(selectedTaxRateOptions), }); @@ -1254,7 +1226,6 @@ function getTaxRatesSection(policyTaxRates: PolicyTaxRateWithDefault | undefined // "Search" section title: '', shouldShow: true, - indexOffset, data: getTaxRatesOptions(searchTaxRates), }); @@ -1266,7 +1237,6 @@ function getTaxRatesSection(policyTaxRates: PolicyTaxRateWithDefault | undefined // "All" section when items amount less than the threshold title: '', shouldShow: false, - indexOffset, data: getTaxRatesOptions(enabledTaxRates), }); @@ -1290,18 +1260,14 @@ function getTaxRatesSection(policyTaxRates: PolicyTaxRateWithDefault | undefined // "Selected" section title: '', shouldShow: true, - indexOffset, data: getTaxRatesOptions(selectedTaxRatesOptions), }); - - indexOffset += selectedOptions.length; } policyRatesSections.push({ // "All" section when number of items are more than the threshold title: '', shouldShow: true, - indexOffset, data: getTaxRatesOptions(filteredTaxRates), }); @@ -1965,7 +1931,6 @@ function formatSectionsFromSearchTerm( filteredRecentReports: ReportUtils.OptionData[], filteredPersonalDetails: ReportUtils.OptionData[], maxOptionsSelected: boolean, - indexOffset = 0, personalDetails: OnyxEntry = {}, shouldGetOptionDetails = false, ): SectionForSearchTerm { @@ -1983,9 +1948,7 @@ function formatSectionsFromSearchTerm( }) : selectedOptions, shouldShow: selectedOptions.length > 0, - indexOffset, }, - newIndexOffset: indexOffset + selectedOptions.length, }; } @@ -2009,9 +1972,7 @@ function formatSectionsFromSearchTerm( }) : selectedParticipantsWithoutDetails, shouldShow: selectedParticipantsWithoutDetails.length > 0, - indexOffset, }, - newIndexOffset: indexOffset + selectedParticipantsWithoutDetails.length, }; } diff --git a/src/pages/EditReportFieldDropdownPage.tsx b/src/pages/EditReportFieldDropdownPage.tsx index 1ad3c766221b..1ad63bb2bf2f 100644 --- a/src/pages/EditReportFieldDropdownPage.tsx +++ b/src/pages/EditReportFieldDropdownPage.tsx @@ -92,6 +92,7 @@ function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, textInputLabel={translate('common.search')} boldStyle sections={sections} + focusedIndex={0} value={searchValue} onSelectRow={(option: Record) => onSubmit({[fieldID]: option.text})} onChangeText={setSearchValue} diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 72393e89ae1a..b4f40eb0691b 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -73,13 +73,10 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, isSearchingF const sections = useMemo((): OptionsListUtils.CategorySection[] => { const sectionsList: OptionsListUtils.CategorySection[] = []; - let indexOffset = 0; - const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(searchTerm, selectedOptions, filteredRecentReports, filteredPersonalDetails, maxParticipantsReached, indexOffset); + const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(searchTerm, selectedOptions, filteredRecentReports, filteredPersonalDetails, maxParticipantsReached); sectionsList.push(formatResults.section); - indexOffset = formatResults.newIndexOffset; - if (maxParticipantsReached) { return sectionsList; } @@ -88,24 +85,19 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, isSearchingF title: translate('common.recents'), data: filteredRecentReports, shouldShow: filteredRecentReports.length > 0, - indexOffset, }); - indexOffset += filteredRecentReports.length; sectionsList.push({ title: translate('common.contacts'), data: filteredPersonalDetails, shouldShow: filteredPersonalDetails.length > 0, - indexOffset, }); - indexOffset += filteredPersonalDetails.length; if (filteredUserToInvite) { sectionsList.push({ title: undefined, data: [filteredUserToInvite], shouldShow: true, - indexOffset, }); } diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/TypeBusiness/BusinessTypePicker/BusinessTypeSelectorModal.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/TypeBusiness/BusinessTypePicker/BusinessTypeSelectorModal.tsx index 2db3a4fdf7ad..0f85b58bf10a 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/TypeBusiness/BusinessTypePicker/BusinessTypeSelectorModal.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/TypeBusiness/BusinessTypePicker/BusinessTypeSelectorModal.tsx @@ -62,7 +62,7 @@ function BusinessTypeSelectorModal({isVisible, currentBusinessType, onBusinessTy onBackButtonPress={onClose} /> { diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 40a1b009b38d..464a63f723f9 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -97,7 +97,6 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa const sections = useMemo(() => { const sectionsArr: Sections = []; - let indexOffset = 0; if (!didScreenTransitionEnd) { return []; @@ -120,9 +119,7 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa sectionsArr.push({ title: undefined, data: filterSelectedOptionsFormatted, - indexOffset, }); - indexOffset += filterSelectedOptions.length; // Filtering out selected users from the search results const selectedLogins = selectedOptions.map(({login}) => login); @@ -133,15 +130,12 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa sectionsArr.push({ title: translate('common.contacts'), data: personalDetailsFormatted, - indexOffset, }); - indexOffset += personalDetailsFormatted.length; if (hasUnselectedUserToInvite) { sectionsArr.push({ title: undefined, data: [OptionsListUtils.formatMemberForList(userToInvite)], - indexOffset, }); } diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 7593857536a6..3b33ced25d5f 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -265,7 +265,7 @@ function RoomMembersPage({report, session, policies}: RoomMembersPageProps) { { const newSections = []; - let indexOffset = 0; if (recentReports.length > 0) { newSections.push({ data: recentReports, shouldShow: true, - indexOffset, }); - indexOffset += recentReports.length; } if (localPersonalDetails.length > 0) { newSections.push({ data: localPersonalDetails, shouldShow: true, - indexOffset, }); - indexOffset += recentReports.length; } if (userToInvite) { newSections.push({ data: [userToInvite], shouldShow: true, - indexOffset, }); } diff --git a/src/pages/WorkspaceSwitcherPage.tsx b/src/pages/WorkspaceSwitcherPage.tsx index d361ba5137b6..7ef1c8d1fb53 100644 --- a/src/pages/WorkspaceSwitcherPage.tsx +++ b/src/pages/WorkspaceSwitcherPage.tsx @@ -155,7 +155,6 @@ function WorkspaceSwitcherPage({policies}: WorkspaceSwitcherPageProps) { () => ({ data: filteredAndSortedUserWorkspaces, shouldShow: true, - indexOffset: 0, }), [filteredAndSortedUserWorkspaces], ); diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js index 7495efb43171..da662b066176 100644 --- a/src/pages/iou/IOUCurrencySelection.js +++ b/src/pages/iou/IOUCurrencySelection.js @@ -145,7 +145,6 @@ function IOUCurrencySelection(props) { : [ { data: filteredCurrencies, - indexOffset: 0, }, ], headerMessage: isEmpty ? translate('common.noResultsFound') : '', diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index 238b66c0e727..c514dd9663df 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -106,7 +106,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ if (!didScreenTransitionEnd) { return [newSections, {}]; } - let indexOffset = 0; const chatOptions = OptionsListUtils.getFilteredOptions( reports, @@ -141,12 +140,10 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ chatOptions.recentReports, chatOptions.personalDetails, maxParticipantsReached, - indexOffset, personalDetails, true, ); newSections.push(formatResults.section); - indexOffset = formatResults.newIndexOffset; if (maxParticipantsReached) { return [newSections, {}]; @@ -156,17 +153,13 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ title: translate('common.recents'), data: chatOptions.recentReports, shouldShow: !_.isEmpty(chatOptions.recentReports), - indexOffset, }); - indexOffset += chatOptions.recentReports.length; newSections.push({ title: translate('common.contacts'), data: chatOptions.personalDetails, shouldShow: !_.isEmpty(chatOptions.personalDetails), - indexOffset, }); - indexOffset += chatOptions.personalDetails.length; if (chatOptions.userToInvite && !OptionsListUtils.isCurrentUser(chatOptions.userToInvite)) { newSections.push({ @@ -176,7 +169,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails); }), shouldShow: true, - indexOffset, }); } diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index 43e4e9bf0eaa..ba1354b4a2e6 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -109,7 +109,6 @@ function IOURequestStepCurrency({ : [ { data: filteredCurrencies, - indexOffset: 0, }, ], headerMessage: isEmpty ? translate('common.noResultsFound') : '', diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 3fde970327d7..f75bf3f7ddd2 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -140,7 +140,6 @@ function MoneyRequestParticipantsSelector({ */ const sections = useMemo(() => { const newSections = []; - let indexOffset = 0; const formatResults = OptionsListUtils.formatSectionsFromSearchTerm( searchTerm, @@ -148,12 +147,10 @@ function MoneyRequestParticipantsSelector({ newChatOptions.recentReports, newChatOptions.personalDetails, maxParticipantsReached, - indexOffset, personalDetails, true, ); newSections.push(formatResults.section); - indexOffset = formatResults.newIndexOffset; if (maxParticipantsReached) { return newSections; @@ -163,17 +160,13 @@ function MoneyRequestParticipantsSelector({ title: translate('common.recents'), data: newChatOptions.recentReports, shouldShow: !_.isEmpty(newChatOptions.recentReports), - indexOffset, }); - indexOffset += newChatOptions.recentReports.length; newSections.push({ title: translate('common.contacts'), data: newChatOptions.personalDetails, shouldShow: !_.isEmpty(newChatOptions.personalDetails), - indexOffset, }); - indexOffset += newChatOptions.personalDetails.length; if (newChatOptions.userToInvite && !OptionsListUtils.isCurrentUser(newChatOptions.userToInvite)) { newSections.push({ @@ -183,7 +176,6 @@ function MoneyRequestParticipantsSelector({ return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails); }), shouldShow: true, - indexOffset, }); } diff --git a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx index 18e936f3045e..70c2d301b9ac 100644 --- a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx +++ b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx @@ -64,29 +64,23 @@ function BaseShareLogList({betas, reports, onAttachLogToReport}: BaseShareLogLis const sections = useMemo(() => { const sectionsList = []; - let indexOffset = 0; sectionsList.push({ title: translate('common.recents'), data: searchOptions.recentReports, shouldShow: searchOptions.recentReports?.length > 0, - indexOffset, }); - indexOffset += searchOptions.recentReports?.length; sectionsList.push({ title: translate('common.contacts'), data: searchOptions.personalDetails, shouldShow: searchOptions.personalDetails?.length > 0, - indexOffset, }); - indexOffset += searchOptions.personalDetails?.length; if (searchOptions.userToInvite) { sectionsList.push({ data: [searchOptions.userToInvite], shouldShow: true, - indexOffset, }); } diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js index d8327041538d..4adee2cc0dd4 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js @@ -93,7 +93,7 @@ function CountrySelectionPage({route, navigation}) { headerMessage={headerMessage} textInputLabel={translate('common.country')} textInputValue={searchValue} - sections={[{data: searchResults, indexOffset: 0}]} + sections={[{data: searchResults}]} ListItem={RadioListItem} onSelectRow={selectCountry} onChangeText={setSearchValue} diff --git a/src/pages/settings/Profile/PronounsPage.js b/src/pages/settings/Profile/PronounsPage.js index 1d4675a42b8a..b8c0a4ebffde 100644 --- a/src/pages/settings/Profile/PronounsPage.js +++ b/src/pages/settings/Profile/PronounsPage.js @@ -100,7 +100,7 @@ function PronounsPage({currentUserPersonalDetails, isLoadingApp}) { textInputLabel={translate('pronounsPage.pronouns')} textInputPlaceholder={translate('pronounsPage.placeholderText')} textInputValue={searchValue} - sections={[{data: filteredPronounsList, indexOffset: 0}]} + sections={[{data: filteredPronounsList}]} ListItem={RadioListItem} onSelectRow={updatePronouns} onChangeText={setSearchValue} diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index b6c8a5967abc..9e8dafcc5205 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -94,7 +94,7 @@ function TimezoneSelectPage(props) { textInputValue={timezoneInputText} onChangeText={filterShownTimezones} onSelectRow={saveSelectedTimezone} - sections={[{data: timezoneOptions, indexOffset: 0, isDisabled: timezone.automatic}]} + sections={[{data: timezoneOptions, isDisabled: timezone.automatic}]} initiallyFocusedOptionKey={_.get(_.filter(timezoneOptions, (tz) => tz.text === timezone.selected)[0], 'keyForList')} showScrollIndicator shouldShowTooltips={false} diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 0e1e64dfa415..67a6e5f57d01 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -121,39 +121,31 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { const sections = useMemo(() => { const sectionsList = []; - let indexOffset = 0; if (currentUserOption) { sectionsList.push({ title: translate('newTaskPage.assignMe'), data: [currentUserOption], shouldShow: true, - indexOffset, }); - indexOffset += 1; } sectionsList.push({ title: translate('common.recents'), data: recentReports, shouldShow: recentReports?.length > 0, - indexOffset, }); - indexOffset += recentReports?.length; sectionsList.push({ title: translate('common.contacts'), data: personalDetails, shouldShow: personalDetails?.length > 0, - indexOffset, }); - indexOffset += personalDetails?.length; if (userToInvite) { sectionsList.push({ data: [userToInvite], shouldShow: true, - indexOffset, }); } diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.js b/src/pages/tasks/TaskShareDestinationSelectorModal.js index b8d9229e6158..e4144f8b348e 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.js +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.js @@ -90,15 +90,12 @@ function TaskShareDestinationSelectorModal(props) { const getSections = () => { const sections = []; - let indexOffset = 0; if (filteredRecentReports?.length > 0) { sections.push({ data: filteredRecentReports, shouldShow: true, - indexOffset, }); - indexOffset += filteredRecentReports?.length; } return sections; diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index 8efc7d7c6a1e..b65f168fd7b2 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -164,7 +164,6 @@ function WorkspaceInvitePage({ const sections: MembersSection[] = useMemo(() => { const sectionsArr: MembersSection[] = []; - let indexOffset = 0; if (!didScreenTransitionEnd) { return []; @@ -188,9 +187,7 @@ function WorkspaceInvitePage({ title: undefined, data: filterSelectedOptions, shouldShow: true, - indexOffset, }); - indexOffset += filterSelectedOptions.length; // Filtering out selected users from the search results const selectedLogins = selectedOptions.map(({login}) => login); @@ -201,9 +198,7 @@ function WorkspaceInvitePage({ title: translate('common.contacts'), data: personalDetailsFormatted, shouldShow: !isEmptyObject(personalDetailsFormatted), - indexOffset, }); - indexOffset += personalDetailsFormatted.length; Object.values(usersToInvite).forEach((userToInvite) => { const hasUnselectedUserToInvite = !selectedLogins.some((selectedLogin) => selectedLogin === userToInvite.login); @@ -213,7 +208,6 @@ function WorkspaceInvitePage({ title: undefined, data: [OptionsListUtils.formatMemberForList(userToInvite)], shouldShow: true, - indexOffset: indexOffset++, }); } }); diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 62b96943453c..311be0481f84 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -488,7 +488,7 @@ function WorkspaceMembersPage(props) { Date: Thu, 22 Feb 2024 13:38:57 +0100 Subject: [PATCH 02/13] Fix TS issue and update tests --- .../OptionsList/BaseOptionsList.tsx | 2 +- src/components/OptionsList/types.ts | 3 +++ tests/unit/OptionsListUtilsTest.js | 20 ------------------- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/components/OptionsList/BaseOptionsList.tsx b/src/components/OptionsList/BaseOptionsList.tsx index 928308c73bfe..6e3effc24e90 100644 --- a/src/components/OptionsList/BaseOptionsList.tsx +++ b/src/components/OptionsList/BaseOptionsList.tsx @@ -182,7 +182,7 @@ function BaseOptionsList( option={item} showTitleTooltip={showTitleTooltip} hoverStyle={optionHoveredStyle} - optionIsFocused={!disableFocusOptions && !isItemDisabled && focusedIndex === index + section.indexOffset} + optionIsFocused={!disableFocusOptions && !isItemDisabled && focusedIndex === index + (section.indexOffset ?? 0)} onSelectRow={onSelectRow} isSelected={isSelected} showSelectedState={canSelectMultipleOptions} diff --git a/src/components/OptionsList/types.ts b/src/components/OptionsList/types.ts index dc455a53690d..c8c117d800e4 100644 --- a/src/components/OptionsList/types.ts +++ b/src/components/OptionsList/types.ts @@ -9,6 +9,9 @@ type Section = { /** Title of the section */ title: string; + /** The initial index of this section given the total number of options in each section's data array */ + indexOffset?: number; + /** Array of options */ data: OptionData[]; diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 00f1307ab59f..cd17b5157059 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -713,7 +713,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: false, - indexOffset: 0, data: [ { text: 'Food', @@ -746,7 +745,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [ { text: 'Food', @@ -771,7 +769,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [], }, ]; @@ -837,7 +834,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: false, - indexOffset: 0, data: [ { text: 'Medical', @@ -852,7 +848,6 @@ describe('OptionsListUtils', () => { { title: 'Recent', shouldShow: true, - indexOffset: 1, data: [ { text: 'Restaurant', @@ -867,7 +862,6 @@ describe('OptionsListUtils', () => { { title: 'All', shouldShow: true, - indexOffset: 2, data: [ { text: 'Cars', @@ -964,7 +958,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [ { text: 'Food', @@ -997,7 +990,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [], }, ]; @@ -1006,7 +998,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: false, - indexOffset: 0, data: [ { text: 'Medical', @@ -1111,7 +1102,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: false, - indexOffset: 0, // data sorted alphabetically by name data: [ { @@ -1142,7 +1132,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [ { text: 'Accounting', @@ -1158,7 +1147,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [], }, ]; @@ -1212,7 +1200,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [ { text: 'Medical', @@ -1226,7 +1213,6 @@ describe('OptionsListUtils', () => { { title: 'Recent', shouldShow: true, - indexOffset: 1, data: [ { text: 'HR', @@ -1240,7 +1226,6 @@ describe('OptionsListUtils', () => { { title: 'All', shouldShow: true, - indexOffset: 2, // data sorted alphabetically by name data: [ { @@ -1299,7 +1284,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [ { text: 'Accounting', @@ -1322,7 +1306,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [], }, ]; @@ -2088,7 +2071,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: false, - indexOffset: 0, // data sorted alphabetically by name data: [ { @@ -2141,7 +2123,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, // data sorted alphabetically by name data: [ { @@ -2165,7 +2146,6 @@ describe('OptionsListUtils', () => { { title: '', shouldShow: true, - indexOffset: 0, data: [], }, ]; From 049756b984e4918117b5bfa2ffbbd6b8ee04879f Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 22 Feb 2024 15:32:24 +0100 Subject: [PATCH 03/13] Update tests --- tests/perf-test/OptionsSelector.perf-test.js | 14 +++++--------- tests/perf-test/SelectionList.perf-test.js | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/perf-test/OptionsSelector.perf-test.js b/tests/perf-test/OptionsSelector.perf-test.js index 6104ded05c6a..969015ae0fbc 100644 --- a/tests/perf-test/OptionsSelector.perf-test.js +++ b/tests/perf-test/OptionsSelector.perf-test.js @@ -36,21 +36,17 @@ jest.mock('../../src/components/withNavigationFocus', () => (Component) => { }); const generateSections = (sectionConfigs) => - _.map(sectionConfigs, ({numItems, indexOffset, shouldShow = true}) => ({ + _.map(sectionConfigs, ({numItems, shouldShow = true}, index) => ({ data: Array.from({length: numItems}, (_v, i) => ({ - text: `Item ${i + indexOffset}`, - keyForList: `item-${i + indexOffset}`, + text: `Item ${i + index}`, + keyForList: `item-${i + index}`, })), - indexOffset, shouldShow, })); -const singleSectionSConfig = [{numItems: 1000, indexOffset: 0}]; +const singleSectionSConfig = [{numItems: 1000}]; -const mutlipleSectionsConfig = [ - {numItems: 1000, indexOffset: 0}, - {numItems: 100, indexOffset: 70}, -]; +const mutlipleSectionsConfig = [{numItems: 1000}, {numItems: 100}]; function OptionsSelectorWrapper(args) { const sections = generateSections(singleSectionSConfig); diff --git a/tests/perf-test/SelectionList.perf-test.js b/tests/perf-test/SelectionList.perf-test.js index a109f92a1501..4afdca30313f 100644 --- a/tests/perf-test/SelectionList.perf-test.js +++ b/tests/perf-test/SelectionList.perf-test.js @@ -64,7 +64,6 @@ function SelectionListWrapper(args) { keyForList: `item-${i}`, isSelected: _.contains(selectedIds, `item-${i}`), })), - indexOffset: 0, isDisabled: false, }, ]; From 2317ae5055e79e2f1800c1e39fe196ffc6e5418d Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 27 Feb 2024 19:48:44 +0100 Subject: [PATCH 04/13] Refactore code and add new utilit for sections --- src/components/OptionsList/BaseOptionsList.tsx | 7 ++----- src/components/SelectionList/BaseSelectionList.tsx | 8 +++----- src/libs/getSectionsWithIndexOffset.ts | 9 +++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 src/libs/getSectionsWithIndexOffset.ts diff --git a/src/components/OptionsList/BaseOptionsList.tsx b/src/components/OptionsList/BaseOptionsList.tsx index 6e3effc24e90..50e0ce31fcc2 100644 --- a/src/components/OptionsList/BaseOptionsList.tsx +++ b/src/components/OptionsList/BaseOptionsList.tsx @@ -9,6 +9,7 @@ import SectionList from '@components/SectionList'; import Text from '@components/Text'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; +import getSectionsWithIndexOffset from '@libs/getSectionsWithIndexOffset'; import type {OptionData} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import variables from '@styles/variables'; @@ -67,6 +68,7 @@ function BaseOptionsList( const listContainerStyles = useMemo(() => listContainerStylesProp ?? [styles.flex1], [listContainerStylesProp, styles.flex1]); const contentContainerStyles = useMemo(() => [safeAreaPaddingBottomStyle, contentContainerStylesProp], [contentContainerStylesProp, safeAreaPaddingBottomStyle]); + const sectionsWithIndexOffset = getSectionsWithIndexOffset(sections); /** * This helper function is used to memoize the computation needed for getItemLayout. It is run whenever section data changes. @@ -223,11 +225,6 @@ function BaseOptionsList( return ; }; - const sectionsWithIndexOffset = sections.map((section, index) => { - const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + curr.data.length, 0); - return {...section, indexOffset}; - }); - return ( {isLoading ? ( diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index fbaa5f77e9d0..1cb86e58123c 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -18,6 +18,7 @@ import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; +import getSectionsWithIndexOffset from '@libs/getSectionsWithIndexOffset'; import Log from '@libs/Log'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -78,6 +79,8 @@ function BaseSelectionList( const [maxToRenderPerBatch, setMaxToRenderPerBatch] = useState(shouldUseDynamicMaxToRenderPerBatch ? 0 : CONST.MAX_TO_RENDER_PER_BATCH.DEFAULT); const [isInitialSectionListRender, setIsInitialSectionListRender] = useState(true); + const sectionsWithIndexOffset = getSectionsWithIndexOffset(sections); + /** * Iterates through the sections and items inside each section, and builds 3 arrays along the way: * - `allOptions`: Contains all the items in the list, flattened, regardless of section @@ -377,11 +380,6 @@ function BaseSelectionList( isActive: !disableKeyboardShortcuts && isFocused, }); - const sectionsWithIndexOffset = sections.map((section, index) => { - const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + curr.data.length, 0); - return {...section, indexOffset}; - }); - return ( (sections: Array>) { + return sections.map((section, index) => { + const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + curr.data.length, 0); + return {...section, indexOffset}; + }); +} From 279cf4a5db74ecd7abea1787fbcfd8cc231e0af6 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 27 Feb 2024 21:35:01 +0100 Subject: [PATCH 05/13] Update getSectionsWithIndexOffset --- src/libs/getSectionsWithIndexOffset.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/getSectionsWithIndexOffset.ts b/src/libs/getSectionsWithIndexOffset.ts index 522412ab0949..e6c0820374e8 100644 --- a/src/libs/getSectionsWithIndexOffset.ts +++ b/src/libs/getSectionsWithIndexOffset.ts @@ -3,7 +3,7 @@ import type {SectionListData} from 'react-native'; /** Returns a list of sections with IndexOffset */ export default function getSectionsWithIndexOffset(sections: Array>) { return sections.map((section, index) => { - const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + curr.data.length, 0); + const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + (curr.data?.length ?? 0), 0); return {...section, indexOffset}; }); } From 7eb76d666f4e0fbd2c6932cacb36931a4273020c Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 27 Feb 2024 21:39:23 +0100 Subject: [PATCH 06/13] Remove unnecessary code --- src/components/SelectionList/BaseSelectionList.tsx | 1 - src/pages/workspace/categories/WorkspaceCategoriesPage.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 1cb86e58123c..f3d7bc92df13 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -78,7 +78,6 @@ function BaseSelectionList( const isFocused = useIsFocused(); const [maxToRenderPerBatch, setMaxToRenderPerBatch] = useState(shouldUseDynamicMaxToRenderPerBatch ? 0 : CONST.MAX_TO_RENDER_PER_BATCH.DEFAULT); const [isInitialSectionListRender, setIsInitialSectionListRender] = useState(true); - const sectionsWithIndexOffset = getSectionsWithIndexOffset(sections); /** diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 7cd9972a6f57..a41d6158303f 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -128,7 +128,7 @@ function WorkspaceCategoriesPage({policyCategories, route}: WorkspaceCategoriesP {categoryList.length ? ( Date: Wed, 28 Feb 2024 21:19:07 +0100 Subject: [PATCH 07/13] Remove unnecessary code --- src/components/MoneyRequestConfirmationList.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 773e98b6462e..c9d4929e1b48 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -56,7 +56,6 @@ type Option = Partial; type CategorySection = { title: string | undefined; shouldShow: boolean; - indexOffset: number; data: Option[]; }; @@ -386,14 +385,12 @@ function MoneyRequestConfirmationList({ title: translate('moneyRequestConfirmationList.paidBy'), data: [formattedPayeeOption], shouldShow: true, - indexOffset: 0, isDisabled: canModifyParticipantsValue, }, { title: translate('moneyRequestConfirmationList.splitWith'), data: formattedParticipantsList, shouldShow: true, - indexOffset: 1, }, ); } else { @@ -405,7 +402,6 @@ function MoneyRequestConfirmationList({ title: translate('common.to'), data: formattedSelectedParticipants, shouldShow: true, - indexOffset: 0, }); } return sections; From 0db97cfa2c0b4f31c02b1b8a05886516946172c3 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 4 Mar 2024 10:29:37 +0100 Subject: [PATCH 08/13] Remove unnecessary code --- src/components/MoneyRequestConfirmationList.js | 3 --- .../workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx | 2 +- .../workspace/workflows/WorkspaceWorkflowsApproverPage.tsx | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index dfe1d96b0e5d..b3a43cf583ea 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -378,14 +378,12 @@ function MoneyRequestConfirmationList(props) { title: translate('moneyRequestConfirmationList.paidBy'), data: [formattedPayeeOption], shouldShow: true, - indexOffset: 0, isDisabled: shouldDisablePaidBySection, }, { title: translate('moneyRequestConfirmationList.splitWith'), data: formattedParticipantsList, shouldShow: true, - indexOffset: 1, }, ); } else { @@ -397,7 +395,6 @@ function MoneyRequestConfirmationList(props) { title: translate('common.to'), data: formattedSelectedParticipants, shouldShow: true, - indexOffset: 0, }); } return sections; diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx index 84d70e799c42..49c353f8b6aa 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx @@ -83,7 +83,7 @@ function WorkspaceAutoReportingMonthlyOffsetPage({policy}: WorkspaceAutoReportin /> 0, - indexOffset: 0, }); sectionsArray.push({ title: translate('common.all'), data: formattedPolicyMembers, shouldShow: true, - indexOffset: formattedApprover.length, }); return sectionsArray; From 1acf6b24430446f1820f47854a036b94e2fb998b Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 5 Mar 2024 11:04:44 +0100 Subject: [PATCH 09/13] Fix comments --- src/components/OptionsList/BaseOptionsList.tsx | 12 ++++++------ src/components/OptionsList/types.ts | 14 +++++++++----- src/components/SelectionList/BaseSelectionList.tsx | 9 ++++----- src/components/SelectionList/types.ts | 11 +++++++---- src/libs/getSectionsWithIndexOffset.ts | 6 ++++-- src/pages/EditReportFieldDropdownPage.tsx | 1 + 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/components/OptionsList/BaseOptionsList.tsx b/src/components/OptionsList/BaseOptionsList.tsx index 50e0ce31fcc2..436f4c147931 100644 --- a/src/components/OptionsList/BaseOptionsList.tsx +++ b/src/components/OptionsList/BaseOptionsList.tsx @@ -14,7 +14,7 @@ import type {OptionData} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; -import type {BaseOptionListProps, OptionsList, OptionsListData, Section} from './types'; +import type {BaseOptionListProps, OptionsList, OptionsListData, OptionsListDataWithIndexOffset, SectionWithIndexOffset} from './types'; function BaseOptionsList( { @@ -136,7 +136,7 @@ function BaseOptionsList( * [{header}, {sectionHeader}, {item}, {item}, {sectionHeader}, {item}, {item}, {footer}] */ // eslint-disable-next-line @typescript-eslint/naming-convention - const getItemLayout = (_data: OptionsListData[] | null, flatDataArrayIndex: number) => { + const getItemLayout = (_data: OptionsListDataWithIndexOffset[] | null, flatDataArrayIndex: number) => { if (!flattenedData.current[flatDataArrayIndex]) { flattenedData.current = buildFlatSectionArray(); } @@ -164,7 +164,7 @@ function BaseOptionsList( * @return {Component} */ - const renderItem: SectionListRenderItem = ({item, index, section}) => { + const renderItem: SectionListRenderItem = ({item, index, section}) => { const isItemDisabled = isDisabled || !!section.isDisabled || !!item.isDisabled; const isSelected = selectedOptions?.some((option) => { if (option.keyForList && option.keyForList === item.keyForList) { @@ -184,7 +184,7 @@ function BaseOptionsList( option={item} showTitleTooltip={showTitleTooltip} hoverStyle={optionHoveredStyle} - optionIsFocused={!disableFocusOptions && !isItemDisabled && focusedIndex === index + (section.indexOffset ?? 0)} + optionIsFocused={!disableFocusOptions && !isItemDisabled && focusedIndex === index + section.indexOffset} onSelectRow={onSelectRow} isSelected={isSelected} showSelectedState={canSelectMultipleOptions} @@ -205,7 +205,7 @@ function BaseOptionsList( /** * Function which renders a section header component */ - const renderSectionHeader = ({section: {title, shouldShow}}: {section: OptionsListData}) => { + const renderSectionHeader = ({section: {title, shouldShow}}: {section: OptionsListDataWithIndexOffset}) => { if (!title && shouldShow && !hideSectionHeaders && sectionHeaderStyle) { return ; } @@ -238,7 +238,7 @@ function BaseOptionsList( {headerMessage} ) : null} - + ref={ref} style={listStyles} indicatorStyle="white" diff --git a/src/components/OptionsList/types.ts b/src/components/OptionsList/types.ts index c8c117d800e4..9d7ed8ecf362 100644 --- a/src/components/OptionsList/types.ts +++ b/src/components/OptionsList/types.ts @@ -2,16 +2,15 @@ import type {RefObject} from 'react'; import type {SectionList, SectionListData, StyleProp, View, ViewStyle} from 'react-native'; import type {OptionData} from '@libs/ReportUtils'; -type OptionsList = SectionList; type OptionsListData = SectionListData; +type OptionsListDataWithIndexOffset = SectionListData; + +type OptionsList = SectionList; type Section = { /** Title of the section */ title: string; - /** The initial index of this section given the total number of options in each section's data array */ - indexOffset?: number; - /** Array of options */ data: OptionData[]; @@ -22,6 +21,11 @@ type Section = { isDisabled?: boolean; }; +type SectionWithIndexOffset = Section & { + /** The initial index of this section given the total number of options in each section's data array */ + indexOffset: number; +}; + type OptionsListProps = { /** option flexStyle for the options list container */ listContainerStyles?: StyleProp; @@ -134,4 +138,4 @@ type BaseOptionListProps = OptionsListProps & { listStyles?: StyleProp; }; -export type {OptionsListProps, BaseOptionListProps, Section, OptionsList, OptionsListData}; +export type {OptionsListProps, BaseOptionListProps, Section, OptionsList, OptionsListData, SectionWithIndexOffset, OptionsListDataWithIndexOffset}; diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 920716b230fc..0adb23115b15 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -22,7 +22,7 @@ import Log from '@libs/Log'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import type {BaseSelectionListProps, ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, Section, SectionListDataType} from './types'; +import type {BaseSelectionListProps, ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, SectionListDataType, SectionWithIndexOffset} from './types'; function BaseSelectionList( { @@ -70,7 +70,7 @@ function BaseSelectionList( ) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const listRef = useRef>>(null); + const listRef = useRef>>(null); const textInputRef = useRef(null); const focusTimeoutRef = useRef(null); const shouldShowTextInput = !!textInputLabel; @@ -276,9 +276,8 @@ function BaseSelectionList( ); }; - const renderItem = ({item, index, section}: SectionListRenderItemInfo>) => { - const indexOffset = section.indexOffset ? section.indexOffset : 0; - const normalizedIndex = index + indexOffset; + const renderItem = ({item, index, section}: SectionListRenderItemInfo>) => { + const normalizedIndex = index + section.indexOffset; const isDisabled = !!section.isDisabled || item.isDisabled; const isItemFocused = !isDisabled && focusedIndex === normalizedIndex; // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 005a8ab21cc1..440ea31a97e8 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -143,9 +143,6 @@ type Section = { /** Title of the section */ title?: string; - /** The initial index of this section given the total number of options in each section's data array */ - indexOffset?: number; - /** Array of options */ data?: TItem[]; @@ -156,6 +153,11 @@ type Section = { shouldShow?: boolean; }; +type SectionWithIndexOffset = Section & { + /** The initial index of this section given the total number of options in each section's data array */ + indexOffset: number; +}; + type BaseSelectionListProps = Partial & { /** Sections for the section list */ sections: Array>>; @@ -293,12 +295,13 @@ type FlattenedSectionsReturn = { type ButtonOrCheckBoxRoles = 'button' | 'checkbox'; -type SectionListDataType = SectionListData>; +type SectionListDataType = SectionListData>; export type { BaseSelectionListProps, CommonListItemProps, Section, + SectionWithIndexOffset, BaseListItemProps, UserListItemProps, RadioListItemProps, diff --git a/src/libs/getSectionsWithIndexOffset.ts b/src/libs/getSectionsWithIndexOffset.ts index e6c0820374e8..7de78d048a4d 100644 --- a/src/libs/getSectionsWithIndexOffset.ts +++ b/src/libs/getSectionsWithIndexOffset.ts @@ -1,7 +1,9 @@ import type {SectionListData} from 'react-native'; -/** Returns a list of sections with IndexOffset */ -export default function getSectionsWithIndexOffset(sections: Array>) { +/** + * Returns a list of sections with indexOffset + */ +export default function getSectionsWithIndexOffset(sections: Array>): Array> { return sections.map((section, index) => { const indexOffset = [...sections].splice(0, index).reduce((acc, curr) => acc + (curr.data?.length ?? 0), 0); return {...section, indexOffset}; diff --git a/src/pages/EditReportFieldDropdownPage.tsx b/src/pages/EditReportFieldDropdownPage.tsx index 1ad63bb2bf2f..e8f1d97494af 100644 --- a/src/pages/EditReportFieldDropdownPage.tsx +++ b/src/pages/EditReportFieldDropdownPage.tsx @@ -92,6 +92,7 @@ function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, textInputLabel={translate('common.search')} boldStyle sections={sections} + // Focus the first option when searching focusedIndex={0} value={searchValue} onSelectRow={(option: Record) => onSubmit({[fieldID]: option.text})} From 7d67f31369e367a20f5a2135269ad2b668e5c383 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 5 Mar 2024 11:11:28 +0100 Subject: [PATCH 10/13] Remove unnecessary code --- src/pages/workspace/tags/WorkspaceTagsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index c82740eff361..7d9ceac74203 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -113,7 +113,7 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { {tagList.length ? ( {}} onSelectAll={toggleAllTags} From 826fbec3b44a74bc6d6b83dabcb8457f252314e7 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Fri, 15 Mar 2024 20:30:02 +0100 Subject: [PATCH 11/13] Update stories --- src/stories/SelectionList.stories.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/stories/SelectionList.stories.tsx b/src/stories/SelectionList.stories.tsx index 92936d6d73a3..11be5e2e3bad 100644 --- a/src/stories/SelectionList.stories.tsx +++ b/src/stories/SelectionList.stories.tsx @@ -40,7 +40,6 @@ const SECTIONS = [ isSelected: false, }, ], - indexOffset: 0, isDisabled: false, }, { @@ -61,7 +60,6 @@ const SECTIONS = [ isSelected: false, }, ], - indexOffset: 3, isDisabled: false, }, ]; @@ -71,7 +69,7 @@ function Default(props: BaseSelectionListProps) { const sections = props.sections.map((section) => { const data = section.data.map((item, index) => { - const isSelected = selectedIndex === index + (section?.indexOffset ?? 0); + const isSelected = selectedIndex === index; return {...item, isSelected}; }); @@ -83,7 +81,7 @@ function Default(props: BaseSelectionListProps) { const newSelectedIndex = section.data.findIndex((option) => option.keyForList === item.keyForList); if (newSelectedIndex >= 0) { - setSelectedIndex(newSelectedIndex + (section?.indexOffset ?? 0)); + setSelectedIndex(newSelectedIndex); } }); }; @@ -115,7 +113,7 @@ function WithTextInput(props: BaseSelectionListProps) { return memo; } - const isSelected = selectedIndex === index + (section?.indexOffset ?? 0); + const isSelected = selectedIndex === index; memo.push({...item, isSelected}); return memo; }, []); @@ -128,7 +126,7 @@ function WithTextInput(props: BaseSelectionListProps) { const newSelectedIndex = section.data.findIndex((option) => option.keyForList === item.keyForList); if (newSelectedIndex >= 0) { - setSelectedIndex(newSelectedIndex + (section?.indexOffset ?? 0)); + setSelectedIndex(newSelectedIndex); } }); }; @@ -177,7 +175,7 @@ function WithAlternateText(props: BaseSelectionListProps) { const sections = props.sections.map((section) => { const data = section.data.map((item, index) => { - const isSelected = selectedIndex === index + (section?.indexOffset ?? 0); + const isSelected = selectedIndex === index; return { ...item, @@ -194,7 +192,7 @@ function WithAlternateText(props: BaseSelectionListProps) { const newSelectedIndex = section.data.findIndex((option) => option.keyForList === item.keyForList); if (newSelectedIndex >= 0) { - setSelectedIndex(newSelectedIndex + (section?.indexOffset ?? 0)); + setSelectedIndex(newSelectedIndex); } }); }; @@ -225,7 +223,7 @@ function MultipleSelection(props: BaseSelectionListProps) { allIds.push(item.keyForList); } const isSelected = item.keyForList ? selectedIds.includes(item.keyForList) : false; - const isAdmin = index + (section?.indexOffset ?? 0) === 0; + const isAdmin = index === 0; return { ...item, @@ -295,7 +293,7 @@ function WithSectionHeader(props: BaseSelectionListProps) { allIds.push(item.keyForList); } const isSelected = item.keyForList ? selectedIds.includes(item.keyForList) : false; - const isAdmin = itemIndex + (section?.indexOffset ?? 0) === 0; + const isAdmin = itemIndex === 0; return { ...item, @@ -363,7 +361,7 @@ function WithConfirmButton(props: BaseSelectionListProps) { allIds.push(item.keyForList); } const isSelected = item.keyForList ? selectedIds.includes(item.keyForList) : false; - const isAdmin = itemIndex + (section.indexOffset ?? 0) === 0; + const isAdmin = itemIndex === 0; return { ...item, From ff625d2f11f36289955d67a47d50abebd3725200 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Tue, 19 Mar 2024 00:22:39 +0100 Subject: [PATCH 12/13] Fix lint issues --- tests/perf-test/OptionsSelector.perf-test.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/perf-test/OptionsSelector.perf-test.tsx b/tests/perf-test/OptionsSelector.perf-test.tsx index 9b45744cba8b..44dc4ac6c317 100644 --- a/tests/perf-test/OptionsSelector.perf-test.tsx +++ b/tests/perf-test/OptionsSelector.perf-test.tsx @@ -51,10 +51,7 @@ const generateSections = (sections: GenerateSectionsProps) => const singleSectionsConfig = [{numberOfItems: 1000}]; -const mutlipleSectionsConfig = [ - {numberOfItems: 1000}, - {numberOfItems: 100}, -]; +const mutlipleSectionsConfig = [{numberOfItems: 1000}, {numberOfItems: 100}]; // @ts-expect-error TODO: Remove this once OptionsSelector is migrated to TypeScript. function OptionsSelectorWrapper(args) { const sections = generateSections(singleSectionsConfig); From 83c4c31b2605ae7d908033a5361a80e23cce33fb Mon Sep 17 00:00:00 2001 From: Yauheni Date: Mon, 25 Mar 2024 22:45:15 +0100 Subject: [PATCH 13/13] Fix comments --- src/components/OptionsList/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/OptionsList/types.ts b/src/components/OptionsList/types.ts index 9d7ed8ecf362..b7180e6281b4 100644 --- a/src/components/OptionsList/types.ts +++ b/src/components/OptionsList/types.ts @@ -4,7 +4,6 @@ import type {OptionData} from '@libs/ReportUtils'; type OptionsListData = SectionListData; type OptionsListDataWithIndexOffset = SectionListData; - type OptionsList = SectionList; type Section = {