From 07f1d81beacec427f390c5301982ca2ac88371a2 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 31 Dec 2025 17:42:00 +0100 Subject: [PATCH 01/40] Remove Onyx.connect() for the key: ONYXKEYS.COLLECTION.REPORT in src/libs/OptionsListUtils.ts --- .../LHNOptionsList/LHNOptionsList.tsx | 1 + src/components/OptionListContextProvider.tsx | 3 +- .../Search/SearchFiltersChatsSelector.tsx | 4 +- .../Search/SearchRouter/SearchRouter.tsx | 3 +- src/libs/OptionsListUtils/index.ts | 86 +++++++++-------- src/libs/SidebarUtils.ts | 4 +- tests/unit/OptionsListUtilsTest.tsx | 93 +++++++++++++++++++ 7 files changed, 152 insertions(+), 42 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 27c6ebf2daa5..02e92e32bab2 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -233,6 +233,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio policy: itemPolicy, isReportArchived: !!itemReportNameValuePairs?.private_isArchived, policyForMovingExpensesID, + chatReport, }); const shouldShowRBRorGBRTooltip = firstReportIDWithGBRorRBR === reportID; diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 3a108beef173..23c9931f67f0 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -215,7 +215,8 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { continue; } - const newReportOption = createOptionFromReport(report, personalDetails, reportAttributes?.reports, {showPersonalDetails: true}); + const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const newReportOption = createOptionFromReport(report, personalDetails, reportAttributes?.reports, {showPersonalDetails: true}, chatReport); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); newReportOptions.push({ newReportOption, diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 2d8f438aeb86..920485faaf1a 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -63,7 +63,9 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const selectedOptions = useMemo(() => { return selectedReportIDs.map((id) => { - const report = getSelectedOptionData(createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails, reportAttributesDerived)); + const reportData = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]; + const chatReport = reportData?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportData.chatReportID}`] : undefined; + const report = getSelectedOptionData(createOptionFromReport({...reportData, reportID: id}, personalDetails, reportAttributesDerived, undefined, chatReport)); const isReportArchived = archivedReportsIdSet.has(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`); const alternateText = getAlternateText(report, {}, isReportArchived, {}); return {...report, alternateText}; diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 8f547047cb0e..d639fe4af813 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -156,7 +156,8 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla return undefined; } - const option = createOptionFromReport(report, personalDetails, undefined, {showPersonalDetails: true}); + const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const option = createOptionFromReport(report, personalDetails, undefined, {showPersonalDetails: true}, chatReport); reportForContextualSearch = option; } diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index ad5d5a36e8c9..92f5973f2134 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -223,15 +223,6 @@ Onyx.connect({ callback: (val) => (allPolicies = val), }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => { - allReports = value; - }, -}); - let allReportNameValuePairs: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, @@ -265,8 +256,8 @@ Onyx.connect({ const reportActionsArray = Object.values(reportActions[1] ?? {}); let sortedReportActions = getSortedReportActions(withDEWRoutedActionsArray(reportActionsArray), true); allSortedReportActions[reportID] = sortedReportActions; - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; + const report = getReportOrDraftReport(reportID); + const chatReport = getReportOrDraftReport(report?.chatReportID); // If the report is a one-transaction report and has , we need to return the combined reportActions so that the LHN can display modifications // to the transaction thread or the report itself @@ -464,12 +455,13 @@ function getAlternateText( lastActorDetails: Partial | null = {}, ) { const report = getReportOrDraftReport(option.reportID); + const chatReport = getReportOrDraftReport(report?.chatReportID); const isAdminRoom = reportUtilsIsAdminRoom(report); const isAnnounceRoom = reportUtilsIsAnnounceRoom(report); const isGroupChat = reportUtilsIsGroupChat(report); const isExpenseThread = isMoneyRequest(report); const formattedLastMessageText = - formatReportLastMessageText(Parser.htmlToText(option.lastMessageText ?? '')) || getLastMessageTextForReport({report, lastActorDetails, isReportArchived}); + formatReportLastMessageText(Parser.htmlToText(option.lastMessageText ?? '')) || getLastMessageTextForReport({report, lastActorDetails, isReportArchived, chatReport}); const reportPrefix = getReportSubtitlePrefix(report); const formattedLastMessageTextWithPrefix = reportPrefix + formattedLastMessageText; @@ -597,6 +589,7 @@ function getLastMessageTextForReport({ policy, isReportArchived = false, policyForMovingExpensesID, + chatReport, }: { report: OnyxEntry; lastActorDetails: Partial | null; @@ -605,6 +598,7 @@ function getLastMessageTextForReport({ policy?: OnyxEntry; isReportArchived?: boolean; policyForMovingExpensesID?: string; + chatReport?: OnyxEntry; }): string { const reportID = report?.reportID; const lastReportAction = reportID ? lastVisibleReportActions[reportID] : undefined; @@ -803,7 +797,6 @@ function getLastMessageTextForReport({ } if (reportID && !lastMessageTextFromReport && lastReportAction) { - const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; // If the report is a one-transaction report, get the last message text from combined report actions so the LHN can display modifications to the transaction thread or the report itself const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, allSortedReportActions[reportID]); if (transactionThreadReportID) { @@ -833,6 +826,7 @@ function createOption( report: OnyxInputOrEntry, config?: PreviewConfig, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], + chatReport?: OnyxEntry, ): SearchOptionData { const {showChatPreviewLine = false, forcePolicyNamePreview = false, showPersonalDetails = false, selected, isSelected, isDisabled} = config ?? {}; @@ -907,14 +901,14 @@ function createOption( // If displaying chat preview line is needed, let's overwrite the default alternate text const lastActorDetails = personalDetails?.[report?.lastActorAccountID ?? String(CONST.DEFAULT_NUMBER_ID)] ?? {}; - result.lastMessageText = getLastMessageTextForReport({report, lastActorDetails, isReportArchived: !!result.private_isArchived}); + result.lastMessageText = getLastMessageTextForReport({report, lastActorDetails, isReportArchived: !!result.private_isArchived, chatReport}); result.alternateText = showPersonalDetails && personalDetail?.login ? personalDetail.login : getAlternateText(result, {showChatPreviewLine, forcePolicyNamePreview}, !!result.private_isArchived, lastActorDetails); const personalDetailsForCompute: PersonalDetailsList | undefined = personalDetails ?? undefined; - const computedReportName = computeReportName(report, allReports, allPolicies, undefined, allReportNameValuePairs, personalDetailsForCompute, allReportActions); + const computedReportName = computeReportName(report, undefined, allPolicies, undefined, allReportNameValuePairs, personalDetailsForCompute, allReportActions); reportName = showPersonalDetails ? getDisplayNameForParticipant({accountID: accountIDs.at(0), formatPhoneNumber: formatPhoneNumberPhoneUtils}) || formatPhoneNumberPhoneUtils(personalDetail?.login ?? '') : computedReportName; @@ -1171,6 +1165,7 @@ function processReport( report: OnyxEntry | null, personalDetails: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], + chatReport?: OnyxEntry, ): { reportMapEntry?: [number, Report]; // The entry to add to reportMapForAccountIDs if applicable reportOption: SearchOption | null; // The report option to add to allReportOptions if applicable @@ -1194,7 +1189,7 @@ function processReport( reportMapEntry, reportOption: { item: report, - ...createOption(accountIDs, personalDetails, report, undefined, reportAttributesDerived), + ...createOption(accountIDs, personalDetails, report, undefined, reportAttributesDerived, chatReport), }, }; } @@ -1207,7 +1202,8 @@ function createOptionList(personalDetails: OnyxEntry, repor if (reports) { for (const report of Object.values(reports)) { - const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived); + const chatReport = report?.chatReportID ? reports[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived, chatReport); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1220,18 +1216,23 @@ function createOptionList(personalDetails: OnyxEntry, repor } } - const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => ({ - item: personalDetail, - ...createOption( - [personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], - personalDetails, - reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], - { - showPersonalDetails: true, - }, - reportAttributesDerived, - ), - })); + const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => { + const mappedReport = reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID]; + const chatReport = mappedReport?.chatReportID && reports ? reports[`${ONYXKEYS.COLLECTION.REPORT}${mappedReport.chatReportID}`] : undefined; + return { + item: personalDetail, + ...createOption( + [personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], + personalDetails, + mappedReport, + { + showPersonalDetails: true, + }, + reportAttributesDerived, + chatReport, + ), + }; + }); span.setAttributes({ personalDetails: allPersonalDetailsOptions.length, @@ -1317,7 +1318,8 @@ function createFilteredOptionList( // Step 5: Process the limited set of reports (performance optimization) const reportOptions: Array> = []; for (const report of limitedReports) { - const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived); + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived, chatReport); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1344,10 +1346,12 @@ function createFilteredOptionList( const personalDetailsOptions = includeP2P ? Object.values(personalDetails ?? {}).map((personalDetail) => { const accountID = personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID; + const mappedReport = reportMapForAccountIDs[accountID]; + const chatReport = mappedReport?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${mappedReport.chatReportID}`] : undefined; return { item: personalDetail, - ...createOption([accountID], personalDetails, reportMapForAccountIDs[accountID], {showPersonalDetails: true}, reportAttributesDerived), + ...createOption([accountID], personalDetails, mappedReport, {showPersonalDetails: true}, reportAttributesDerived, chatReport), }; }) : []; @@ -1358,12 +1362,18 @@ function createFilteredOptionList( }; } -function createOptionFromReport(report: Report, personalDetails: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], config?: PreviewConfig) { +function createOptionFromReport( + report: Report, + personalDetails: OnyxEntry, + reportAttributesDerived?: ReportAttributesDerivedValue['reports'], + config?: PreviewConfig, + chatReport?: OnyxEntry, +) { const accountIDs = getParticipantsAccountIDsForDisplay(report); return { item: report, - ...createOption(accountIDs, personalDetails, report, config, reportAttributesDerived), + ...createOption(accountIDs, personalDetails, report, config, reportAttributesDerived, chatReport), }; } @@ -1798,7 +1808,7 @@ function getUserToInviteContactOption({ return userToInvite; } -function isValidReport(option: SearchOption, config: IsValidReportsConfig, draftComment: string | undefined): boolean { +function isValidReport(option: SearchOption, config: IsValidReportsConfig, draftComment: string | undefined, chatReport?: OnyxEntry): boolean { const { betas = [], includeMultipleParticipantReports = false, @@ -1819,8 +1829,6 @@ function isValidReport(option: SearchOption, config: IsValidReportsConfi preferredPolicyID, } = config; const topmostReportId = Navigation.getTopmostReportId(); - - const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${option.item.chatReportID}`]; const doesReportHaveViolations = shouldDisplayViolationsRBRInLHN(option.item, transactionViolations); const shouldBeInOptionList = shouldReportBeInOptionList({ @@ -1973,12 +1981,12 @@ function prepareReportOptionsForDisplay(options: Array>, co let isOptionUnread = option.isUnread; if (shouldUnreadBeBold) { - const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`]; + const chatReport = getReportOrDraftReport(report.chatReportID); const oneTransactionThreadReportID = report.type === CONST.REPORT.TYPE.IOU || report.type === CONST.REPORT.TYPE.EXPENSE || report.type === CONST.REPORT.TYPE.INVOICE ? getOneTransactionThreadReportID(report, chatReport, allSortedReportActions[report.reportID]) : undefined; - const oneTransactionThreadReport = oneTransactionThreadReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneTransactionThreadReportID}`] : undefined; + const oneTransactionThreadReport = oneTransactionThreadReportID ? getReportOrDraftReport(oneTransactionThreadReportID) : undefined; isOptionUnread = isUnread(report, oneTransactionThreadReport, !!option.private_isArchived) && !!report.lastActorAccountID; } @@ -2154,6 +2162,7 @@ function getValidOptions( } const draftComment = draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${report.reportID}`]; + const chatReport = getReportOrDraftReport(report.item.chatReportID); return isValidReport( report, @@ -2164,6 +2173,7 @@ function getValidOptions( loginsToExclude, }, draftComment, + chatReport, ); }; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index ead6cb601e8e..8c59122df29e 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -109,6 +109,7 @@ import { // eslint-disable-next-line @typescript-eslint/no-deprecated getReportName, getReportNotificationPreference, + getReportOrDraftReport, getReportParticipantsTitle, getReportSubtitlePrefix, getUnreportedTransactionMessage, @@ -792,7 +793,8 @@ function getOptionData({ const lastActorDisplayName = getLastActorDisplayName(lastActorDetails); let lastMessageTextFromReport = lastMessageTextFromReportProp; if (!lastMessageTextFromReport) { - lastMessageTextFromReport = getLastMessageTextForReport({report, lastActorDetails, movedFromReport, movedToReport, policy, isReportArchived}); + const chatReport = getReportOrDraftReport(report?.chatReportID); + lastMessageTextFromReport = getLastMessageTextForReport({report, lastActorDetails, movedFromReport, movedToReport, policy, isReportArchived, chatReport}); } // We need to remove sms domain in case the last message text has a phone number mention with sms domain. diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index e4dfa68ebdf3..a2ebc9de4144 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -2874,4 +2874,97 @@ describe('OptionsListUtils', () => { expect(searchTerms2.includes(displayName)).toBe(true); }); }); + + describe('getLastMessageTextForReport with chatReport parameter', () => { + it('should work correctly when chatReport is passed', async () => { + const chatReportID = '999'; + + const report: Report = { + ...createRandomReport(0, undefined), + chatReportID, + type: CONST.REPORT.TYPE.EXPENSE, + }; + + const chatReport: Report = { + ...createRandomReport(1, undefined), + reportID: chatReportID, + }; + + // Test that the function works without crashing when chatReport is passed + const result = getLastMessageTextForReport({ + report, + lastActorDetails: null, + isReportArchived: false, + chatReport, + }); + + // The function should return a string (may be empty string) + expect(typeof result).toBe('string'); + }); + + it('should work correctly when chatReport is undefined', async () => { + const report: Report = { + ...createRandomReport(0, undefined), + type: CONST.REPORT.TYPE.CHAT, + }; + + const result = getLastMessageTextForReport({ + report, + lastActorDetails: null, + isReportArchived: false, + chatReport: undefined, + }); + + expect(typeof result).toBe('string'); + }); + }); + + describe('createOption with chatReport parameter', () => { + it('should work correctly when chatReport is passed', async () => { + const reportID = '123'; + const chatReportID = '456'; + + const report: Report = { + ...createRandomReport(0, undefined), + reportID, + chatReportID, + participants: { + 1: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, + }; + + const chatReport: Report = { + ...createRandomReport(1, undefined), + reportID: chatReportID, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); + await waitForBatchedUpdates(); + + const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, chatReport); + + expect(result.reportID).toBe(reportID); + expect(typeof result.text).toBe('string'); + }); + + it('should work correctly when chatReport is undefined', async () => { + const report: Report = { + ...createRandomReport(0, undefined), + participants: { + 1: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); + await waitForBatchedUpdates(); + + // Should not throw when chatReport is undefined + const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, undefined); + + expect(result.reportID).toBe(report.reportID); + }); + }); }); From 687ab58a5459d851ca4d32933da5f22ade820575 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Fri, 16 Jan 2026 15:21:09 +0100 Subject: [PATCH 02/40] fixing eslint warning --- src/components/LHNOptionsList/LHNOptionsList.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 89515c0bd764..b1216aa08cc4 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -10,7 +10,6 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {BlockingViewProps} from '@components/BlockingViews/BlockingView'; import BlockingView from '@components/BlockingViews/BlockingView'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; import TextBlock from '@components/TextBlock'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -56,7 +55,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio const flashListRef = useRef>(null); const route = useRoute(); const isScreenFocused = useIsFocused(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['MagnifyingGlass']); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['MagnifyingGlass', 'Plus']); const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: false}); const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {selector: reportsSelector, canBeMissing: true}); @@ -137,7 +136,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio text={translate('common.emptyLHN.subtitleText2')} /> Date: Fri, 16 Jan 2026 16:10:42 +0100 Subject: [PATCH 03/40] fix: pass reports collection to computeReportName for proper name resolution --- src/components/OptionListContextProvider.tsx | 3 +-- .../Search/SearchFiltersChatsSelector.tsx | 3 +-- .../Search/SearchRouter/SearchRouter.tsx | 3 +-- src/libs/OptionsListUtils/index.ts | 25 ++++++++----------- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 0975b347ed1f..aed16f77caf0 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -215,8 +215,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { continue; } - const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; - const newReportOption = createOptionFromReport(report, personalDetails, reportAttributes?.reports, {showPersonalDetails: true}, chatReport); + const newReportOption = createOptionFromReport(report, personalDetails, reportAttributes?.reports, {showPersonalDetails: true}, reports); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); newReportOptions.push({ newReportOption, diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 920485faaf1a..73ef1bd282cf 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -64,8 +64,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const selectedOptions = useMemo(() => { return selectedReportIDs.map((id) => { const reportData = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]; - const chatReport = reportData?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportData.chatReportID}`] : undefined; - const report = getSelectedOptionData(createOptionFromReport({...reportData, reportID: id}, personalDetails, reportAttributesDerived, undefined, chatReport)); + const report = getSelectedOptionData(createOptionFromReport({...reportData, reportID: id}, personalDetails, reportAttributesDerived, undefined, reports)); const isReportArchived = archivedReportsIdSet.has(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`); const alternateText = getAlternateText(report, {}, isReportArchived, {}); return {...report, alternateText}; diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index a81c22c931d7..b3df97d4bcd4 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -156,8 +156,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla return undefined; } - const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; - const option = createOptionFromReport(report, personalDetails, undefined, {showPersonalDetails: true}, chatReport); + const option = createOptionFromReport(report, personalDetails, undefined, {showPersonalDetails: true}, reports); reportForContextualSearch = option; } diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index dc1e0716c708..22a57595622f 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -864,9 +864,10 @@ function createOption( report: OnyxInputOrEntry, config?: PreviewConfig, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], - chatReport?: OnyxEntry, + reports?: OnyxCollection, ): SearchOptionData { const {showChatPreviewLine = false, forcePolicyNamePreview = false, showPersonalDetails = false, selected, isSelected, isDisabled} = config ?? {}; + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; // Initialize only the properties that are actually used in SearchOption context const result: SearchOptionData = { @@ -947,7 +948,7 @@ function createOption( : getAlternateText(result, {showChatPreviewLine, forcePolicyNamePreview}, !!result.private_isArchived, lastActorDetails); const personalDetailsForCompute: PersonalDetailsList | undefined = personalDetails ?? undefined; - const computedReportName = computeReportName(report, undefined, allPolicies, undefined, allReportNameValuePairs, personalDetailsForCompute, allReportActions); + const computedReportName = computeReportName(report, reports, allPolicies, undefined, allReportNameValuePairs, personalDetailsForCompute, allReportActions); reportName = showPersonalDetails ? getDisplayNameForParticipant({accountID: accountIDs.at(0), formatPhoneNumber: formatPhoneNumberPhoneUtils}) || formatPhoneNumberPhoneUtils(personalDetail?.login ?? '') : computedReportName; @@ -1208,7 +1209,7 @@ function processReport( report: OnyxEntry | null, personalDetails: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], - chatReport?: OnyxEntry, + reports?: OnyxCollection, ): { reportMapEntry?: [number, Report]; // The entry to add to reportMapForAccountIDs if applicable reportOption: SearchOption | null; // The report option to add to allReportOptions if applicable @@ -1232,7 +1233,7 @@ function processReport( reportMapEntry, reportOption: { item: report, - ...createOption(accountIDs, personalDetails, report, undefined, reportAttributesDerived, chatReport), + ...createOption(accountIDs, personalDetails, report, undefined, reportAttributesDerived, reports), }, }; } @@ -1245,8 +1246,7 @@ function createOptionList(personalDetails: OnyxEntry, repor if (reports) { for (const report of Object.values(reports)) { - const chatReport = report?.chatReportID ? reports[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; - const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived, chatReport); + const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived, reports); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1261,7 +1261,6 @@ function createOptionList(personalDetails: OnyxEntry, repor const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => { const mappedReport = reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID]; - const chatReport = mappedReport?.chatReportID && reports ? reports[`${ONYXKEYS.COLLECTION.REPORT}${mappedReport.chatReportID}`] : undefined; return { item: personalDetail, ...createOption( @@ -1272,7 +1271,7 @@ function createOptionList(personalDetails: OnyxEntry, repor showPersonalDetails: true, }, reportAttributesDerived, - chatReport, + reports, ), }; }); @@ -1361,8 +1360,7 @@ function createFilteredOptionList( // Step 5: Process the limited set of reports (performance optimization) const reportOptions: Array> = []; for (const report of limitedReports) { - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; - const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived, chatReport); + const {reportMapEntry, reportOption} = processReport(report, personalDetails, reportAttributesDerived, reports); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1390,11 +1388,10 @@ function createFilteredOptionList( ? Object.values(personalDetails ?? {}).map((personalDetail) => { const accountID = personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID; const mappedReport = reportMapForAccountIDs[accountID]; - const chatReport = mappedReport?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${mappedReport.chatReportID}`] : undefined; return { item: personalDetail, - ...createOption([accountID], personalDetails, mappedReport, {showPersonalDetails: true}, reportAttributesDerived, chatReport), + ...createOption([accountID], personalDetails, mappedReport, {showPersonalDetails: true}, reportAttributesDerived, reports), }; }) : []; @@ -1410,13 +1407,13 @@ function createOptionFromReport( personalDetails: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], config?: PreviewConfig, - chatReport?: OnyxEntry, + reports?: OnyxCollection, ) { const accountIDs = getParticipantsAccountIDsForDisplay(report); return { item: report, - ...createOption(accountIDs, personalDetails, report, config, reportAttributesDerived, chatReport), + ...createOption(accountIDs, personalDetails, report, config, reportAttributesDerived, reports), }; } From 5cc558b1a7a64d4515a1b5cbc9ec78509c2ae5e7 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Fri, 16 Jan 2026 16:15:30 +0100 Subject: [PATCH 04/40] minor ts fix --- src/components/LHNOptionsList/LHNOptionsList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index b1216aa08cc4..bc8ec6179f44 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -174,7 +174,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio const reportID = item.reportID; const itemParentReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.parentReportID}`]; const itemReportNameValuePairs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`]; - const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.chatReportID}`]; + const chatReport: OnyxEntry = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.chatReportID}`]; const itemReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; const itemOneTransactionThreadReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getOneTransactionThreadReportID(item, chatReport, itemReportActions, isOffline)}`]; const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${item?.parentReportID}`]; From b7fd95cc49450bec5e8455ecaa060f69332b0bc2 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Fri, 16 Jan 2026 17:21:09 +0100 Subject: [PATCH 05/40] minor fix --- tests/unit/OptionsListUtilsTest.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index dae309e34453..405599ad24e8 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -2616,7 +2616,7 @@ describe('OptionsListUtils', () => { expect(result.alternateText).toBe('Iron Man owes ₫34'); }); - it('should work correctly when chatReport is passed', async () => { + it('should work correctly when reports collection with chatReport is passed', async () => { const reportID = '123'; const chatReportID = '456'; @@ -2635,17 +2635,22 @@ describe('OptionsListUtils', () => { reportID: chatReportID, }; + const reports = { + [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: report, + [`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]: chatReport, + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); - const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, chatReport); + const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, reports); expect(result.reportID).toBe(reportID); expect(typeof result.text).toBe('string'); }); - it('should work correctly when chatReport is undefined', async () => { + it('should work correctly when reports is undefined', async () => { const report: Report = { ...createRandomReport(0, undefined), participants: { @@ -2657,7 +2662,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); await waitForBatchedUpdates(); - // Should not throw when chatReport is undefined + // Should not throw when reports is undefined const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, undefined); expect(result.reportID).toBe(report.reportID); From 060aea4f9d79a03e6653374c8fcf2b064d479336 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 12:40:37 +0100 Subject: [PATCH 06/40] minor refactoring --- src/components/LHNOptionsList/LHNOptionsList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 626273b09e43..786d7946161a 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -178,7 +178,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio const reportID = item.reportID; const itemParentReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.parentReportID}`]; const itemReportNameValuePairs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`]; - const chatReport: OnyxEntry = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.chatReportID}`]; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.chatReportID}`]; const itemReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; const itemOneTransactionThreadReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getOneTransactionThreadReportID(item, chatReport, itemReportActions, isOffline)}`]; const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${item?.parentReportID}`]; From fe4c126ea60eb22099dc767a068a730367953ea7 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 12:57:51 +0100 Subject: [PATCH 07/40] fixing ts --- src/components/OptionListContextProvider.tsx | 2 +- src/components/Search/SearchRouter/SearchRouter.tsx | 2 +- tests/unit/OptionsListUtilsTest.tsx | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index f846df6fe0d2..bb5eabed12a0 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -218,7 +218,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { continue; } - const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reportAttributes?.reports, {showPersonalDetails: true}, reports); + const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reportAttributes?.reports, {showPersonalDetails: true}, {}, reports); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); newReportOptions.push({ newReportOption, diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 9346f4ff2a40..0515ee06d4fb 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -112,7 +112,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla return undefined; } - const option = createOptionFromReport(report, personalDetails, currentUserAccountID, undefined, {showPersonalDetails: true}, reports); + const option = createOptionFromReport(report, personalDetails, currentUserAccountID, undefined, {showPersonalDetails: true}, {}, reports); reportForContextualSearch = option; } diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 1c41901bcc01..f59eb63faaa5 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -3214,7 +3214,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); - const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, undefined, reports); + const result = createOption([1, 2], PERSONAL_DETAILS, report, 1, undefined, undefined, undefined, reports); expect(result.reportID).toBe(reportID); expect(typeof result.text).toBe('string'); @@ -3233,7 +3233,7 @@ describe('OptionsListUtils', () => { await waitForBatchedUpdates(); // Should not throw when reports is undefined - const result = createOption([1, 2], PERSONAL_DETAILS, report, undefined, undefined, undefined); + const result = createOption([1, 2], PERSONAL_DETAILS, report, 1, undefined, undefined, undefined); expect(result.reportID).toBe(report.reportID); }); @@ -5035,6 +5035,7 @@ describe('OptionsListUtils', () => { // Test that the function works without crashing when chatReport is passed const result = getLastMessageTextForReport({ + translate: jest.fn().mockReturnValue(''), report, lastActorDetails: null, isReportArchived: false, @@ -5052,6 +5053,7 @@ describe('OptionsListUtils', () => { }; const result = getLastMessageTextForReport({ + translate: jest.fn().mockReturnValue(''), report, lastActorDetails: null, isReportArchived: false, From 4b91876384a1b9aaed31ee173052307546032260 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 13:26:44 +0100 Subject: [PATCH 08/40] making new param as required --- src/components/OptionListContextProvider.tsx | 6 +++--- src/components/Search/SearchFiltersChatsSelector.tsx | 2 +- src/components/Search/SearchRouter/SearchRouter.tsx | 2 +- src/libs/OptionsListUtils/index.ts | 11 +++++------ src/libs/SidebarUtils.ts | 1 - tests/unit/OptionsListUtilsTest.tsx | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index bb5eabed12a0..2195d99fa292 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -121,7 +121,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { for (const reportKey of changedReportKeys) { const report = changedReportsEntries[reportKey]; const reportID = reportKey.replace(ONYXKEYS.COLLECTION.REPORT, ''); - const {reportOption} = processReport(report, personalDetails, currentUserAccountID, reportAttributes?.reports); + const {reportOption} = processReport(report, personalDetails, currentUserAccountID, reports, reportAttributes?.reports); if (reportOption) { updatedReportsMap.set(reportID, reportOption); @@ -155,7 +155,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { } const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, ''); - const {reportOption} = processReport(updatedReportsMap.get(reportID)?.item, personalDetails, currentUserAccountID, reportAttributes?.reports); + const {reportOption} = processReport(updatedReportsMap.get(reportID)?.item, personalDetails, currentUserAccountID, reports, reportAttributes?.reports); if (reportOption) { updatedReportsMap.set(reportID, reportOption); @@ -218,7 +218,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { continue; } - const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reportAttributes?.reports, {showPersonalDetails: true}, {}, reports); + const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, reportAttributes?.reports, {showPersonalDetails: true}, {}); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); newReportOptions.push({ newReportOption, diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index df12727e23c0..93de3f1c259a 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -73,10 +73,10 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen {...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails, currentUserAccountID, + reports, reportAttributesDerived, undefined, visibleReportActionsData, - reports, ), ); const isReportArchived = archivedReportsIdSet.has(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`); diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 0515ee06d4fb..5793ac4783e9 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -112,7 +112,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla return undefined; } - const option = createOptionFromReport(report, personalDetails, currentUserAccountID, undefined, {showPersonalDetails: true}, {}, reports); + const option = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, undefined, {showPersonalDetails: true}, {}); reportForContextualSearch = option; } diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 3be33201985e..806bb23cf5e3 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -1276,8 +1276,8 @@ function processReport( report: OnyxEntry | null, personalDetails: OnyxEntry, currentUserAccountID: number, + reports: OnyxCollection, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], - reports?: OnyxCollection, visibleReportActionsData: VisibleReportActionsDerivedValue = {}, ): { reportMapEntry?: [number, Report]; // The entry to add to reportMapForAccountIDs if applicable @@ -1310,7 +1310,7 @@ function processReport( function createOptionList( personalDetails: OnyxEntry, currentUserAccountID: number, - reports?: OnyxCollection, + reports: OnyxCollection, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], visibleReportActionsData: VisibleReportActionsDerivedValue = {}, ) { @@ -1321,7 +1321,7 @@ function createOptionList( if (reports) { for (const report of Object.values(reports)) { - const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reportAttributesDerived, reports, visibleReportActionsData); + const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reports, reportAttributesDerived, visibleReportActionsData); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1437,7 +1437,7 @@ function createFilteredOptionList( // Step 5: Process the limited set of reports (performance optimization) const reportOptions: Array> = []; for (const report of limitedReports) { - const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reportAttributesDerived, reports, visibleReportActionsData); + const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reports, reportAttributesDerived, visibleReportActionsData); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1464,7 +1464,6 @@ function createFilteredOptionList( const personalDetailsOptions = includeP2P ? Object.values(personalDetails ?? {}).map((personalDetail) => { const accountID = personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID; - const mappedReport = reportMapForAccountIDs[accountID]; return { item: personalDetail, @@ -1493,10 +1492,10 @@ function createOptionFromReport( report: Report, personalDetails: OnyxEntry, currentUserAccountID: number, + reports: OnyxCollection, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], config?: PreviewConfig, visibleReportActionsData: VisibleReportActionsDerivedValue = {}, - reports?: OnyxCollection, ) { const accountIDs = getParticipantsAccountIDsForDisplay(report); diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 4bee2a3baa46..244976146802 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -128,7 +128,6 @@ import { // eslint-disable-next-line @typescript-eslint/no-deprecated getReportName, getReportNotificationPreference, - getReportOrDraftReport, getReportParticipantsTitle, getReportSubtitlePrefix, getUnreportedTransactionMessage, diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index f59eb63faaa5..0d8a38f6db96 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -645,7 +645,7 @@ describe('OptionsListUtils', () => { OPTIONS_WITH_CHRONOS = createOptionList(PERSONAL_DETAILS_WITH_CHRONOS, CURRENT_USER_ACCOUNT_ID, REPORTS_WITH_CHRONOS); OPTIONS_WITH_RECEIPTS = createOptionList(PERSONAL_DETAILS_WITH_RECEIPTS, CURRENT_USER_ACCOUNT_ID, REPORTS_WITH_RECEIPTS); OPTIONS_WITH_WORKSPACE_ROOM = createOptionList(PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, REPORTS_WITH_WORKSPACE_ROOMS); - OPTIONS_WITH_MANAGER_MCTEST = createOptionList(PERSONAL_DETAILS_WITH_MANAGER_MCTEST, CURRENT_USER_ACCOUNT_ID); + OPTIONS_WITH_MANAGER_MCTEST = createOptionList(PERSONAL_DETAILS_WITH_MANAGER_MCTEST, CURRENT_USER_ACCOUNT_ID, REPORTS); }); describe('getSearchOptions()', () => { From d12186c60db474e3fc28a166fbd8eab394d1e1e5 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 13:50:53 +0100 Subject: [PATCH 09/40] making chatReport as required --- .../LHNOptionsList/OptionRowLHNData.tsx | 2 ++ src/components/OptionListContextProvider.tsx | 2 +- .../Search/SearchRouter/SearchRouter.tsx | 2 +- src/libs/OptionsListUtils/index.ts | 4 ++-- src/libs/SidebarUtils.ts | 2 +- tests/perf-test/SidebarUtils.perf-test.ts | 1 + tests/unit/OptionsListUtilsTest.tsx | 13 +++++++++++++ tests/unit/SidebarUtilsTest.ts | 18 ++++++++++++++++++ 8 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index da78a912afe6..4b0f4d983100 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -52,6 +52,7 @@ function OptionRowLHNData({ const [movedFromReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastAction, CONST.REPORT.MOVE_TYPE.FROM)}`, {canBeMissing: true}); const [movedToReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastAction, CONST.REPORT.MOVE_TYPE.TO)}`, {canBeMissing: true}); const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS, {canBeMissing: true}); + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${fullReport?.chatReportID}`, {canBeMissing: true}); // Check the report errors equality to avoid re-rendering when there are no changes const prevReportErrors = usePrevious(reportAttributes?.reportErrors); const areReportErrorsEqual = useMemo(() => deepEqual(prevReportErrors, reportAttributes?.reportErrors), [prevReportErrors, reportAttributes?.reportErrors]); @@ -79,6 +80,7 @@ function OptionRowLHNData({ movedFromReport, movedToReport, currentUserAccountID, + chatReport, visibleReportActionsData, }); if (deepEqual(item, optionItemRef.current)) { diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 2195d99fa292..0f3b91cd5527 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -218,7 +218,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { continue; } - const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, reportAttributes?.reports, {showPersonalDetails: true}, {}); + const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, reportAttributes?.reports, {showPersonalDetails: true}); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); newReportOptions.push({ newReportOption, diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 5793ac4783e9..aa8d2b02dd54 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -112,7 +112,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla return undefined; } - const option = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, undefined, {showPersonalDetails: true}, {}); + const option = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, undefined, {showPersonalDetails: true}); reportForContextualSearch = option; } diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 806bb23cf5e3..d4db4d1fb504 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -609,7 +609,7 @@ function getLastMessageTextForReport({ policy?: OnyxEntry; isReportArchived?: boolean; policyForMovingExpensesID?: string; - chatReport?: OnyxEntry; + chatReport: OnyxEntry; reportMetadata?: OnyxEntry; visibleReportActionsDataParam?: VisibleReportActionsDerivedValue; lastAction?: OnyxEntry; @@ -1953,7 +1953,7 @@ function getUserToInviteContactOption({ return userToInvite; } -function isValidReport(option: SearchOption, policy: OnyxEntry, config: IsValidReportsConfig, draftComment: string | undefined, chatReport?: OnyxEntry): boolean { +function isValidReport(option: SearchOption, policy: OnyxEntry, config: IsValidReportsConfig, draftComment: string | undefined, chatReport: OnyxEntry): boolean { const { betas = [], includeMultipleParticipantReports = false, diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 244976146802..326c85bc4a35 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -684,7 +684,7 @@ function getOptionData({ movedFromReport?: OnyxEntry; movedToReport?: OnyxEntry; currentUserAccountID: number; - chatReport?: OnyxEntry; + chatReport: OnyxEntry; visibleReportActionsData?: VisibleReportActionsDerivedValue; }): OptionData | undefined { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index ab45ab1c4642..49cac14bdc5b 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -91,6 +91,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 1, + chatReport: undefined, }), ); }); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 0d8a38f6db96..ac52a66e0a2a 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -3320,6 +3320,7 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(getMovedTransactionMessage(translateLocal, movedTransactionAction))); }); @@ -3345,6 +3346,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallySubmitted'))); }); @@ -3371,6 +3373,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallyApproved'))); }); @@ -3397,6 +3400,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallyForwarded'))); }); @@ -3420,6 +3424,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'workspaceActions.forcedCorporateUpgrade'))); }); @@ -3441,6 +3446,7 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(getChangedApproverActionMessage(translateLocal, takeControlAction))); }); @@ -3461,6 +3467,7 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(getChangedApproverActionMessage(translateLocal, rerouteAction))); }); @@ -3481,6 +3488,7 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(getMovedActionMessage(translateLocal, movedAction, report))); }); @@ -3505,6 +3513,7 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); // Then it should return the DYNAMIC_EXTERNAL_WORKFLOW_ROUTED message @@ -3532,6 +3541,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(result).toBe(expectedVisibleText); }); @@ -3584,6 +3594,7 @@ describe('OptionsListUtils', () => { reportMetadata, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(translate(CONST.LOCALES.EN, 'iou.queuedToSubmitViaDEW')); }); @@ -3617,6 +3628,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(customErrorMessage); }); @@ -3647,6 +3659,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + chatReport: undefined, }); expect(lastMessage).toBe(translate(CONST.LOCALES.EN, 'iou.error.genericCreateFailureMessage')); }); diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index 47e4c6d0aba3..7a0c4e091009 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -352,6 +352,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); const optionDataUnpinned = SidebarUtils.getOptionData({ report: MOCK_REPORT_UNPINNED, @@ -368,6 +369,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(optionDataPinned?.isPinned).toBe(true); @@ -1170,6 +1172,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); // Then the alternate text should be equal to the message of the last action prepended with the last actor display name. @@ -1232,6 +1235,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); // Then the alternate text should be equal to the message of the last action prepended with the last actor display name. @@ -1297,6 +1301,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); // Then the alternate text should show @Hidden. @@ -1347,6 +1352,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(optionData?.alternateText).toBe(`test message`); @@ -1388,6 +1394,7 @@ describe('SidebarUtils', () => { isReportArchived: true, lastActionReport: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(optionData?.alternateText).toBe(`test message`); @@ -1426,6 +1433,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(optionData?.alternateText).toBe(`test message`); @@ -1553,6 +1561,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(optionData?.alternateText).toBe(formatReportLastMessageText(iouReport.reportName)); @@ -1596,6 +1605,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(optionData?.alternateText).toBe(`${policy.name} ${CONST.DOT_SEPARATOR} test message`); @@ -1668,6 +1678,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: session.accountID, + chatReport: undefined, }); // Then the alternate text should be equal to the message of the last action prepended with the last actor display name. @@ -1729,6 +1740,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: session.accountID, + chatReport: undefined, }); expect(result?.alternateText).toBe(`You: moved this report to the Three's Workspace workspace`); @@ -1781,6 +1793,7 @@ describe('SidebarUtils', () => { isReportArchived: undefined, lastMessageTextFromReport: report.lastMessageText, currentUserAccountID: session.accountID, + chatReport: undefined, }); expect(result?.alternateText).toBe('You: someMessage'); @@ -1867,6 +1880,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: session.accountID, + chatReport: undefined, visibleReportActionsData: { [iouReportR14932.reportID]: { [linkedCreateAction.reportActionID]: true, @@ -1995,6 +2009,7 @@ describe('SidebarUtils', () => { isReportArchived: undefined, lastMessageTextFromReport: 'test action', currentUserAccountID: 0, + chatReport: undefined, }); expect(result?.alternateText).toContain(`${getReportActionMessageText(lastAction)}`); @@ -2081,6 +2096,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); expect(result?.alternateText).toBe(`One: submitted`); @@ -2179,6 +2195,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: managerID, + chatReport: undefined, }); const reportPreviewMessage = getReportPreviewMessage(iouReport, iouAction, true, true, null, true, lastReportPreviewAction); @@ -2278,6 +2295,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: managerID, + chatReport: undefined, }); const reportPreviewMessage = getReportPreviewMessage(iouReport, iouAction, true, true, null, true, lastReportPreviewAction); From 5ef9211014ce854b87f11e162ff22ef51c228400 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 13:55:02 +0100 Subject: [PATCH 10/40] reverting back onyx connect to be handled in a follow up PR --- src/libs/OptionsListUtils/index.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index d4db4d1fb504..a46fd3fdb28b 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -221,6 +221,15 @@ Onyx.connect({ callback: (val) => (allPolicies = val), }); +let allReports: OnyxCollection; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (value) => { + allReports = value; + }, +}); + let allReportNameValuePairsOnyxConnect: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, @@ -253,8 +262,8 @@ Onyx.connect({ const reportActionsArray = Object.values(reportActions[1] ?? {}); let sortedReportActions = getSortedReportActions(withDEWRoutedActionsArray(reportActionsArray), true); allSortedReportActions[reportID] = sortedReportActions; - const report = getReportOrDraftReport(reportID); - const chatReport = getReportOrDraftReport(report?.chatReportID); + const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; // If the report is a one-transaction report and has , we need to return the combined reportActions so that the LHN can display modifications // to the transaction thread or the report itself @@ -2133,12 +2142,12 @@ function prepareReportOptionsForDisplay( let isOptionUnread = option.isUnread; if (shouldUnreadBeBold) { - const chatReport = getReportOrDraftReport(report.chatReportID); + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`]; const oneTransactionThreadReportID = report.type === CONST.REPORT.TYPE.IOU || report.type === CONST.REPORT.TYPE.EXPENSE || report.type === CONST.REPORT.TYPE.INVOICE ? getOneTransactionThreadReportID(report, chatReport, allSortedReportActions[report.reportID]) : undefined; - const oneTransactionThreadReport = oneTransactionThreadReportID ? getReportOrDraftReport(oneTransactionThreadReportID) : undefined; + const oneTransactionThreadReport = oneTransactionThreadReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneTransactionThreadReportID}`] : undefined; isOptionUnread = isUnread(report, oneTransactionThreadReport, !!option.private_isArchived) && !!report.lastActorAccountID; } @@ -2321,7 +2330,7 @@ function getValidOptions( } const draftComment = draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${report.reportID}`]; - const chatReport = getReportOrDraftReport(report.item.chatReportID); + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.item.chatReportID}`]; return isValidReport( report, From e6fb4d53bf3326e407e4d717c8224f3331e4842f Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 14:58:38 +0100 Subject: [PATCH 11/40] making reports as required --- .../FilterDropdowns/UserSelectPopup.tsx | 8 ++-- .../Search/SearchAutocompleteList.tsx | 4 ++ .../Search/SearchFiltersChatsSelector.tsx | 7 ++- .../SearchFiltersParticipantsSelector.tsx | 8 +++- src/hooks/useSearchSelector.base.ts | 12 +++-- src/libs/OptionsListUtils/index.ts | 48 ++++++++++++------- src/pages/NewChatPage.tsx | 5 +- src/pages/RoomInvitePage.tsx | 5 +- src/pages/Share/ShareDetailsPage.tsx | 5 +- src/pages/Share/ShareTab.tsx | 3 ++ src/pages/iou/SplitBillDetailsPage.tsx | 3 +- .../MoneyRequestAccountantSelector.tsx | 11 +++-- .../request/MoneyRequestAttendeeSelector.tsx | 4 +- .../MoneyRequestParticipantsSelector.tsx | 4 +- tests/perf-test/OptionsListUtils.perf-test.ts | 9 +++- tests/unit/OptionsListUtilsTest.tsx | 30 ++++++++---- 16 files changed, 116 insertions(+), 50 deletions(-) diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index dc876a1d0d1e..e47fff7a691a 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -65,6 +65,7 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele const shouldFocusInputOnScreenFocus = canFocusInputOnScreenFocus(); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [searchTerm, setSearchTerm] = useState(''); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); @@ -106,6 +107,7 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele loginList, currentUserAccountID, currentUserEmail, + reports, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, @@ -113,7 +115,7 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele }, countryCode, ); - }, [options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode, personalDetails, currentUserAccountID, currentUserEmail]); + }, [options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode, personalDetails, currentUserAccountID, currentUserEmail, reports]); const filteredOptions = useMemo(() => { return filterAndOrderOptions( @@ -122,15 +124,15 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele countryCode, loginList, currentUserEmail, - currentUserAccountID, + reports, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, canInviteUser: false, }, ); - }, [optionsList, cleanSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail]); + }, [optionsList, cleanSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, reports]); const listData = useMemo(() => { const personalDetailList = filteredOptions.personalDetails.map((participant) => ({ diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index e839504b4989..faf88d4e4ae1 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -226,6 +226,7 @@ function SearchAutocompleteList({ visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, }); }, [ areOptionsInitialized, @@ -239,6 +240,7 @@ function SearchAutocompleteList({ visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, ]); const [isInitialRender, setIsInitialRender] = useState(true); @@ -453,6 +455,7 @@ function SearchAutocompleteList({ visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, }).personalDetails.filter((participant) => participant.text && !alreadyAutocompletedKeys.has(participant.text.toLowerCase())); return participants.map((participant) => ({ @@ -487,6 +490,7 @@ function SearchAutocompleteList({ visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, }).recentReports.filter((chat) => { if (!chat.text) { return false; diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 93de3f1c259a..e7e4e71a99cc 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -100,6 +100,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, }); }, [ areOptionsInitialized, @@ -112,14 +113,15 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, ]); const chatOptions = useMemo(() => { - return filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, { + return filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, { selectedOptions, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); - }, [defaultOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail]); + }, [defaultOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail, reports]); const {sections, headerMessage} = useMemo(() => { const newSections: Section[] = []; @@ -137,6 +139,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen false, undefined, reportAttributesDerived, + reports, ); newSections.push(formattedResults.section); diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index b6c399deb539..1d8b703232b3 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -52,6 +52,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserAccountID = currentUserPersonalDetails.accountID; const currentUserEmail = currentUserPersonalDetails.email ?? ''; @@ -77,6 +78,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: loginList, currentUserAccountID, currentUserEmail, + reports, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, @@ -96,6 +98,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: personalDetails, currentUserAccountID, currentUserEmail, + reports, ]); const unselectedOptions = useMemo(() => { @@ -103,7 +106,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: }, [defaultOptions, selectedOptions]); const chatOptions = useMemo(() => { - const filteredOptions = filterAndOrderOptions(unselectedOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, { + const filteredOptions = filterAndOrderOptions(unselectedOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, { selectedOptions, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, @@ -118,7 +121,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: } return filteredOptions; - }, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail]); + }, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail, reports]); const {sections, headerMessage} = useMemo(() => { const newSections: Section[] = []; @@ -136,6 +139,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: true, undefined, reportAttributesDerived, + reports, ); const selectedCurrentUser = formattedResults.section.data.find((option) => option.accountID === chatOptions.currentUserOption?.accountID); diff --git a/src/hooks/useSearchSelector.base.ts b/src/hooks/useSearchSelector.base.ts index 5cc956993bd8..3875be282128 100644 --- a/src/hooks/useSearchSelector.base.ts +++ b/src/hooks/useSearchSelector.base.ts @@ -165,6 +165,7 @@ function useSearchSelectorBase({ const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS, {canBeMissing: true}); @@ -206,9 +207,10 @@ function useSearchSelectorBase({ visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_MEMBER_INVITE: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, { + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { betas: betas ?? [], includeP2P: true, includeSelectedOptions: false, @@ -221,7 +223,7 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, { + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { ...getValidOptionsConfig, betas: betas ?? [], searchString: computedSearchTerm, @@ -240,6 +242,7 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, + reports, { betas, includeMultipleParticipantReports: true, @@ -257,7 +260,7 @@ function useSearchSelectorBase({ countryCode, ); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_DESTINATION: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, { + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { betas, selectedOptions, includeMultipleParticipantReports: true, @@ -276,7 +279,7 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_ATTENDEES: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, { + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { ...getValidOptionsConfig, betas: betas ?? [], includeP2P: true, @@ -318,6 +321,7 @@ function useSearchSelectorBase({ currentUserAccountID, currentUserEmail, personalDetails, + reports, ]); const isOptionSelected = useMemo(() => { diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index a46fd3fdb28b..7fea9a10e7b2 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -877,15 +877,15 @@ function createOption( personalDetails: OnyxInputOrEntry, report: OnyxInputOrEntry, currentUserAccountID: number, + reports: OnyxCollection, config?: PreviewConfig, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], privateIsArchived?: string, - allReports?: OnyxCollection, visibleReportActionsData: VisibleReportActionsDerivedValue = {}, translate?: LocalizedTranslate, ): SearchOptionData { const {showChatPreviewLine = false, forcePolicyNamePreview = false, showPersonalDetails = false, selected, isSelected, isDisabled} = config ?? {}; - const chatReport = report?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; // Initialize only the properties that are actually used in SearchOption context const result: SearchOptionData = { @@ -986,7 +986,7 @@ function createOption( const personalDetailsForCompute: PersonalDetailsList | undefined = personalDetails ?? undefined; const computedReportName = computeReportName( report, - allReports, + reports, allPolicies, undefined, undefined, @@ -1054,13 +1054,13 @@ function getReportOption( personalDetails ?? {}, !isEmptyObject(report) ? report : undefined, currentUserAccountID, + reportDrafts, { showChatPreviewLine: false, forcePolicyNamePreview: false, }, reportAttributesDerived, privateIsArchived, - reportDrafts, visibleReportActionsData, ); @@ -1104,6 +1104,7 @@ function getReportDisplayOption( currentUserAccountID: number, personalDetails: OnyxEntry, privateIsArchived: string | undefined, + reports: OnyxCollection, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], visibleReportActionsData: VisibleReportActionsDerivedValue = {}, ): OptionData { @@ -1114,13 +1115,13 @@ function getReportDisplayOption( personalDetails ?? {}, !isEmptyObject(report) ? report : undefined, currentUserAccountID, + reports, { showChatPreviewLine: false, forcePolicyNamePreview: false, }, reportAttributesDerived, privateIsArchived, - undefined, visibleReportActionsData, ); @@ -1154,6 +1155,7 @@ function getPolicyExpenseReportOption( participant: Participant | SearchOptionData, currentUserAccountID: number, personalDetails: OnyxEntry, + reports: OnyxCollection, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], visibleReportActionsData: VisibleReportActionsDerivedValue = {}, ): SearchOptionData { @@ -1168,13 +1170,13 @@ function getPolicyExpenseReportOption( personalDetails ?? {}, !isEmptyObject(expenseReport) ? expenseReport : null, currentUserAccountID, + reports, { showChatPreviewLine: false, forcePolicyNamePreview: false, }, reportAttributesDerived, undefined, - undefined, visibleReportActionsData, ); @@ -1311,7 +1313,7 @@ function processReport( reportMapEntry, reportOption: { item: report, - ...createOption(accountIDs, personalDetails, report, currentUserAccountID, undefined, reportAttributesDerived, undefined, reports, visibleReportActionsData), + ...createOption(accountIDs, personalDetails, report, currentUserAccountID, reports, undefined, reportAttributesDerived, undefined, visibleReportActionsData), }, }; } @@ -1350,12 +1352,12 @@ function createOptionList( personalDetails, reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID], currentUserAccountID, + reports, { showPersonalDetails: true, }, reportAttributesDerived, undefined, - reports, visibleReportActionsData, ), })); @@ -1481,10 +1483,10 @@ function createFilteredOptionList( personalDetails, reportMapForAccountIDs[accountID], currentUserAccountID, + reports, {showPersonalDetails: true}, reportAttributesDerived, undefined, - reports, visibleReportActionsData, ), }; @@ -1510,7 +1512,7 @@ function createOptionFromReport( return { item: report, - ...createOption(accountIDs, personalDetails, report, currentUserAccountID, config, reportAttributesDerived, undefined, reports, visibleReportActionsData), + ...createOption(accountIDs, personalDetails, report, currentUserAccountID, reports, config, reportAttributesDerived, undefined, visibleReportActionsData), }; } @@ -1797,8 +1799,9 @@ function getUserToInviteOption({ loginList = {}, currentUserEmail, currentUserAccountID, + reports, visibleReportActionsData = {}, -}: GetUserToInviteConfig & {visibleReportActionsData?: VisibleReportActionsDerivedValue}): SearchOptionData | null { +}: GetUserToInviteConfig & {reports: OnyxCollection; visibleReportActionsData?: VisibleReportActionsDerivedValue}): SearchOptionData | null { if (!searchValue) { return null; } @@ -1831,12 +1834,12 @@ function getUserToInviteOption({ personalDetailsExtended, null, currentUserAccountID, + reports, { showChatPreviewLine, }, undefined, undefined, - undefined, visibleReportActionsData, ); userToInvite.isOptimisticAccount = true; @@ -2256,6 +2259,7 @@ function getValidOptions( loginList: OnyxEntry, currentUserAccountID: number, currentUserEmail: string, + reports: OnyxCollection, { excludeLogins = {}, includeSelectedOptions = false, @@ -2484,6 +2488,7 @@ function getValidOptions( loginList, currentUserEmail, currentUserAccountID, + reports, countryCode, { excludeLogins: loginsToExclude, @@ -2546,7 +2551,8 @@ function getSearchOptions({ visibleReportActionsData = {}, currentUserAccountID, currentUserEmail, -}: SearchOptionsConfig): Options { + reports, +}: SearchOptionsConfig & {reports: OnyxCollection}): Options { Timing.start(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markStart(CONST.TIMING.LOAD_SEARCH_OPTIONS); @@ -2558,7 +2564,7 @@ function getSearchOptions({ loginList, currentUserAccountID, currentUserEmail, - + reports, { betas, includeRecentReports, @@ -2683,6 +2689,7 @@ function getMemberInviteOptions( loginList: OnyxEntry, currentUserAccountID: number, currentUserEmail: string, + reports: OnyxCollection, betas: Beta[] = [], excludeLogins: Record = {}, includeSelectedOptions = false, @@ -2697,6 +2704,7 @@ function getMemberInviteOptions( loginList, currentUserAccountID, currentUserEmail, + reports, { betas, includeP2P: true, @@ -2776,6 +2784,7 @@ function formatSectionsFromSearchTerm( shouldGetOptionDetails = false, filteredWorkspaceChats: SearchOptionData[] = [], reportAttributesDerived?: ReportAttributesDerivedValue['reports'], + reports?: OnyxCollection, ): SectionForSearchTerm { // We show the selected participants at the top of the list when there is no search term or maximum number of participants has already been selected // However, if there is a search term we remove the selected participants from the top of the list unless they are part of the search results @@ -2788,7 +2797,7 @@ function formatSectionsFromSearchTerm( ? selectedOptions.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; return isReportPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) : selectedOptions, @@ -2816,7 +2825,7 @@ function formatSectionsFromSearchTerm( ? selectedParticipantsWithoutDetails.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; return isReportPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) : selectedParticipantsWithoutDetails, @@ -2944,6 +2953,7 @@ function filterUserToInvite( loginList: OnyxEntry, currentUserEmail: string, currentUserAccountID: number, + reports: OnyxCollection, countryCode: number = CONST.DEFAULT_COUNTRY_CODE, config?: FilterUserToInviteConfig, ): SearchOptionData | null { @@ -2974,6 +2984,7 @@ function filterUserToInvite( loginList, currentUserEmail, currentUserAccountID, + reports, ...config, }); } @@ -3015,6 +3026,7 @@ function filterOptions( loginList: OnyxEntry, currentUserEmail: string, currentUserAccountID: number, + reports: OnyxCollection, config?: FilterUserToInviteConfig, ): Options { const trimmedSearchInput = searchInputValue.trim(); @@ -3037,6 +3049,7 @@ function filterOptions( loginList, currentUserEmail, currentUserAccountID, + reports, countryCode, config, ); @@ -3099,11 +3112,12 @@ function filterAndOrderOptions( loginList: OnyxEntry, currentUserEmail: string, currentUserAccountID: number, + reports: OnyxCollection, config?: FilterAndOrderConfig, ): Options { let filterResult = options; if (searchInputValue.trim().length > 0) { - filterResult = filterOptions(options, searchInputValue, countryCode, loginList, currentUserEmail, currentUserAccountID, config); + filterResult = filterOptions(options, searchInputValue, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, config); } const orderedOptions = combineOrderingOfReportsAndPersonalDetails(filterResult, searchInputValue, config); diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index e3e0e01b99b9..74edb0178819 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -90,6 +90,7 @@ function useOptions() { const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); + const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const reports = listOptions?.reports ?? []; const personalDetails = listOptions?.personalDetails ?? []; @@ -105,6 +106,7 @@ function useOptions() { loginList, currentUserAccountID, currentUserEmail, + allReports, { betas: betas ?? [], includeSelfDM: true, @@ -118,7 +120,7 @@ function useOptions() { const areOptionsInitialized = !isLoading; - const options = filterAndOrderOptions(unselectedOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, { + const options = filterAndOrderOptions(unselectedOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, allReports, { selectedOptions, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, }); @@ -164,6 +166,7 @@ function useOptions() { loginList, currentUserEmail: personalData.email ?? '', currentUserAccountID: personalData.accountID, + reports: allReports, }); if (participantOption) { result.push({ diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index aef1e3446ae2..da5f6f727b0e 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -72,6 +72,7 @@ function RoomInvitePage({ const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const isReportArchived = useReportIsArchived(report.reportID); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const {options, areOptionsInitialized} = useOptionsList(); @@ -96,7 +97,7 @@ function RoomInvitePage({ return {recentReports: [], personalDetails: [], userToInvite: null, currentUserOption: null}; } - const inviteOptions = getMemberInviteOptions(options.personalDetails, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, betas ?? [], excludedUsers); + const inviteOptions = getMemberInviteOptions(options.personalDetails, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, betas ?? [], excludedUsers); // Update selectedOptions with the latest personalDetails information const detailsMap: Record = {}; for (const detail of inviteOptions.personalDetails) { @@ -123,7 +124,7 @@ function RoomInvitePage({ if (debouncedSearchTerm.trim() === '') { return defaultOptions; } - const filteredOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, { + const filteredOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, { excludeLogins: excludedUsers, }); diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index f0db68c6d8fb..0fbf0700b851 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -55,6 +55,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const [validatedFile] = useOnyx(ONYXKEYS.VALIDATED_FILE_OBJECT, {canBeMissing: true}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const personalDetails = usePersonalDetails(); const personalDetail = useCurrentUserPersonalDetails(); const isTextShared = currentAttachment?.mimeType === CONST.SHARE_FILE_MIMETYPE.TXT; @@ -68,8 +69,8 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; const ancestors = useAncestors(report); const displayReport = useMemo( - () => getReportDisplayOption(report, unknownUserDetails, personalDetail.accountID, personalDetails, privateIsArchived, reportAttributesDerived), - [report, unknownUserDetails, personalDetails, privateIsArchived, reportAttributesDerived, personalDetail.accountID], + () => getReportDisplayOption(report, unknownUserDetails, personalDetail.accountID, personalDetails, privateIsArchived, reports, reportAttributesDerived), + [report, unknownUserDetails, personalDetails, privateIsArchived, reportAttributesDerived, personalDetail.accountID, reports], ); const shouldShowAttachment = !isTextShared; diff --git a/src/pages/Share/ShareTab.tsx b/src/pages/Share/ShareTab.tsx index f454bd06c794..26988e86ec5f 100644 --- a/src/pages/Share/ShareTab.tsx +++ b/src/pages/Share/ShareTab.tsx @@ -66,6 +66,7 @@ function ShareTab({ref}: ShareTabProps) { const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const showLoadingPlaceholder = useMemo(() => !areOptionsInitialized || !didScreenTransitionEnd, [areOptionsInitialized, didScreenTransitionEnd]); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const searchOptions = useMemo(() => { if (!areOptionsInitialized) { return defaultListOptions; @@ -85,6 +86,7 @@ function ShareTab({ref}: ShareTabProps) { visibleReportActionsData, currentUserAccountID, currentUserEmail, + reports, }); }, [ areOptionsInitialized, @@ -97,6 +99,7 @@ function ShareTab({ref}: ShareTabProps) { loginList, visibleReportActionsData, currentUserAccountID, + reports, currentUserEmail, ]); diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index b3c3af497809..73cf98f2e020 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -66,6 +66,7 @@ function SplitBillDetailsPage({route, report, reportAction}: SplitBillDetailsPag const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, {canBeMissing: true}); const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID @@ -73,7 +74,7 @@ function SplitBillDetailsPage({route, report, reportAction}: SplitBillDetailsPag if (isPolicyExpenseChat(report)) { participants = [ getParticipantsOption({accountID: participantAccountIDs.at(0), selected: true, reportID: ''}, personalDetails), - getPolicyExpenseReportOption({...report, selected: true, reportID}, currentUserPersonalDetails.accountID, personalDetails, reportAttributesDerived), + getPolicyExpenseReportOption({...report, selected: true, reportID}, currentUserPersonalDetails.accountID, personalDetails, reports, reportAttributesDerived), ]; } else { participants = participantAccountIDs.map((accountID) => getParticipantsOption({accountID, selected: true, reportID: ''}, personalDetails)); diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 006907687d3e..25a4f8418ddc 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -67,6 +67,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserEmail = currentUserPersonalDetails.email ?? ''; const currentUserAccountID = currentUserPersonalDetails.accountID; @@ -92,6 +93,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType loginList, currentUserAccountID, currentUserEmail, + reports, { betas, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, @@ -122,6 +124,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType currentUserAccountID, currentUserEmail, personalDetails, + reports, ]); const chatOptions = useMemo(() => { @@ -134,12 +137,12 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType headerMessage: '', }; } - const newOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, { + const newOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, }); return newOptions; - }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail]); + }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, reports]); /** * Returns the sections needed for the OptionsSelector @@ -163,6 +166,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType true, undefined, reportAttributesDerived, + reports, ); newSections.push(formatResults.section); @@ -191,7 +195,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType data: [chatOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }), shouldShow: true, @@ -221,6 +225,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType countryCode, currentUserAccountID, currentUserEmail, + reports, ]); const selectAccountant = useCallback( diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index 9b1c57947e26..628d3262eedc 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -70,6 +70,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserEmail = currentUserPersonalDetails.email ?? ''; const currentUserAccountID = currentUserPersonalDetails.accountID; @@ -219,6 +220,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde true, undefined, reportAttributesDerived, + reports, ); newSections.push({ @@ -257,7 +259,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde data: [orderedAvailableOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) as OptionData[], shouldShow: true, diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index b7c97e731c11..4bf88e727ab8 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -124,6 +124,7 @@ function MoneyRequestParticipantsSelector({ const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [textInputAutoFocus, setTextInputAutoFocus] = useState(!isNative); const selectionListRef = useRef(null); @@ -296,6 +297,7 @@ function MoneyRequestParticipantsSelector({ true, undefined, reportAttributesDerived, + reports, ); newSections.push(formatResults.section); @@ -345,7 +347,7 @@ function MoneyRequestParticipantsSelector({ data: [availableOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }), shouldShow: true, diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index d6f5fd7a48b6..d36c62ba31ca 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -137,6 +137,7 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, currentUserEmail: MOCK_CURRENT_USER_EMAIL, + reports: {}, }), ); }); @@ -152,10 +153,11 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, + {}, ValidOptionsConfig, ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID); + filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}); }); }); test('[OptionsListUtils] getFilteredOptions with empty search value', async () => { @@ -168,10 +170,11 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, + {}, ValidOptionsConfig, ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID); + filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}); }); }); @@ -187,6 +190,7 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, + {}, { betas: mockedBetas, includeMultipleParticipantReports: true, @@ -215,6 +219,7 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, + {}, mockedBetas, {}, false, diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index ac52a66e0a2a..96ac183c6f5f 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -660,6 +660,7 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // Then all personal details (including those that have reports) should be returned @@ -687,6 +688,7 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // Then the current user should be included in personalDetails @@ -716,6 +718,7 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // Then the current user should not be included in personalDetails @@ -1808,9 +1811,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then all options should be returned expect(filteredOptions.recentReports.length + filteredOptions.personalDetails.length).toBe(14); @@ -1828,9 +1832,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { sortByReportTypeInSearch: true, }); @@ -1857,9 +1862,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1879,9 +1885,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1903,9 +1910,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { sortByReportTypeInSearch: true, }); @@ -1927,9 +1935,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1948,9 +1957,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -1971,9 +1981,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only two reports should be returned expect(filterOptions.recentReports.length).toBe(2); @@ -1992,9 +2003,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); From 4595c670d5b23f3277af57c45714d5202a636c13 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 16:15:56 +0100 Subject: [PATCH 12/40] fixing tests --- tests/unit/OptionsListUtilsTest.tsx | 170 ++++++++++++++++++---------- 1 file changed, 113 insertions(+), 57 deletions(-) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 96ac183c6f5f..aa5aaea66f97 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -745,6 +745,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call orderOptions() results = orderOptions(results); @@ -784,6 +785,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call orderOptions() results = orderOptions(results); @@ -811,7 +813,7 @@ describe('OptionsListUtils', () => { it('should return empty options when no reports or personal details are provided', () => { // Given empty arrays of reports and personalDetails // When we call getValidOptions() - const results = getValidOptions({reports: [], personalDetails: []}, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); + const results = getValidOptions({reports: [], personalDetails: []}, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); // Then the result should be empty expect(results.personalDetails).toEqual([]); @@ -833,6 +835,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // Then the result should include all personalDetails except the currently logged in user @@ -855,6 +858,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, }, @@ -877,6 +881,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, }, @@ -902,6 +907,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, }, @@ -929,6 +935,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeP2P: true, canShowManagerMcTest: true, @@ -953,6 +960,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeP2P: true, canShowManagerMcTest: false, @@ -986,6 +994,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeP2P: true, canShowManagerMcTest: true, @@ -1043,6 +1052,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeMultipleParticipantReports: true, }, @@ -1097,6 +1107,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeMultipleParticipantReports: true, showRBR: true, @@ -1149,6 +1160,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeMultipleParticipantReports: true, showRBR: false, @@ -1205,6 +1217,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { includeRecentReports: true, shouldUnreadBeBold: true, @@ -1240,6 +1253,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { personalDetails: customPersonalDetails, }, @@ -1256,7 +1270,7 @@ describe('OptionsListUtils', () => { it('should include all reports by default', () => { // Given a set of reports and personalDetails that includes workspace rooms // When we call getValidOptions() - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, { + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1281,6 +1295,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); const reportLogins = new Set(results.recentReports.map((reportOption) => reportOption.login)); const personalDetailsOverlapWithReports = results.personalDetails.every((personalDetailOption) => reportLogins.has(personalDetailOption.login)); @@ -1302,6 +1317,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {'peterparker@expensify.com': true}, }, @@ -1323,6 +1339,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // Then the result should include all personalDetails except the currently logged in user @@ -1345,6 +1362,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, }, @@ -1368,6 +1386,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, }, @@ -1394,6 +1413,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, }, @@ -1418,6 +1438,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { maxRecentReportElements: maxRecentReports, }, @@ -1438,6 +1459,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); const resultsWithLimit = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, @@ -1447,6 +1469,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { maxRecentReportElements: 2, }, @@ -1467,6 +1490,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); const resultsWithLimit = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, @@ -1476,6 +1500,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { maxRecentReportElements: 2, }, @@ -1498,6 +1523,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { maxElements: maxTotalElements, maxRecentReportElements: maxRecentReports, @@ -1532,6 +1558,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -1573,6 +1600,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -1598,7 +1626,7 @@ describe('OptionsListUtils', () => { it('should sort personal details alphabetically and return expected structure', () => { // Given a set of personalDetails // When we call getMemberInviteOptions - const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, []); + const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); // Then personal details should be sorted alphabetically expect(results.personalDetails.at(0)?.text).toBe('Black Panther'); @@ -1617,7 +1645,7 @@ describe('OptionsListUtils', () => { const excludeLogins = {'reedrichards@expensify.com': true}; // When we call getMemberInviteOptions with excludeLogins - const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, [], excludeLogins); + const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, [], excludeLogins); // Then the excluded login should not be in the results const excludedUser = results.personalDetails.find((detail) => detail.login === 'reedrichards@expensify.com'); @@ -2026,9 +2054,10 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then the user to invite should be returned expect(filteredOptions.userToInvite?.login).toBe(searchText); @@ -2045,12 +2074,13 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }, ); // When we call filterAndOrderOptions with a search value and excluded logins list - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -2068,9 +2098,10 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value and excludeLogins - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -2088,9 +2119,10 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 2 - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { maxRecentReportsToShow: 2, }); @@ -2099,7 +2131,7 @@ describe('OptionsListUtils', () => { // Note: in the past maxRecentReportsToShow: 0 would return all recent reports, this has changed, and is expected to return none now // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 0 - const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { maxRecentReportsToShow: 0, }); @@ -2118,9 +2150,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then there should be one matching result expect(filteredOptions.personalDetails.length).toBe(1); @@ -2130,9 +2163,9 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, []); + const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -2140,9 +2173,9 @@ describe('OptionsListUtils', () => { it('should return one personal detail if search value matches an email (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, []); + const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then one personal detail should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -2168,6 +2201,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -2184,7 +2218,7 @@ describe('OptionsListUtils', () => { }, ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2210,6 +2244,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -2226,7 +2261,7 @@ describe('OptionsListUtils', () => { }, ); // When we pass the returned options to filterAndOrderOptions with a search value that matches the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2252,6 +2287,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -2268,7 +2304,7 @@ describe('OptionsListUtils', () => { }, ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2284,9 +2320,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that matches a personal detail with no existing report - const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2306,9 +2343,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2327,9 +2365,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2348,9 +2387,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2368,9 +2408,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value without accent mark - const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then one personalDetails with accent mark should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -2386,9 +2427,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2409,9 +2451,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2432,9 +2475,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2455,9 +2499,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2476,9 +2521,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -2494,9 +2540,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { sortByReportTypeInSearch: true, }); @@ -2518,9 +2565,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, ); // When we call filterAndOrderOptions with a search value that matches both reports and personal details and maxRecentReportsToShow param - const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { maxRecentReportsToShow: 5, }); @@ -2544,9 +2592,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value that matches a personal detail - const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then one personal detail should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2563,9 +2612,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value that matches multiple items - const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -2587,9 +2637,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredResults = filterAndOrderOptions(results, 'barry.allen@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, { + const filteredResults = filterAndOrderOptions(results, 'barry.allen@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { sortByReportTypeInSearch: true, }); @@ -2615,9 +2666,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); const matchingEntries = filteredOptions.personalDetails.filter((detail) => detail.login === login); // Then there should be 2 unique login entries @@ -2639,9 +2691,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID); + const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); // Then the self dm should be on top. expect(filteredOptions.recentReports.at(0)?.isSelfDM).toBe(true); @@ -3193,7 +3246,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction); await waitForBatchedUpdates(); - const result = createOption([1, 2], PERSONAL_DETAILS, report, CURRENT_USER_ACCOUNT_ID, {showChatPreviewLine: true}); + const result = createOption([1, 2], PERSONAL_DETAILS, report, CURRENT_USER_ACCOUNT_ID, REPORTS, {showChatPreviewLine: true}); expect(result.alternateText).toBe('Iron Man owes ₫34'); }); @@ -3226,7 +3279,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); - const result = createOption([1, 2], PERSONAL_DETAILS, report, 1, undefined, undefined, undefined, reports); + const result = createOption([1, 2], PERSONAL_DETAILS, report, 1, reports); expect(result.reportID).toBe(reportID); expect(typeof result.text).toBe('string'); @@ -3904,7 +3957,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); // Then it should return an option with isSelfDM and alternateText set expect(result.isSelfDM).toBe(true); @@ -3924,7 +3977,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); // Then it should return an option with invoice room text and alternateText expect(result.isInvoiceRoom).toBe(true); @@ -3946,7 +3999,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, unknownUserDetails, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined); + const result = getReportDisplayOption(report, unknownUserDetails, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); // Then it should return an option with unknownUserDetails data expect(result.text).toBe('Unknown User'); @@ -3967,7 +4020,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); // Then it should return an option with workspace name expect(result.text).toBe(POLICY.name); @@ -3994,7 +4047,7 @@ describe('OptionsListUtils', () => { }; // When we call getReportDisplayOption with custom personalDetails - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, customPersonalDetails, undefined); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, customPersonalDetails, undefined, REPORTS); // Then it should use the custom personalDetails parameter expect(result).toBeDefined(); @@ -4011,7 +4064,7 @@ describe('OptionsListUtils', () => { const emptyPersonalDetails: PersonalDetailsList = {}; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, emptyPersonalDetails, undefined); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, emptyPersonalDetails, undefined, REPORTS); // Then it should not throw and return a valid option expect(result).toBeDefined(); @@ -4023,7 +4076,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption with undefined report - const result = getReportDisplayOption(undefined, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined); + const result = getReportDisplayOption(undefined, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); // Then it should return a valid option (createOption handles undefined) expect(result).toBeDefined(); @@ -4048,7 +4101,7 @@ describe('OptionsListUtils', () => { const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`]: policy}; // Test that getValidOptions accepts policies collection as second parameter - const results = getValidOptions({reports: [], personalDetails: []}, policies, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); + const results = getValidOptions({reports: [], personalDetails: []}, policies, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4057,7 +4110,7 @@ describe('OptionsListUtils', () => { it('should work with undefined policies', () => { const options = {reports: [], personalDetails: []}; - const results = getValidOptions(options, undefined, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); + const results = getValidOptions(options, undefined, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4066,7 +4119,7 @@ describe('OptionsListUtils', () => { it('should work with empty policies collection', () => { const options = {reports: [], personalDetails: []}; - const results = getValidOptions(options, {}, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); + const results = getValidOptions(options, {}, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4098,6 +4151,7 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, + REPORTS, { betas: [], includeRecentReports: true, @@ -4404,7 +4458,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -4427,7 +4481,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -4447,7 +4501,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined, REPORTS); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -4471,7 +4525,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -4495,7 +4549,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -4806,7 +4860,7 @@ describe('OptionsListUtils', () => { selected: true, }; - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails, REPORTS); expect(option).toBeDefined(); expect(option.text).toBe('Test Workspace Policy'); @@ -4867,7 +4921,7 @@ describe('OptionsListUtils', () => { isPolicyExpenseChat: true, }; - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails, REPORTS); expect(option).toBeDefined(); expect(option.text).toBe('Team Workspace'); @@ -4911,7 +4965,7 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is empty - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, {}); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, {}, REPORTS); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Without Details'); @@ -4955,7 +5009,7 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is undefined - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, undefined); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, undefined, REPORTS); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Undefined Details'); @@ -5007,10 +5061,10 @@ describe('OptionsListUtils', () => { selected: false, }; - const optionSelected = getPolicyExpenseReportOption(participantSelected, CURRENT_USER_ACCOUNT_ID, {}); + const optionSelected = getPolicyExpenseReportOption(participantSelected, CURRENT_USER_ACCOUNT_ID, {}, REPORTS); // eslint-disable-next-line rulesdir/no-negated-variables - const optionNotSelected = getPolicyExpenseReportOption(participantNotSelected, CURRENT_USER_ACCOUNT_ID, {}); + const optionNotSelected = getPolicyExpenseReportOption(participantNotSelected, CURRENT_USER_ACCOUNT_ID, {}, REPORTS); expect(optionSelected.isSelected).toBe(true); expect(optionSelected.selected).toBe(true); @@ -5026,6 +5080,7 @@ describe('OptionsListUtils', () => { loginList: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); expect(result).toBeNull(); }); @@ -5037,6 +5092,7 @@ describe('OptionsListUtils', () => { loginList: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, }); expect(result).not.toBeNull(); expect(result?.login).toBe('Jeff Amazon'); From 12903dd7c6fb98bc3071e966b8ae6033a9974039 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 17:00:49 +0100 Subject: [PATCH 13/40] fixing eslint --- .../FilterDropdowns/UserSelectPopup.tsx | 49 +- .../SearchFiltersParticipantsSelector.tsx | 16 +- src/hooks/useSearchSelector.base.ts | 74 +- src/libs/OptionsListUtils/index.ts | 154 ++- src/libs/OptionsListUtils/types.ts | 33 +- src/pages/NewChatPage.tsx | 20 +- src/pages/RoomInvitePage.tsx | 11 +- .../MoneyRequestAccountantSelector.tsx | 18 +- tests/perf-test/OptionsListUtils.perf-test.ts | 98 +- tests/unit/OptionsListUtilsTest.tsx | 1047 +++++++++-------- 10 files changed, 800 insertions(+), 720 deletions(-) diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index e47fff7a691a..7682fb1d8fb5 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -96,42 +96,43 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele }, [selectedOptions]); const optionsList = useMemo(() => { - return memoizedGetValidOptions( - { + return memoizedGetValidOptions({ + options: { reports: options.reports, personalDetails: options.personalDetails, }, - allPolicies, + policies: allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - { - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - includeCurrentUser: true, - personalDetails, - }, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + includeCurrentUser: true, + personalDetails, countryCode, - ); - }, [options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode, personalDetails, currentUserAccountID, currentUserEmail, reports]); + }); + }, [ + options.reports, + options.personalDetails, + allPolicies, + draftComments, + nvpDismissedProductTraining, + loginList, + countryCode, + personalDetails, + currentUserAccountID, + currentUserEmail, + reports, + ]); const filteredOptions = useMemo(() => { - return filterAndOrderOptions( - optionsList, - cleanSearchTerm, - countryCode, - loginList, - currentUserEmail, - currentUserAccountID, - reports, - { - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, - canInviteUser: false, - }, - ); + return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, { + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + canInviteUser: false, + }); }, [optionsList, cleanSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, reports]); const listData = useMemo(() => { diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index 1d8b703232b3..9695023fccab 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -67,25 +67,23 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: return defaultListOptions; } - return memoizedGetValidOptions( - { + return memoizedGetValidOptions({ + options: { reports: options.reports, personalDetails: options.personalDetails, }, - allPolicies, + policies: allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - { - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - includeCurrentUser: true, - personalDetails, - }, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + includeCurrentUser: true, + personalDetails, countryCode, - ); + }); }, [ areOptionsInitialized, options.reports, diff --git a/src/hooks/useSearchSelector.base.ts b/src/hooks/useSearchSelector.base.ts index 3875be282128..871d81f782fe 100644 --- a/src/hooks/useSearchSelector.base.ts +++ b/src/hooks/useSearchSelector.base.ts @@ -210,7 +210,15 @@ function useSearchSelectorBase({ reports, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_MEMBER_INVITE: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { + return getValidOptions({ + options: optionsWithContacts, + policies: allPolicies, + draftComments, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, betas: betas ?? [], includeP2P: true, includeSelectedOptions: false, @@ -223,7 +231,15 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { + return getValidOptions({ + options: optionsWithContacts, + policies: allPolicies, + draftComments, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, ...getValidOptionsConfig, betas: betas ?? [], searchString: computedSearchTerm, @@ -234,33 +250,39 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_LOG: - return getValidOptions( - optionsWithContacts, - allPolicies, + return getValidOptions({ + options: optionsWithContacts, + policies: allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - { - betas, - includeMultipleParticipantReports: true, - includeP2P: true, - forcePolicyNamePreview: true, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - includeThreads: true, - includeReadOnly: false, - searchString: computedSearchTerm, - maxElements: maxResults, - includeUserToInvite, - personalDetails, - }, + betas, + includeMultipleParticipantReports: true, + includeP2P: true, + forcePolicyNamePreview: true, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + includeThreads: true, + includeReadOnly: false, + searchString: computedSearchTerm, + maxElements: maxResults, + includeUserToInvite, + personalDetails, countryCode, - ); + }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_DESTINATION: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { + return getValidOptions({ + options: optionsWithContacts, + policies: allPolicies, + draftComments, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, betas, selectedOptions, includeMultipleParticipantReports: true, @@ -279,7 +301,15 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_ATTENDEES: - return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { + return getValidOptions({ + options: optionsWithContacts, + policies: allPolicies, + draftComments, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, ...getValidOptionsConfig, betas: betas ?? [], includeP2P: true, diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 7fea9a10e7b2..84af8c4e5fa6 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -172,8 +172,10 @@ import type {Attendee, Participant} from '@src/types/onyx/IOU'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type { FilterUserToInviteConfig, + GetMemberInviteOptionsParams, GetOptionsConfig, GetUserToInviteConfig, + GetValidOptionsParams, GetValidReportsConfig, IsValidReportsConfig, MemberForList, @@ -2251,36 +2253,34 @@ function getRestrictedLogins( /** * Options are reports and personal details. This function filters out the options that are not valid to be displayed. */ -function getValidOptions( - options: OptionList, - policiesCollection: OnyxCollection, - draftComments: OnyxCollection | undefined, - nvpDismissedProductTraining: OnyxEntry, - loginList: OnyxEntry, - currentUserAccountID: number, - currentUserEmail: string, - reports: OnyxCollection, - { - excludeLogins = {}, - includeSelectedOptions = false, - includeRecentReports = true, - recentAttendees, - selectedOptions = [], - shouldSeparateSelfDMChat = false, - shouldSeparateWorkspaceChat = false, - excludeHiddenThreads = false, - canShowManagerMcTest = false, - searchString, - maxElements, - includeUserToInvite = false, - maxRecentReportElements = undefined, - shouldAcceptName = false, - personalDetails, - ...config - }: GetOptionsConfig = {}, - countryCode: number = CONST.DEFAULT_COUNTRY_CODE, - visibleReportActionsData: VisibleReportActionsDerivedValue = {}, -): Options { +function getValidOptions({ + options, + policies: policiesCollection, + draftComments, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, + countryCode = CONST.DEFAULT_COUNTRY_CODE, + visibleReportActionsData = {}, + excludeLogins = {}, + includeSelectedOptions = false, + includeRecentReports = true, + recentAttendees, + selectedOptions = [], + shouldSeparateSelfDMChat = false, + shouldSeparateWorkspaceChat = false, + excludeHiddenThreads = false, + canShowManagerMcTest = false, + searchString, + maxElements, + includeUserToInvite = false, + maxRecentReportElements = undefined, + shouldAcceptName = false, + personalDetails, + ...config +}: GetValidOptionsParams): Options { const restrictedLogins = getRestrictedLogins(config, options, canShowManagerMcTest, nvpDismissedProductTraining); // Gather shared configs: @@ -2556,39 +2556,37 @@ function getSearchOptions({ Timing.start(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markStart(CONST.TIMING.LOAD_SEARCH_OPTIONS); - const optionList = getValidOptions( + const optionList = getValidOptions({ options, - allPolicies, + policies: allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - { - betas, - includeRecentReports, - includeMultipleParticipantReports: true, - showChatPreviewLine: isUsedInChatFinder, - includeP2P: true, - includeOwnedWorkspaceChats: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - includeReadOnly, - includeSelfDM: true, - shouldBoldTitleByDefault: !isUsedInChatFinder, - excludeHiddenThreads: true, - maxElements: maxResults, - includeCurrentUser, - searchString: searchQuery, - includeUserToInvite, - shouldShowGBR, - shouldUnreadBeBold, - }, + betas, + includeRecentReports, + includeMultipleParticipantReports: true, + showChatPreviewLine: isUsedInChatFinder, + includeP2P: true, + includeOwnedWorkspaceChats: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + includeReadOnly, + includeSelfDM: true, + shouldBoldTitleByDefault: !isUsedInChatFinder, + excludeHiddenThreads: true, + maxElements: maxResults, + includeCurrentUser, + searchString: searchQuery, + includeUserToInvite, + shouldShowGBR, + shouldUnreadBeBold, countryCode, visibleReportActionsData, - ); + }); Timing.end(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markEnd(CONST.TIMING.LOAD_SEARCH_OPTIONS); @@ -2683,40 +2681,36 @@ function formatMemberForList(member: SearchOptionData): MemberForList { * Build the options for the Workspace Member Invite view * This method will be removed. See https://github.com/Expensify/App/issues/66615 for more information. */ -function getMemberInviteOptions( - personalDetails: Array>, - nvpDismissedProductTraining: OnyxEntry, - loginList: OnyxEntry, - currentUserAccountID: number, - currentUserEmail: string, - reports: OnyxCollection, - betas: Beta[] = [], - excludeLogins: Record = {}, +function getMemberInviteOptions({ + personalDetails, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, + betas = [], + excludeLogins = {}, includeSelectedOptions = false, - countryCode: number = CONST.DEFAULT_COUNTRY_CODE, - visibleReportActionsData: VisibleReportActionsDerivedValue = {}, -): Options { - return getValidOptions( - {personalDetails, reports: []}, - undefined, - undefined, + countryCode = CONST.DEFAULT_COUNTRY_CODE, + visibleReportActionsData = {}, +}: GetMemberInviteOptionsParams): Options { + return getValidOptions({ + options: {personalDetails, reports: []}, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - { - betas, - includeP2P: true, - excludeLogins, - includeSelectedOptions, - includeRecentReports: false, - searchString: '', - maxElements: undefined, - }, + betas, + includeP2P: true, + excludeLogins, + includeSelectedOptions, + includeRecentReports: false, + searchString: '', + maxElements: undefined, countryCode, visibleReportActionsData, - ); + }); } /** diff --git a/src/libs/OptionsListUtils/types.ts b/src/libs/OptionsListUtils/types.ts index d1e2d633870a..e575b7dce06e 100644 --- a/src/libs/OptionsListUtils/types.ts +++ b/src/libs/OptionsListUtils/types.ts @@ -2,7 +2,9 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {OptionData} from '@libs/ReportUtils'; import type {AvatarSource} from '@libs/UserAvatarUtils'; import type {IOUAction} from '@src/CONST'; -import type {Beta, Login, PersonalDetails, PersonalDetailsList, Report, ReportActions, TransactionViolation} from '@src/types/onyx'; +import type CONST from '@src/CONST'; +import type {Beta, DismissedProductTraining, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportActions, TransactionViolation} from '@src/types/onyx'; +import type {VisibleReportActionsDerivedValue} from '@src/types/onyx/DerivedValues'; import type {Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; /** @@ -276,10 +278,39 @@ type OrderReportOptionsConfig = { type ReportAndPersonalDetailOptions = Pick; +type GetValidOptionsParams = { + options: OptionList; + policies?: OnyxCollection; + draftComments?: OnyxCollection; + nvpDismissedProductTraining: OnyxEntry; + loginList: OnyxEntry; + currentUserAccountID: number; + currentUserEmail: string; + reports: OnyxCollection; + countryCode?: number; + visibleReportActionsData?: VisibleReportActionsDerivedValue; +} & GetOptionsConfig; + +type GetMemberInviteOptionsParams = { + personalDetails: Array>; + nvpDismissedProductTraining: OnyxEntry; + loginList: OnyxEntry; + currentUserAccountID: number; + currentUserEmail: string; + reports: OnyxCollection; + betas?: Beta[]; + excludeLogins?: Record; + includeSelectedOptions?: boolean; + countryCode?: number; + visibleReportActionsData?: VisibleReportActionsDerivedValue; +}; + export type { FilterUserToInviteConfig, + GetMemberInviteOptionsParams, GetOptionsConfig, GetUserToInviteConfig, + GetValidOptionsParams, GetValidOptionsSharedConfig, GetValidReportsConfig, MemberForList, diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 74edb0178819..499af7c6b5ea 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -95,26 +95,24 @@ function useOptions() { const reports = listOptions?.reports ?? []; const personalDetails = listOptions?.personalDetails ?? []; - const defaultOptions = getValidOptions( - { + const defaultOptions = getValidOptions({ + options: { reports, personalDetails: personalDetails.concat(contacts), }, - allPolicies, + policies: allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, - allReports, - { - betas: betas ?? [], - includeSelfDM: true, - shouldAlwaysIncludeDM: true, - personalDetails: allPersonalDetails, - }, + reports: allReports, + betas: betas ?? [], + includeSelfDM: true, + shouldAlwaysIncludeDM: true, + personalDetails: allPersonalDetails, countryCode, - ); + }); const unselectedOptions = filterSelectedOptions(defaultOptions, new Set(selectedOptions.map(({accountID}) => accountID))); diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index da5f6f727b0e..4969daf16a0b 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -97,7 +97,16 @@ function RoomInvitePage({ return {recentReports: [], personalDetails: [], userToInvite: null, currentUserOption: null}; } - const inviteOptions = getMemberInviteOptions(options.personalDetails, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, betas ?? [], excludedUsers); + const inviteOptions = getMemberInviteOptions({ + personalDetails: options.personalDetails, + nvpDismissedProductTraining, + loginList, + currentUserAccountID, + currentUserEmail, + reports, + betas: betas ?? [], + excludeLogins: excludedUsers, + }); // Update selectedOptions with the latest personalDetails information const detailsMap: Record = {}; for (const detail of inviteOptions.personalDetails) { diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 25a4f8418ddc..4a3775b33e1b 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -82,26 +82,24 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType getEmptyOptions(); } - const optionList = memoizedGetValidOptions( - { + const optionList = memoizedGetValidOptions({ + options: { reports: options.reports, personalDetails: options.personalDetails, }, - allPolicies, + policies: allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - { - betas, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - action, - personalDetails, - }, + betas, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + action, + personalDetails, countryCode, - ); + }); const orderedOptions = orderOptions(optionList); diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index d36c62ba31ca..33aac427a3d1 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -145,34 +145,34 @@ describe('OptionsListUtils', () => { /* Testing getFilteredOptions */ test('[OptionsListUtils] getFilteredOptions with search value', async () => { await waitForBatchedUpdates(); - const formattedOptions = getValidOptions( - {reports: options.reports, personalDetails: options.personalDetails}, - allPolicies, - {}, + const formattedOptions = getValidOptions({ + options: {reports: options.reports, personalDetails: options.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - MOCK_CURRENT_USER_ACCOUNT_ID, - MOCK_CURRENT_USER_EMAIL, - {}, - ValidOptionsConfig, - ); + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + reports: {}, + ...ValidOptionsConfig, + }); await measureFunction(() => { filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}); }); }); test('[OptionsListUtils] getFilteredOptions with empty search value', async () => { await waitForBatchedUpdates(); - const formattedOptions = getValidOptions( - {reports: options.reports, personalDetails: options.personalDetails}, - allPolicies, - {}, + const formattedOptions = getValidOptions({ + options: {reports: options.reports, personalDetails: options.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - MOCK_CURRENT_USER_ACCOUNT_ID, - MOCK_CURRENT_USER_EMAIL, - {}, - ValidOptionsConfig, - ); + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + reports: {}, + ...ValidOptionsConfig, + }); await measureFunction(() => { filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}); }); @@ -182,30 +182,28 @@ describe('OptionsListUtils', () => { test('[OptionsListUtils] getShareDestinationOptions', async () => { await waitForBatchedUpdates(); await measureFunction(() => - getValidOptions( - {reports: options.reports, personalDetails: options.personalDetails}, - allPolicies, - {}, + getValidOptions({ + options: {reports: options.reports, personalDetails: options.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - MOCK_CURRENT_USER_ACCOUNT_ID, - MOCK_CURRENT_USER_EMAIL, - {}, - { - betas: mockedBetas, - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }, - ), + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + reports: {}, + betas: mockedBetas, + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }), ); }); @@ -213,18 +211,18 @@ describe('OptionsListUtils', () => { test('[OptionsListUtils] getMemberInviteOptions', async () => { await waitForBatchedUpdates(); await measureFunction(() => - getMemberInviteOptions( - options.personalDetails, + getMemberInviteOptions({ + personalDetails: options.personalDetails, nvpDismissedProductTraining, loginList, - MOCK_CURRENT_USER_ACCOUNT_ID, - MOCK_CURRENT_USER_EMAIL, - {}, - mockedBetas, - {}, - false, - COUNTRY_CODE, - ), + currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, + currentUserEmail: MOCK_CURRENT_USER_EMAIL, + reports: {}, + betas: mockedBetas, + excludeLogins: {}, + includeSelectedOptions: false, + countryCode: COUNTRY_CODE, + }), ); }); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index aa5aaea66f97..3850ad15fc47 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -57,7 +57,7 @@ import initOnyxDerivedValues from '@userActions/OnyxDerived'; import CONST from '@src/CONST'; import IntlStore from '@src/languages/IntlStore'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetails, Policy, Report, ReportAction, ReportNameValuePairs, Transaction} from '@src/types/onyx'; +import type {DismissedProductTraining, PersonalDetails, Policy, Report, ReportAction, ReportNameValuePairs, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import createRandomReportAction from '../utils/collections/reportActions'; import {createRandomReport, createRegularChat} from '../utils/collections/reports'; @@ -734,19 +734,19 @@ describe('OptionsListUtils', () => { it('should sort options alphabetically and preserves reportID for personal details with existing reports', () => { // Given a set of reports and personalDetails // When we call getValidOptions() - let results: Pick = getValidOptions( - { + let results: Pick = getValidOptions({ + options: { reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails, }, - allPolicies, - {}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call orderOptions() results = orderOptions(results); @@ -777,16 +777,16 @@ describe('OptionsListUtils', () => { it('should sort personal details options alphabetically when only personal details are provided', () => { // Given a set of personalDetails and an empty reports array - let results: Pick = getValidOptions( - {personalDetails: OPTIONS.personalDetails, reports: []}, - allPolicies, - {}, + let results: Pick = getValidOptions({ + options: {personalDetails: OPTIONS.personalDetails, reports: []}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call orderOptions() results = orderOptions(results); @@ -813,7 +813,16 @@ describe('OptionsListUtils', () => { it('should return empty options when no reports or personal details are provided', () => { // Given empty arrays of reports and personalDetails // When we call getValidOptions() - const results = getValidOptions({reports: [], personalDetails: []}, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); + const results = getValidOptions({ + options: {reports: [], personalDetails: []}, + policies: allPolicies, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // Then the result should be empty expect(results.personalDetails).toEqual([]); @@ -827,16 +836,16 @@ describe('OptionsListUtils', () => { it('should include Concierge by default in results', () => { // Given a set of reports and personalDetails that includes Concierge // When we call getValidOptions() - const results = getValidOptions( - {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // Then the result should include all personalDetails except the currently logged in user expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 1); @@ -847,22 +856,20 @@ describe('OptionsListUtils', () => { it('should exclude Concierge when excludedLogins is specified', () => { // Given a set of reports and personalDetails that includes Concierge and a config object that excludes Concierge // When we call getValidOptions() - const results = getValidOptions( - { + const results = getValidOptions({ + options: { reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails, }, - allPolicies, - {}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, + }); // Then the result should include all personalDetails except the currently logged in user and Concierge expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 2); @@ -873,19 +880,17 @@ describe('OptionsListUtils', () => { it('should exclude Chronos when excludedLogins is specified', () => { // Given a set of reports and personalDetails that includes Chronos and a config object that excludes Chronos // When we call getValidOptions() - const results = getValidOptions( - {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, + }); // Then the result should include all personalDetails except the currently logged in user and Chronos expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CHRONOS.personalDetails).length - 2); @@ -896,22 +901,20 @@ describe('OptionsListUtils', () => { it('should exclude Receipts option from results when excludedLogins is specified', () => { // Given a set of reports and personalDetails that includes receipts and a config object that excludes receipts // When we call getValidOptions() - const results = getValidOptions( - { + const results = getValidOptions({ + options: { reports: OPTIONS_WITH_RECEIPTS.reports, personalDetails: OPTIONS_WITH_RECEIPTS.personalDetails, }, - allPolicies, - {}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, + }); // Then the result should include all personalDetails except the currently logged in user and receipts expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_RECEIPTS.personalDetails).length - 2); @@ -922,26 +925,23 @@ describe('OptionsListUtils', () => { it('should include Manager McTest in results by default', () => { // Given a set of reports and personalDetails that includes Manager McTest // When we call getValidOptions() - const result = getValidOptions( - {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - allPolicies, - {}, - { - // @ts-expect-error Mocked for testing + const result = getValidOptions({ + options: {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, + policies: allPolicies, + draftComments: {}, + nvpDismissedProductTraining: { [CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.RENAME_SAVED_SEARCH]: { timestamp: DateUtils.getDBTime(new Date().valueOf()), }, - }, + } as OnyxEntry, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeP2P: true, - canShowManagerMcTest: true, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeP2P: true, + canShowManagerMcTest: true, + betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + }); // Then the result should include all personalDetails except the currently logged in user expect(result.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 1); @@ -952,21 +952,19 @@ describe('OptionsListUtils', () => { it('should exclude Manager McTest from results if flag is set to false', () => { // Given a set of reports and personalDetails that includes Manager McTest and a config object that excludes Manager McTest // When we call getValidOptions() - const result = getValidOptions( - {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - allPolicies, - {}, + const result = getValidOptions({ + options: {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeP2P: true, - canShowManagerMcTest: false, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeP2P: true, + canShowManagerMcTest: false, + betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + }); // Then the result should include all personalDetails except the currently logged in user and Manager McTest expect(result.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 2); @@ -986,21 +984,19 @@ describe('OptionsListUtils', () => { ) .then(() => { // When we call getValidOptions() - const optionsWhenUserAlreadySubmittedExpense = getValidOptions( - {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - allPolicies, - {}, + const optionsWhenUserAlreadySubmittedExpense = getValidOptions({ + options: {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeP2P: true, - canShowManagerMcTest: true, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeP2P: true, + canShowManagerMcTest: true, + betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + }); // Then the result should include all personalDetails except the currently logged in user and Manager McTest expect(optionsWhenUserAlreadySubmittedExpense.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 2); @@ -1044,19 +1040,17 @@ describe('OptionsListUtils', () => { notificationPreference: 'hidden', }; // When we call getValidOptions with includeMultipleParticipantReports set to true - const results = getValidOptions( - {reports: [adminRoom], personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: [adminRoom], personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeMultipleParticipantReports: true, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeMultipleParticipantReports: true, + }); const adminRoomOption = results.recentReports.find((report) => report.reportID === '1455140530846319'); // Then the result should include the admin room @@ -1099,20 +1093,18 @@ describe('OptionsListUtils', () => { notificationPreference: 'hidden', brickRoadIndicator: CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, }; - const results = getValidOptions( - {reports: [workspaceChat], personalDetails: []}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: [workspaceChat], personalDetails: []}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeMultipleParticipantReports: true, - showRBR: true, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeMultipleParticipantReports: true, + showRBR: true, + }); expect(results.recentReports.at(0)?.brickRoadIndicator).toBe(CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR); }); @@ -1152,20 +1144,18 @@ describe('OptionsListUtils', () => { notificationPreference: 'hidden', brickRoadIndicator: CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, }; - const results = getValidOptions( - {reports: [workspaceChat], personalDetails: []}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: [workspaceChat], personalDetails: []}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeMultipleParticipantReports: true, - showRBR: false, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeMultipleParticipantReports: true, + showRBR: false, + }); expect(results.recentReports.at(0)?.brickRoadIndicator).toBe(null); }); @@ -1209,21 +1199,19 @@ describe('OptionsListUtils', () => { isBold: false, }; - const results = getValidOptions( - {reports: [inputOption], personalDetails: []}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: [inputOption], personalDetails: []}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - includeRecentReports: true, - shouldUnreadBeBold: true, - includeMultipleParticipantReports: true, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + includeRecentReports: true, + shouldUnreadBeBold: true, + includeMultipleParticipantReports: true, + }); expect(results.recentReports.at(0)?.isBold).toBe(true); expect(results.recentReports.at(0)?.isUnread).toBe(true); @@ -1245,19 +1233,17 @@ describe('OptionsListUtils', () => { }; // When we call getValidOptions with personalDetails parameter - const results = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - {}, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: {}, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - personalDetails: customPersonalDetails, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + personalDetails: customPersonalDetails, + }); // Then the function should complete without errors and return valid results // The personalDetails param is used internally by prepareReportOptionsForDisplay for workspace chats @@ -1270,7 +1256,15 @@ describe('OptionsListUtils', () => { it('should include all reports by default', () => { // Given a set of reports and personalDetails that includes workspace rooms // When we call getValidOptions() - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { + const results = getValidOptions({ + options: OPTIONS_WITH_WORKSPACE_ROOM, + policies: allPolicies, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1287,16 +1281,16 @@ describe('OptionsListUtils', () => { it('should exclude users with recent reports from personalDetails', () => { // Given a set of reports and personalDetails // When we call getValidOptions with no search value - const results = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); const reportLogins = new Set(results.recentReports.map((reportOption) => reportOption.login)); const personalDetailsOverlapWithReports = results.personalDetails.every((personalDetailOption) => reportLogins.has(personalDetailOption.login)); @@ -1309,19 +1303,17 @@ describe('OptionsListUtils', () => { it('should exclude selected options', () => { // Given a set of reports and personalDetails // When we call getValidOptions with excludeLogins param - const results = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {'peterparker@expensify.com': true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {'peterparker@expensify.com': true}, + }); // Then the option should not appear anywhere in either list expect(results.recentReports.every((option) => option.login !== 'peterparker@expensify.com')).toBe(true); @@ -1331,16 +1323,16 @@ describe('OptionsListUtils', () => { it('should include Concierge in the results by default', () => { // Given a set of report and personalDetails that include Concierge // When we call getValidOptions() - const results = getValidOptions( - {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // Then the result should include all personalDetails except the currently logged in user expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 1); @@ -1351,22 +1343,20 @@ describe('OptionsListUtils', () => { it('should exclude Concierge from the results when it is specified in excludedLogins', () => { // Given a set of reports and personalDetails that includes Concierge // When we call getValidOptions with excludeLogins param - const results = getValidOptions( - { + const results = getValidOptions({ + options: { reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails, }, - undefined, - {}, + policies: undefined, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, + }); // Then the result should include all personalDetails except the currently logged in user and Concierge expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 2); @@ -1378,19 +1368,17 @@ describe('OptionsListUtils', () => { it('should exclude Chronos from the results when it is specified in excludedLogins', () => { // given a set of reports and personalDetails that includes Chronos // When we call getValidOptions() with excludeLogins param - const results = getValidOptions( - {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, + }); // Then the result should include all personalDetails except the currently logged in user and Chronos expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CHRONOS.personalDetails).length - 2); @@ -1402,22 +1390,20 @@ describe('OptionsListUtils', () => { it('should exclude Receipts from the results when it is specified in excludedLogins', () => { // Given a set of reports and personalDetails that includes receipts // When we call getValidOptions() with excludeLogins param - const results = getValidOptions( - { + const results = getValidOptions({ + options: { reports: OPTIONS_WITH_RECEIPTS.reports, personalDetails: OPTIONS_WITH_RECEIPTS.personalDetails, }, - undefined, - {}, + policies: undefined, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, + }); // Then the result should include all personalDetails except the currently logged in user and receipts expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_RECEIPTS.personalDetails).length - 2); @@ -1430,19 +1416,17 @@ describe('OptionsListUtils', () => { // Given a set of reports and personalDetails with multiple reports // When we call getValidOptions with maxRecentReportElements set to 2 const maxRecentReports = 2; - const results = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - maxRecentReportElements: maxRecentReports, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + maxRecentReportElements: maxRecentReports, + }); // Then the recent reports should be limited to the specified number expect(results.recentReports.length).toBeLessThanOrEqual(maxRecentReports); @@ -1451,29 +1435,27 @@ describe('OptionsListUtils', () => { it('should show all reports when maxRecentReportElements is not specified', () => { // Given a set of reports and personalDetails // When we call getValidOptions without maxRecentReportElements - const resultsWithoutLimit = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const resultsWithoutLimit = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); - const resultsWithLimit = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); + const resultsWithLimit = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - maxRecentReportElements: 2, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + maxRecentReportElements: 2, + }); // Then the results without limit should have more or equal reports expect(resultsWithoutLimit.recentReports.length).toBeGreaterThanOrEqual(resultsWithLimit.recentReports.length); @@ -1482,29 +1464,27 @@ describe('OptionsListUtils', () => { it('should not affect personalDetails count when maxRecentReportElements is specified', () => { // Given a set of reports and personalDetails // When we call getValidOptions with and without maxRecentReportElements - const resultsWithoutLimit = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const resultsWithoutLimit = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); - const resultsWithLimit = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); + const resultsWithLimit = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - maxRecentReportElements: 2, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + maxRecentReportElements: 2, + }); // Then personalDetails should remain the same regardless of maxRecentReportElements expect(resultsWithLimit.personalDetails.length).toBe(resultsWithoutLimit.personalDetails.length); @@ -1515,20 +1495,18 @@ describe('OptionsListUtils', () => { // When we call getValidOptions with both maxElements and maxRecentReportElements const maxRecentReports = 3; const maxTotalElements = 10; - const results = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - maxElements: maxTotalElements, - maxRecentReportElements: maxRecentReports, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + maxElements: maxTotalElements, + maxRecentReportElements: maxRecentReports, + }); // Then recent reports should be limited by maxRecentReportElements expect(results.recentReports.length).toBeLessThanOrEqual(maxRecentReports); @@ -1550,30 +1528,28 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with an empty search value - const results = getValidOptions( - {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }); // Then all the recent reports should be returned except the archived rooms and the hidden thread expect(results.recentReports.length).toBe(Object.values(OPTIONS.reports).length - 2); @@ -1592,30 +1568,28 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with an empty search value - const results = getValidOptions( - {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const results = getValidOptions({ + options: {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }); // Then all recent reports should be returned except the archived rooms and the hidden thread expect(results.recentReports.length).toBe(Object.values(OPTIONS_WITH_WORKSPACE_ROOM.reports).length - 2); @@ -1626,7 +1600,15 @@ describe('OptionsListUtils', () => { it('should sort personal details alphabetically and return expected structure', () => { // Given a set of personalDetails // When we call getMemberInviteOptions - const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); + const results = getMemberInviteOptions({ + personalDetails: OPTIONS.personalDetails, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + }); // Then personal details should be sorted alphabetically expect(results.personalDetails.at(0)?.text).toBe('Black Panther'); @@ -1642,10 +1624,19 @@ describe('OptionsListUtils', () => { it('should exclude logins when excludeLogins is provided', () => { // Given a set of personalDetails and excludeLogins - const excludeLogins = {'reedrichards@expensify.com': true}; + const excludeLoginsMap = {'reedrichards@expensify.com': true}; // When we call getMemberInviteOptions with excludeLogins - const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, [], excludeLogins); + const results = getMemberInviteOptions({ + personalDetails: OPTIONS.personalDetails, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + excludeLogins: excludeLoginsMap, + }); // Then the excluded login should not be in the results const excludedUser = results.personalDetails.find((detail) => detail.login === 'reedrichards@expensify.com'); @@ -2066,19 +2057,17 @@ describe('OptionsListUtils', () => { it('should not return any results if the search value is on an excluded logins list', () => { const searchText = 'admin@expensify.com'; // Given a set of options with excluded logins list - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + }); // When we call filterAndOrderOptions with a search value and excluded logins list const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, @@ -2163,7 +2152,15 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); + const options = getMemberInviteOptions({ + personalDetails: OPTIONS.personalDetails, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + }); // When we call filterAndOrderOptions with a search value that does not match any personal details const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2173,7 +2170,15 @@ describe('OptionsListUtils', () => { it('should return one personal detail if search value matches an email (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); + const options = getMemberInviteOptions({ + personalDetails: OPTIONS.personalDetails, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + }); // When we call filterAndOrderOptions with a search value that matches an email const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2193,30 +2198,28 @@ describe('OptionsListUtils', () => { return filtered; }, []); // When we call getValidOptions for share destination with the filteredReports - const options = getValidOptions( - {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2236,30 +2239,28 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with the filteredReports - const options = getValidOptions( - {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }); // When we pass the returned options to filterAndOrderOptions with a search value that matches the group chat name const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2279,22 +2280,21 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with the filteredReports - const options = getValidOptions( - {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, includeTasks: true, excludeLogins: {}, includeOwnedWorkspaceChats: true, @@ -2312,16 +2312,16 @@ describe('OptionsListUtils', () => { it('should show the option from personal details when searching for personal detail with no existing report', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that matches a personal detail with no existing report const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2335,16 +2335,16 @@ describe('OptionsListUtils', () => { it('should not return any options or user to invite if there are no search results and the string does not match a potential email or phone', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2357,16 +2357,16 @@ describe('OptionsListUtils', () => { it('should not return any options but should return an user to invite if no matching options exist and the search value is a potential email', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2379,16 +2379,16 @@ describe('OptionsListUtils', () => { it('should return user to invite when search term has a period with options for it that do not contain the period', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2400,16 +2400,16 @@ describe('OptionsListUtils', () => { it('should return user which has displayName with accent mark when search value without accent mark', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value without accent mark const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2419,16 +2419,16 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2443,16 +2443,16 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number with country code added', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2467,16 +2467,16 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number with special characters added', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2491,16 +2491,16 @@ describe('OptionsListUtils', () => { it('should not return any options or user to invite if contact number contains alphabet characters', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2513,16 +2513,16 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that does not match any personal details const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2532,16 +2532,16 @@ describe('OptionsListUtils', () => { it('should return one recent report and no personal details if a search value provides an email', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that matches an email const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { sortByReportTypeInSearch: true, @@ -2557,16 +2557,16 @@ describe('OptionsListUtils', () => { it('should return all matching reports and personal details', () => { // Given a set of options - const options = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - allPolicies, - {}, + const options = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + policies: allPolicies, + draftComments: {}, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); // When we call filterAndOrderOptions with a search value that matches both reports and personal details and maxRecentReportsToShow param const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { maxRecentReportsToShow: 5, @@ -4101,7 +4101,16 @@ describe('OptionsListUtils', () => { const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`]: policy}; // Test that getValidOptions accepts policies collection as second parameter - const results = getValidOptions({reports: [], personalDetails: []}, policies, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); + const results = getValidOptions({ + options: {reports: [], personalDetails: []}, + policies, + draftComments: undefined, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4109,8 +4118,16 @@ describe('OptionsListUtils', () => { }); it('should work with undefined policies', () => { - const options = {reports: [], personalDetails: []}; - const results = getValidOptions(options, undefined, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); + const results = getValidOptions({ + options: {reports: [], personalDetails: []}, + policies: undefined, + draftComments: undefined, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4118,8 +4135,16 @@ describe('OptionsListUtils', () => { }); it('should work with empty policies collection', () => { - const options = {reports: [], personalDetails: []}; - const results = getValidOptions(options, {}, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); + const results = getValidOptions({ + options: {reports: [], personalDetails: []}, + policies: {}, + draftComments: undefined, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4143,20 +4168,18 @@ describe('OptionsListUtils', () => { const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${testPolicyID}`]: policy}; // Verify function works with policies parameter - const results = getValidOptions( - {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + const results = getValidOptions({ + options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, policies, - undefined, + draftComments: undefined, nvpDismissedProductTraining, loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - REPORTS, - { - betas: [], - includeRecentReports: true, - }, - ); + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + betas: [], + includeRecentReports: true, + }); expect(results.recentReports).toBeDefined(); expect(Array.isArray(results.recentReports)).toBe(true); From 6a90d9b2e440275b1396eafcc88e2faa3bb00926 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 17:21:18 +0100 Subject: [PATCH 14/40] fixing prettier --- .../FilterDropdowns/UserSelectPopup.tsx | 16 +- .../SearchFiltersParticipantsSelector.tsx | 16 +- src/hooks/useSearchSelector.base.ts | 74 +- src/libs/OptionsListUtils/index.ts | 157 +-- src/libs/OptionsListUtils/types.ts | 33 +- src/pages/NewChatPage.tsx | 20 +- src/pages/RoomInvitePage.tsx | 10 +- .../MoneyRequestAccountantSelector.tsx | 18 +- tests/perf-test/OptionsListUtils.perf-test.ts | 98 +- tests/unit/OptionsListUtilsTest.tsx | 1055 ++++++++--------- 10 files changed, 724 insertions(+), 773 deletions(-) diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index 7682fb1d8fb5..e83b764516de 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -96,23 +96,25 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele }, [selectedOptions]); const optionsList = useMemo(() => { - return memoizedGetValidOptions({ - options: { + return memoizedGetValidOptions( + { reports: options.reports, personalDetails: options.personalDetails, }, - policies: allPolicies, + allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - includeCurrentUser: true, - personalDetails, + { + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + includeCurrentUser: true, + personalDetails, + }, countryCode, - }); + ); }, [ options.reports, options.personalDetails, diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index 9695023fccab..1d8b703232b3 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -67,23 +67,25 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: return defaultListOptions; } - return memoizedGetValidOptions({ - options: { + return memoizedGetValidOptions( + { reports: options.reports, personalDetails: options.personalDetails, }, - policies: allPolicies, + allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - includeCurrentUser: true, - personalDetails, + { + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + includeCurrentUser: true, + personalDetails, + }, countryCode, - }); + ); }, [ areOptionsInitialized, options.reports, diff --git a/src/hooks/useSearchSelector.base.ts b/src/hooks/useSearchSelector.base.ts index 871d81f782fe..3875be282128 100644 --- a/src/hooks/useSearchSelector.base.ts +++ b/src/hooks/useSearchSelector.base.ts @@ -210,15 +210,7 @@ function useSearchSelectorBase({ reports, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_MEMBER_INVITE: - return getValidOptions({ - options: optionsWithContacts, - policies: allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - reports, + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { betas: betas ?? [], includeP2P: true, includeSelectedOptions: false, @@ -231,15 +223,7 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL: - return getValidOptions({ - options: optionsWithContacts, - policies: allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - reports, + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { ...getValidOptionsConfig, betas: betas ?? [], searchString: computedSearchTerm, @@ -250,39 +234,33 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_LOG: - return getValidOptions({ - options: optionsWithContacts, - policies: allPolicies, + return getValidOptions( + optionsWithContacts, + allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - betas, - includeMultipleParticipantReports: true, - includeP2P: true, - forcePolicyNamePreview: true, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - includeThreads: true, - includeReadOnly: false, - searchString: computedSearchTerm, - maxElements: maxResults, - includeUserToInvite, - personalDetails, + { + betas, + includeMultipleParticipantReports: true, + includeP2P: true, + forcePolicyNamePreview: true, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + includeThreads: true, + includeReadOnly: false, + searchString: computedSearchTerm, + maxElements: maxResults, + includeUserToInvite, + personalDetails, + }, countryCode, - }); + ); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_DESTINATION: - return getValidOptions({ - options: optionsWithContacts, - policies: allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - reports, + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { betas, selectedOptions, includeMultipleParticipantReports: true, @@ -301,15 +279,7 @@ function useSearchSelectorBase({ personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_ATTENDEES: - return getValidOptions({ - options: optionsWithContacts, - policies: allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - reports, + return getValidOptions(optionsWithContacts, allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, { ...getValidOptionsConfig, betas: betas ?? [], includeP2P: true, diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 84af8c4e5fa6..40619976382c 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -172,10 +172,8 @@ import type {Attendee, Participant} from '@src/types/onyx/IOU'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type { FilterUserToInviteConfig, - GetMemberInviteOptionsParams, GetOptionsConfig, GetUserToInviteConfig, - GetValidOptionsParams, GetValidReportsConfig, IsValidReportsConfig, MemberForList, @@ -2253,34 +2251,36 @@ function getRestrictedLogins( /** * Options are reports and personal details. This function filters out the options that are not valid to be displayed. */ -function getValidOptions({ - options, - policies: policiesCollection, - draftComments, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - reports, - countryCode = CONST.DEFAULT_COUNTRY_CODE, - visibleReportActionsData = {}, - excludeLogins = {}, - includeSelectedOptions = false, - includeRecentReports = true, - recentAttendees, - selectedOptions = [], - shouldSeparateSelfDMChat = false, - shouldSeparateWorkspaceChat = false, - excludeHiddenThreads = false, - canShowManagerMcTest = false, - searchString, - maxElements, - includeUserToInvite = false, - maxRecentReportElements = undefined, - shouldAcceptName = false, - personalDetails, - ...config -}: GetValidOptionsParams): Options { +function getValidOptions( + options: OptionList, + policiesCollection: OnyxCollection, + draftComments: OnyxCollection | undefined, + nvpDismissedProductTraining: OnyxEntry, + loginList: OnyxEntry, + currentUserAccountID: number, + currentUserEmail: string, + reports: OnyxCollection, + { + excludeLogins = {}, + includeSelectedOptions = false, + includeRecentReports = true, + recentAttendees, + selectedOptions = [], + shouldSeparateSelfDMChat = false, + shouldSeparateWorkspaceChat = false, + excludeHiddenThreads = false, + canShowManagerMcTest = false, + searchString, + maxElements, + includeUserToInvite = false, + maxRecentReportElements = undefined, + shouldAcceptName = false, + personalDetails, + ...config + }: GetOptionsConfig = {}, + countryCode: number = CONST.DEFAULT_COUNTRY_CODE, + visibleReportActionsData: VisibleReportActionsDerivedValue = {}, +): Options { const restrictedLogins = getRestrictedLogins(config, options, canShowManagerMcTest, nvpDismissedProductTraining); // Gather shared configs: @@ -2527,6 +2527,7 @@ type SearchOptionsConfig = { currentUserAccountID: number; currentUserEmail: string; personalDetails?: OnyxEntry; + reports: OnyxCollection; }; /** @@ -2552,41 +2553,43 @@ function getSearchOptions({ currentUserAccountID, currentUserEmail, reports, -}: SearchOptionsConfig & {reports: OnyxCollection}): Options { +}: SearchOptionsConfig): Options { Timing.start(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markStart(CONST.TIMING.LOAD_SEARCH_OPTIONS); - const optionList = getValidOptions({ + const optionList = getValidOptions( options, - policies: allPolicies, + allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - betas, - includeRecentReports, - includeMultipleParticipantReports: true, - showChatPreviewLine: isUsedInChatFinder, - includeP2P: true, - includeOwnedWorkspaceChats: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - includeReadOnly, - includeSelfDM: true, - shouldBoldTitleByDefault: !isUsedInChatFinder, - excludeHiddenThreads: true, - maxElements: maxResults, - includeCurrentUser, - searchString: searchQuery, - includeUserToInvite, - shouldShowGBR, - shouldUnreadBeBold, + { + betas, + includeRecentReports, + includeMultipleParticipantReports: true, + showChatPreviewLine: isUsedInChatFinder, + includeP2P: true, + includeOwnedWorkspaceChats: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + includeReadOnly, + includeSelfDM: true, + shouldBoldTitleByDefault: !isUsedInChatFinder, + excludeHiddenThreads: true, + maxElements: maxResults, + includeCurrentUser, + searchString: searchQuery, + includeUserToInvite, + shouldShowGBR, + shouldUnreadBeBold, + }, countryCode, visibleReportActionsData, - }); + ); Timing.end(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markEnd(CONST.TIMING.LOAD_SEARCH_OPTIONS); @@ -2681,36 +2684,40 @@ function formatMemberForList(member: SearchOptionData): MemberForList { * Build the options for the Workspace Member Invite view * This method will be removed. See https://github.com/Expensify/App/issues/66615 for more information. */ -function getMemberInviteOptions({ - personalDetails, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - reports, - betas = [], - excludeLogins = {}, +function getMemberInviteOptions( + personalDetails: Array>, + nvpDismissedProductTraining: OnyxEntry, + loginList: OnyxEntry, + currentUserAccountID: number, + currentUserEmail: string, + reports: OnyxCollection, + betas: Beta[] = [], + excludeLogins: Record = {}, includeSelectedOptions = false, - countryCode = CONST.DEFAULT_COUNTRY_CODE, - visibleReportActionsData = {}, -}: GetMemberInviteOptionsParams): Options { - return getValidOptions({ - options: {personalDetails, reports: []}, + countryCode: number = CONST.DEFAULT_COUNTRY_CODE, + visibleReportActionsData: VisibleReportActionsDerivedValue = {}, +): Options { + return getValidOptions( + {personalDetails, reports: []}, + undefined, + undefined, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - betas, - includeP2P: true, - excludeLogins, - includeSelectedOptions, - includeRecentReports: false, - searchString: '', - maxElements: undefined, + { + betas, + includeP2P: true, + excludeLogins, + includeSelectedOptions, + includeRecentReports: false, + searchString: '', + maxElements: undefined, + }, countryCode, visibleReportActionsData, - }); + ); } /** diff --git a/src/libs/OptionsListUtils/types.ts b/src/libs/OptionsListUtils/types.ts index e575b7dce06e..d1e2d633870a 100644 --- a/src/libs/OptionsListUtils/types.ts +++ b/src/libs/OptionsListUtils/types.ts @@ -2,9 +2,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {OptionData} from '@libs/ReportUtils'; import type {AvatarSource} from '@libs/UserAvatarUtils'; import type {IOUAction} from '@src/CONST'; -import type CONST from '@src/CONST'; -import type {Beta, DismissedProductTraining, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportActions, TransactionViolation} from '@src/types/onyx'; -import type {VisibleReportActionsDerivedValue} from '@src/types/onyx/DerivedValues'; +import type {Beta, Login, PersonalDetails, PersonalDetailsList, Report, ReportActions, TransactionViolation} from '@src/types/onyx'; import type {Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; /** @@ -278,39 +276,10 @@ type OrderReportOptionsConfig = { type ReportAndPersonalDetailOptions = Pick; -type GetValidOptionsParams = { - options: OptionList; - policies?: OnyxCollection; - draftComments?: OnyxCollection; - nvpDismissedProductTraining: OnyxEntry; - loginList: OnyxEntry; - currentUserAccountID: number; - currentUserEmail: string; - reports: OnyxCollection; - countryCode?: number; - visibleReportActionsData?: VisibleReportActionsDerivedValue; -} & GetOptionsConfig; - -type GetMemberInviteOptionsParams = { - personalDetails: Array>; - nvpDismissedProductTraining: OnyxEntry; - loginList: OnyxEntry; - currentUserAccountID: number; - currentUserEmail: string; - reports: OnyxCollection; - betas?: Beta[]; - excludeLogins?: Record; - includeSelectedOptions?: boolean; - countryCode?: number; - visibleReportActionsData?: VisibleReportActionsDerivedValue; -}; - export type { FilterUserToInviteConfig, - GetMemberInviteOptionsParams, GetOptionsConfig, GetUserToInviteConfig, - GetValidOptionsParams, GetValidOptionsSharedConfig, GetValidReportsConfig, MemberForList, diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 499af7c6b5ea..74edb0178819 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -95,24 +95,26 @@ function useOptions() { const reports = listOptions?.reports ?? []; const personalDetails = listOptions?.personalDetails ?? []; - const defaultOptions = getValidOptions({ - options: { + const defaultOptions = getValidOptions( + { reports, personalDetails: personalDetails.concat(contacts), }, - policies: allPolicies, + allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, - reports: allReports, - betas: betas ?? [], - includeSelfDM: true, - shouldAlwaysIncludeDM: true, - personalDetails: allPersonalDetails, + allReports, + { + betas: betas ?? [], + includeSelfDM: true, + shouldAlwaysIncludeDM: true, + personalDetails: allPersonalDetails, + }, countryCode, - }); + ); const unselectedOptions = filterSelectedOptions(defaultOptions, new Set(selectedOptions.map(({accountID}) => accountID))); diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 4969daf16a0b..a6079757537e 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -97,16 +97,16 @@ function RoomInvitePage({ return {recentReports: [], personalDetails: [], userToInvite: null, currentUserOption: null}; } - const inviteOptions = getMemberInviteOptions({ - personalDetails: options.personalDetails, + const inviteOptions = getMemberInviteOptions( + options.personalDetails, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - betas: betas ?? [], - excludeLogins: excludedUsers, - }); + betas ?? [], + excludedUsers, + ); // Update selectedOptions with the latest personalDetails information const detailsMap: Record = {}; for (const detail of inviteOptions.personalDetails) { diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 4a3775b33e1b..25a4f8418ddc 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -82,24 +82,26 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType getEmptyOptions(); } - const optionList = memoizedGetValidOptions({ - options: { + const optionList = memoizedGetValidOptions( + { reports: options.reports, personalDetails: options.personalDetails, }, - policies: allPolicies, + allPolicies, draftComments, nvpDismissedProductTraining, loginList, currentUserAccountID, currentUserEmail, reports, - betas, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - action, - personalDetails, + { + betas, + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + action, + personalDetails, + }, countryCode, - }); + ); const orderedOptions = orderOptions(optionList); diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index 33aac427a3d1..d36c62ba31ca 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -145,34 +145,34 @@ describe('OptionsListUtils', () => { /* Testing getFilteredOptions */ test('[OptionsListUtils] getFilteredOptions with search value', async () => { await waitForBatchedUpdates(); - const formattedOptions = getValidOptions({ - options: {reports: options.reports, personalDetails: options.personalDetails}, - policies: allPolicies, - draftComments: {}, + const formattedOptions = getValidOptions( + {reports: options.reports, personalDetails: options.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, - currentUserEmail: MOCK_CURRENT_USER_EMAIL, - reports: {}, - ...ValidOptionsConfig, - }); + MOCK_CURRENT_USER_ACCOUNT_ID, + MOCK_CURRENT_USER_EMAIL, + {}, + ValidOptionsConfig, + ); await measureFunction(() => { filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}); }); }); test('[OptionsListUtils] getFilteredOptions with empty search value', async () => { await waitForBatchedUpdates(); - const formattedOptions = getValidOptions({ - options: {reports: options.reports, personalDetails: options.personalDetails}, - policies: allPolicies, - draftComments: {}, + const formattedOptions = getValidOptions( + {reports: options.reports, personalDetails: options.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, - currentUserEmail: MOCK_CURRENT_USER_EMAIL, - reports: {}, - ...ValidOptionsConfig, - }); + MOCK_CURRENT_USER_ACCOUNT_ID, + MOCK_CURRENT_USER_EMAIL, + {}, + ValidOptionsConfig, + ); await measureFunction(() => { filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}); }); @@ -182,28 +182,30 @@ describe('OptionsListUtils', () => { test('[OptionsListUtils] getShareDestinationOptions', async () => { await waitForBatchedUpdates(); await measureFunction(() => - getValidOptions({ - options: {reports: options.reports, personalDetails: options.personalDetails}, - policies: allPolicies, - draftComments: {}, + getValidOptions( + {reports: options.reports, personalDetails: options.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, - currentUserEmail: MOCK_CURRENT_USER_EMAIL, - reports: {}, - betas: mockedBetas, - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }), + MOCK_CURRENT_USER_ACCOUNT_ID, + MOCK_CURRENT_USER_EMAIL, + {}, + { + betas: mockedBetas, + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }, + ), ); }); @@ -211,18 +213,18 @@ describe('OptionsListUtils', () => { test('[OptionsListUtils] getMemberInviteOptions', async () => { await waitForBatchedUpdates(); await measureFunction(() => - getMemberInviteOptions({ - personalDetails: options.personalDetails, + getMemberInviteOptions( + options.personalDetails, nvpDismissedProductTraining, loginList, - currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, - currentUserEmail: MOCK_CURRENT_USER_EMAIL, - reports: {}, - betas: mockedBetas, - excludeLogins: {}, - includeSelectedOptions: false, - countryCode: COUNTRY_CODE, - }), + MOCK_CURRENT_USER_ACCOUNT_ID, + MOCK_CURRENT_USER_EMAIL, + {}, + mockedBetas, + {}, + false, + COUNTRY_CODE, + ), ); }); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 3850ad15fc47..e4bbc3ec976a 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -57,7 +57,7 @@ import initOnyxDerivedValues from '@userActions/OnyxDerived'; import CONST from '@src/CONST'; import IntlStore from '@src/languages/IntlStore'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {DismissedProductTraining, PersonalDetails, Policy, Report, ReportAction, ReportNameValuePairs, Transaction} from '@src/types/onyx'; +import type {PersonalDetails, Policy, Report, ReportAction, ReportNameValuePairs, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import createRandomReportAction from '../utils/collections/reportActions'; import {createRandomReport, createRegularChat} from '../utils/collections/reports'; @@ -734,19 +734,19 @@ describe('OptionsListUtils', () => { it('should sort options alphabetically and preserves reportID for personal details with existing reports', () => { // Given a set of reports and personalDetails // When we call getValidOptions() - let results: Pick = getValidOptions({ - options: { + let results: Pick = getValidOptions( + { reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails, }, - policies: allPolicies, - draftComments: {}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call orderOptions() results = orderOptions(results); @@ -777,16 +777,16 @@ describe('OptionsListUtils', () => { it('should sort personal details options alphabetically when only personal details are provided', () => { // Given a set of personalDetails and an empty reports array - let results: Pick = getValidOptions({ - options: {personalDetails: OPTIONS.personalDetails, reports: []}, - policies: allPolicies, - draftComments: {}, + let results: Pick = getValidOptions( + {personalDetails: OPTIONS.personalDetails, reports: []}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call orderOptions() results = orderOptions(results); @@ -813,16 +813,16 @@ describe('OptionsListUtils', () => { it('should return empty options when no reports or personal details are provided', () => { // Given empty arrays of reports and personalDetails // When we call getValidOptions() - const results = getValidOptions({ - options: {reports: [], personalDetails: []}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: [], personalDetails: []}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // Then the result should be empty expect(results.personalDetails).toEqual([]); @@ -836,16 +836,16 @@ describe('OptionsListUtils', () => { it('should include Concierge by default in results', () => { // Given a set of reports and personalDetails that includes Concierge // When we call getValidOptions() - const results = getValidOptions({ - options: {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // Then the result should include all personalDetails except the currently logged in user expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 1); @@ -856,20 +856,22 @@ describe('OptionsListUtils', () => { it('should exclude Concierge when excludedLogins is specified', () => { // Given a set of reports and personalDetails that includes Concierge and a config object that excludes Concierge // When we call getValidOptions() - const results = getValidOptions({ - options: { + const results = getValidOptions( + { reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails, }, - policies: allPolicies, - draftComments: {}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, + }, + ); // Then the result should include all personalDetails except the currently logged in user and Concierge expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 2); @@ -880,17 +882,19 @@ describe('OptionsListUtils', () => { it('should exclude Chronos when excludedLogins is specified', () => { // Given a set of reports and personalDetails that includes Chronos and a config object that excludes Chronos // When we call getValidOptions() - const results = getValidOptions({ - options: {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, + }, + ); // Then the result should include all personalDetails except the currently logged in user and Chronos expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CHRONOS.personalDetails).length - 2); @@ -901,20 +905,22 @@ describe('OptionsListUtils', () => { it('should exclude Receipts option from results when excludedLogins is specified', () => { // Given a set of reports and personalDetails that includes receipts and a config object that excludes receipts // When we call getValidOptions() - const results = getValidOptions({ - options: { + const results = getValidOptions( + { reports: OPTIONS_WITH_RECEIPTS.reports, personalDetails: OPTIONS_WITH_RECEIPTS.personalDetails, }, - policies: allPolicies, - draftComments: {}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, + }, + ); // Then the result should include all personalDetails except the currently logged in user and receipts expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_RECEIPTS.personalDetails).length - 2); @@ -925,23 +931,26 @@ describe('OptionsListUtils', () => { it('should include Manager McTest in results by default', () => { // Given a set of reports and personalDetails that includes Manager McTest // When we call getValidOptions() - const result = getValidOptions({ - options: {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - policies: allPolicies, - draftComments: {}, - nvpDismissedProductTraining: { + const result = getValidOptions( + {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, + allPolicies, + {}, + { + // @ts-expect-error Mocked for testing [CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.RENAME_SAVED_SEARCH]: { timestamp: DateUtils.getDBTime(new Date().valueOf()), }, - } as OnyxEntry, + }, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeP2P: true, - canShowManagerMcTest: true, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeP2P: true, + canShowManagerMcTest: true, + betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + }, + ); // Then the result should include all personalDetails except the currently logged in user expect(result.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 1); @@ -952,19 +961,21 @@ describe('OptionsListUtils', () => { it('should exclude Manager McTest from results if flag is set to false', () => { // Given a set of reports and personalDetails that includes Manager McTest and a config object that excludes Manager McTest // When we call getValidOptions() - const result = getValidOptions({ - options: {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - policies: allPolicies, - draftComments: {}, + const result = getValidOptions( + {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeP2P: true, - canShowManagerMcTest: false, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeP2P: true, + canShowManagerMcTest: false, + betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + }, + ); // Then the result should include all personalDetails except the currently logged in user and Manager McTest expect(result.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 2); @@ -984,19 +995,21 @@ describe('OptionsListUtils', () => { ) .then(() => { // When we call getValidOptions() - const optionsWhenUserAlreadySubmittedExpense = getValidOptions({ - options: {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, - policies: allPolicies, - draftComments: {}, + const optionsWhenUserAlreadySubmittedExpense = getValidOptions( + {reports: OPTIONS_WITH_MANAGER_MCTEST.reports, personalDetails: OPTIONS_WITH_MANAGER_MCTEST.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeP2P: true, - canShowManagerMcTest: true, - betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeP2P: true, + canShowManagerMcTest: true, + betas: [CONST.BETAS.NEWDOT_MANAGER_MCTEST], + }, + ); // Then the result should include all personalDetails except the currently logged in user and Manager McTest expect(optionsWhenUserAlreadySubmittedExpense.personalDetails.length).toBe(Object.values(OPTIONS_WITH_MANAGER_MCTEST.personalDetails).length - 2); @@ -1040,17 +1053,19 @@ describe('OptionsListUtils', () => { notificationPreference: 'hidden', }; // When we call getValidOptions with includeMultipleParticipantReports set to true - const results = getValidOptions({ - options: {reports: [adminRoom], personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: [adminRoom], personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeMultipleParticipantReports: true, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeMultipleParticipantReports: true, + }, + ); const adminRoomOption = results.recentReports.find((report) => report.reportID === '1455140530846319'); // Then the result should include the admin room @@ -1093,18 +1108,20 @@ describe('OptionsListUtils', () => { notificationPreference: 'hidden', brickRoadIndicator: CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, }; - const results = getValidOptions({ - options: {reports: [workspaceChat], personalDetails: []}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: [workspaceChat], personalDetails: []}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeMultipleParticipantReports: true, - showRBR: true, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeMultipleParticipantReports: true, + showRBR: true, + }, + ); expect(results.recentReports.at(0)?.brickRoadIndicator).toBe(CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR); }); @@ -1144,18 +1161,20 @@ describe('OptionsListUtils', () => { notificationPreference: 'hidden', brickRoadIndicator: CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, }; - const results = getValidOptions({ - options: {reports: [workspaceChat], personalDetails: []}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: [workspaceChat], personalDetails: []}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeMultipleParticipantReports: true, - showRBR: false, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeMultipleParticipantReports: true, + showRBR: false, + }, + ); expect(results.recentReports.at(0)?.brickRoadIndicator).toBe(null); }); @@ -1199,19 +1218,21 @@ describe('OptionsListUtils', () => { isBold: false, }; - const results = getValidOptions({ - options: {reports: [inputOption], personalDetails: []}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: [inputOption], personalDetails: []}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - includeRecentReports: true, - shouldUnreadBeBold: true, - includeMultipleParticipantReports: true, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + includeRecentReports: true, + shouldUnreadBeBold: true, + includeMultipleParticipantReports: true, + }, + ); expect(results.recentReports.at(0)?.isBold).toBe(true); expect(results.recentReports.at(0)?.isUnread).toBe(true); @@ -1233,17 +1254,19 @@ describe('OptionsListUtils', () => { }; // When we call getValidOptions with personalDetails parameter - const results = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: {}, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + {}, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - personalDetails: customPersonalDetails, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + personalDetails: customPersonalDetails, + }, + ); // Then the function should complete without errors and return valid results // The personalDetails param is used internally by prepareReportOptionsForDisplay for workspace chats @@ -1256,15 +1279,7 @@ describe('OptionsListUtils', () => { it('should include all reports by default', () => { // Given a set of reports and personalDetails that includes workspace rooms // When we call getValidOptions() - const results = getValidOptions({ - options: OPTIONS_WITH_WORKSPACE_ROOM, - policies: allPolicies, - draftComments: {}, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1281,16 +1296,16 @@ describe('OptionsListUtils', () => { it('should exclude users with recent reports from personalDetails', () => { // Given a set of reports and personalDetails // When we call getValidOptions with no search value - const results = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); const reportLogins = new Set(results.recentReports.map((reportOption) => reportOption.login)); const personalDetailsOverlapWithReports = results.personalDetails.every((personalDetailOption) => reportLogins.has(personalDetailOption.login)); @@ -1303,17 +1318,19 @@ describe('OptionsListUtils', () => { it('should exclude selected options', () => { // Given a set of reports and personalDetails // When we call getValidOptions with excludeLogins param - const results = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {'peterparker@expensify.com': true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {'peterparker@expensify.com': true}, + }, + ); // Then the option should not appear anywhere in either list expect(results.recentReports.every((option) => option.login !== 'peterparker@expensify.com')).toBe(true); @@ -1323,16 +1340,16 @@ describe('OptionsListUtils', () => { it('should include Concierge in the results by default', () => { // Given a set of report and personalDetails that include Concierge // When we call getValidOptions() - const results = getValidOptions({ - options: {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // Then the result should include all personalDetails except the currently logged in user expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 1); @@ -1343,20 +1360,22 @@ describe('OptionsListUtils', () => { it('should exclude Concierge from the results when it is specified in excludedLogins', () => { // Given a set of reports and personalDetails that includes Concierge // When we call getValidOptions with excludeLogins param - const results = getValidOptions({ - options: { + const results = getValidOptions( + { reports: OPTIONS_WITH_CONCIERGE.reports, personalDetails: OPTIONS_WITH_CONCIERGE.personalDetails, }, - policies: undefined, - draftComments: {}, + undefined, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, + }, + ); // Then the result should include all personalDetails except the currently logged in user and Concierge expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CONCIERGE.personalDetails).length - 2); @@ -1368,17 +1387,19 @@ describe('OptionsListUtils', () => { it('should exclude Chronos from the results when it is specified in excludedLogins', () => { // given a set of reports and personalDetails that includes Chronos // When we call getValidOptions() with excludeLogins param - const results = getValidOptions({ - options: {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS_WITH_CHRONOS.reports, personalDetails: OPTIONS_WITH_CHRONOS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, + }, + ); // Then the result should include all personalDetails except the currently logged in user and Chronos expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_CHRONOS.personalDetails).length - 2); @@ -1390,20 +1411,22 @@ describe('OptionsListUtils', () => { it('should exclude Receipts from the results when it is specified in excludedLogins', () => { // Given a set of reports and personalDetails that includes receipts // When we call getValidOptions() with excludeLogins param - const results = getValidOptions({ - options: { + const results = getValidOptions( + { reports: OPTIONS_WITH_RECEIPTS.reports, personalDetails: OPTIONS_WITH_RECEIPTS.personalDetails, }, - policies: undefined, - draftComments: {}, + undefined, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, + }, + ); // Then the result should include all personalDetails except the currently logged in user and receipts expect(results.personalDetails.length).toBe(Object.values(OPTIONS_WITH_RECEIPTS.personalDetails).length - 2); @@ -1416,17 +1439,19 @@ describe('OptionsListUtils', () => { // Given a set of reports and personalDetails with multiple reports // When we call getValidOptions with maxRecentReportElements set to 2 const maxRecentReports = 2; - const results = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - maxRecentReportElements: maxRecentReports, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + maxRecentReportElements: maxRecentReports, + }, + ); // Then the recent reports should be limited to the specified number expect(results.recentReports.length).toBeLessThanOrEqual(maxRecentReports); @@ -1435,27 +1460,29 @@ describe('OptionsListUtils', () => { it('should show all reports when maxRecentReportElements is not specified', () => { // Given a set of reports and personalDetails // When we call getValidOptions without maxRecentReportElements - const resultsWithoutLimit = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const resultsWithoutLimit = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); - const resultsWithLimit = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); + const resultsWithLimit = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - maxRecentReportElements: 2, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + maxRecentReportElements: 2, + }, + ); // Then the results without limit should have more or equal reports expect(resultsWithoutLimit.recentReports.length).toBeGreaterThanOrEqual(resultsWithLimit.recentReports.length); @@ -1464,27 +1491,29 @@ describe('OptionsListUtils', () => { it('should not affect personalDetails count when maxRecentReportElements is specified', () => { // Given a set of reports and personalDetails // When we call getValidOptions with and without maxRecentReportElements - const resultsWithoutLimit = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const resultsWithoutLimit = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); - const resultsWithLimit = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); + const resultsWithLimit = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - maxRecentReportElements: 2, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + maxRecentReportElements: 2, + }, + ); // Then personalDetails should remain the same regardless of maxRecentReportElements expect(resultsWithLimit.personalDetails.length).toBe(resultsWithoutLimit.personalDetails.length); @@ -1495,18 +1524,20 @@ describe('OptionsListUtils', () => { // When we call getValidOptions with both maxElements and maxRecentReportElements const maxRecentReports = 3; const maxTotalElements = 10; - const results = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - maxElements: maxTotalElements, - maxRecentReportElements: maxRecentReports, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + maxElements: maxTotalElements, + maxRecentReportElements: maxRecentReports, + }, + ); // Then recent reports should be limited by maxRecentReportElements expect(results.recentReports.length).toBeLessThanOrEqual(maxRecentReports); @@ -1528,28 +1559,30 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with an empty search value - const results = getValidOptions({ - options: {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }, + ); // Then all the recent reports should be returned except the archived rooms and the hidden thread expect(results.recentReports.length).toBe(Object.values(OPTIONS.reports).length - 2); @@ -1568,28 +1601,30 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with an empty search value - const results = getValidOptions({ - options: {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const results = getValidOptions( + {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }, + ); // Then all recent reports should be returned except the archived rooms and the hidden thread expect(results.recentReports.length).toBe(Object.values(OPTIONS_WITH_WORKSPACE_ROOM.reports).length - 2); @@ -1600,15 +1635,7 @@ describe('OptionsListUtils', () => { it('should sort personal details alphabetically and return expected structure', () => { // Given a set of personalDetails // When we call getMemberInviteOptions - const results = getMemberInviteOptions({ - personalDetails: OPTIONS.personalDetails, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - }); + const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); // Then personal details should be sorted alphabetically expect(results.personalDetails.at(0)?.text).toBe('Black Panther'); @@ -1624,19 +1651,10 @@ describe('OptionsListUtils', () => { it('should exclude logins when excludeLogins is provided', () => { // Given a set of personalDetails and excludeLogins - const excludeLoginsMap = {'reedrichards@expensify.com': true}; + const excludeLogins = {'reedrichards@expensify.com': true}; // When we call getMemberInviteOptions with excludeLogins - const results = getMemberInviteOptions({ - personalDetails: OPTIONS.personalDetails, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - excludeLogins: excludeLoginsMap, - }); + const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, [], excludeLogins); // Then the excluded login should not be in the results const excludedUser = results.personalDetails.find((detail) => detail.login === 'reedrichards@expensify.com'); @@ -2057,17 +2075,19 @@ describe('OptionsListUtils', () => { it('should not return any results if the search value is on an excluded logins list', () => { const searchText = 'admin@expensify.com'; // Given a set of options with excluded logins list - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, + }, + ); // When we call filterAndOrderOptions with a search value and excluded logins list const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, @@ -2152,15 +2172,7 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions({ - personalDetails: OPTIONS.personalDetails, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - }); + const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); // When we call filterAndOrderOptions with a search value that does not match any personal details const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2170,15 +2182,7 @@ describe('OptionsListUtils', () => { it('should return one personal detail if search value matches an email (getMemberInviteOptions)', () => { // Given a set of options - const options = getMemberInviteOptions({ - personalDetails: OPTIONS.personalDetails, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - }); + const options = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, []); // When we call filterAndOrderOptions with a search value that matches an email const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2198,28 +2202,30 @@ describe('OptionsListUtils', () => { return filtered; }, []); // When we call getValidOptions for share destination with the filteredReports - const options = getValidOptions({ - options: {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: filteredReports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }, + ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2239,28 +2245,30 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with the filteredReports - const options = getValidOptions({ - options: {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, - includeTasks: true, - excludeLogins: {}, - includeOwnedWorkspaceChats: true, - includeSelfDM: true, - searchString: '', - includeUserToInvite: false, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, + includeTasks: true, + excludeLogins: {}, + includeOwnedWorkspaceChats: true, + includeSelfDM: true, + searchString: '', + includeUserToInvite: false, + }, + ); // When we pass the returned options to filterAndOrderOptions with a search value that matches the group chat name const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2280,21 +2288,22 @@ describe('OptionsListUtils', () => { }, []); // When we call getValidOptions for share destination with the filteredReports - const options = getValidOptions({ - options: {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: filteredReportsWithWorkspaceRooms, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - includeMultipleParticipantReports: true, - showChatPreviewLine: true, - forcePolicyNamePreview: true, - includeThreads: true, - includeMoneyRequests: true, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + betas: [], + includeMultipleParticipantReports: true, + showChatPreviewLine: true, + forcePolicyNamePreview: true, + includeThreads: true, + includeMoneyRequests: true, includeTasks: true, excludeLogins: {}, includeOwnedWorkspaceChats: true, @@ -2312,16 +2321,16 @@ describe('OptionsListUtils', () => { it('should show the option from personal details when searching for personal detail with no existing report', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that matches a personal detail with no existing report const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2335,16 +2344,16 @@ describe('OptionsListUtils', () => { it('should not return any options or user to invite if there are no search results and the string does not match a potential email or phone', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2357,16 +2366,16 @@ describe('OptionsListUtils', () => { it('should not return any options but should return an user to invite if no matching options exist and the search value is a potential email', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2379,16 +2388,16 @@ describe('OptionsListUtils', () => { it('should return user to invite when search term has a period with options for it that do not contain the period', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2400,16 +2409,16 @@ describe('OptionsListUtils', () => { it('should return user which has displayName with accent mark when search value without accent mark', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value without accent mark const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2419,16 +2428,16 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2443,16 +2452,16 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number with country code added', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2467,16 +2476,16 @@ describe('OptionsListUtils', () => { it('should not return options but should return an user to invite if no matching options exist and the search value is a potential phone number with special characters added', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2491,16 +2500,16 @@ describe('OptionsListUtils', () => { it('should not return any options or user to invite if contact number contains alphabet characters', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2513,16 +2522,16 @@ describe('OptionsListUtils', () => { it('should not return any options if search value does not match any personal details', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that does not match any personal details const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); @@ -2532,16 +2541,16 @@ describe('OptionsListUtils', () => { it('should return one recent report and no personal details if a search value provides an email', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that matches an email const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { sortByReportTypeInSearch: true, @@ -2557,16 +2566,16 @@ describe('OptionsListUtils', () => { it('should return all matching reports and personal details', () => { // Given a set of options - const options = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, - policies: allPolicies, - draftComments: {}, + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); // When we call filterAndOrderOptions with a search value that matches both reports and personal details and maxRecentReportsToShow param const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, { maxRecentReportsToShow: 5, @@ -4101,16 +4110,16 @@ describe('OptionsListUtils', () => { const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`]: policy}; // Test that getValidOptions accepts policies collection as second parameter - const results = getValidOptions({ - options: {reports: [], personalDetails: []}, + const results = getValidOptions( + {reports: [], personalDetails: []}, policies, - draftComments: undefined, + undefined, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4118,16 +4127,8 @@ describe('OptionsListUtils', () => { }); it('should work with undefined policies', () => { - const results = getValidOptions({ - options: {reports: [], personalDetails: []}, - policies: undefined, - draftComments: undefined, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + const options = {reports: [], personalDetails: []}; + const results = getValidOptions(options, undefined, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4135,16 +4136,8 @@ describe('OptionsListUtils', () => { }); it('should work with empty policies collection', () => { - const results = getValidOptions({ - options: {reports: [], personalDetails: []}, - policies: {}, - draftComments: undefined, - nvpDismissedProductTraining, - loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - }); + const options = {reports: [], personalDetails: []}; + const results = getValidOptions(options, {}, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4168,18 +4161,20 @@ describe('OptionsListUtils', () => { const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${testPolicyID}`]: policy}; // Verify function works with policies parameter - const results = getValidOptions({ - options: {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, policies, - draftComments: undefined, + undefined, nvpDismissedProductTraining, loginList, - currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, - betas: [], - includeRecentReports: true, - }); + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + { + betas: [], + includeRecentReports: true, + }, + ); expect(results.recentReports).toBeDefined(); expect(Array.isArray(results.recentReports)).toBe(true); From adf96a4480e4a69df87ffa219a2c7f0c4c21cb6e Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 17:34:35 +0100 Subject: [PATCH 15/40] fixing eslint --- src/libs/OptionsListUtils/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 40619976382c..4f5783f8a689 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -2251,6 +2251,7 @@ function getRestrictedLogins( /** * Options are reports and personal details. This function filters out the options that are not valid to be displayed. */ +// eslint-disable-next-line @typescript-eslint/max-params function getValidOptions( options: OptionList, policiesCollection: OnyxCollection, @@ -2684,6 +2685,7 @@ function formatMemberForList(member: SearchOptionData): MemberForList { * Build the options for the Workspace Member Invite view * This method will be removed. See https://github.com/Expensify/App/issues/66615 for more information. */ +// eslint-disable-next-line @typescript-eslint/max-params function getMemberInviteOptions( personalDetails: Array>, nvpDismissedProductTraining: OnyxEntry, From e2e787b835267b0ce282d425c1c7f30b4e7d3aac Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 18:12:33 +0100 Subject: [PATCH 16/40] fixing dependecies --- src/components/Search/SearchFiltersParticipantsSelector.tsx | 2 +- src/pages/RoomInvitePage.tsx | 4 ++-- src/pages/iou/request/MoneyRequestAttendeeSelector.tsx | 1 + src/pages/iou/request/MoneyRequestParticipantsSelector.tsx | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index 1d8b703232b3..2614d4953257 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -188,7 +188,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}: sections: newSections, headerMessage: message, }; - }, [areOptionsInitialized, cleanSearchTerm, selectedOptions, chatOptions, personalDetails, reportAttributesDerived, translate, formatPhoneNumber, currentUserAccountID]); + }, [areOptionsInitialized, cleanSearchTerm, selectedOptions, chatOptions, personalDetails, reportAttributesDerived, translate, formatPhoneNumber, currentUserAccountID, reports]); const resetChanges = useCallback(() => { setSelectedOptions([]); diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index a6079757537e..7474c5b637e6 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -127,7 +127,7 @@ function RoomInvitePage({ recentReports: [], currentUserOption: null, }; - }, [areOptionsInitialized, betas, excludedUsers, loginList, nvpDismissedProductTraining, options.personalDetails, selectedOptions, currentUserAccountID, currentUserEmail]); + }, [areOptionsInitialized, betas, excludedUsers, loginList, nvpDismissedProductTraining, options.personalDetails, selectedOptions, currentUserAccountID, currentUserEmail, reports]); const inviteOptions = useMemo(() => { if (debouncedSearchTerm.trim() === '') { @@ -138,7 +138,7 @@ function RoomInvitePage({ }); return filteredOptions; - }, [debouncedSearchTerm, defaultOptions, countryCode, loginList, excludedUsers, currentUserAccountID, currentUserEmail]); + }, [debouncedSearchTerm, defaultOptions, countryCode, loginList, excludedUsers, currentUserAccountID, currentUserEmail, reports]); const sections = useMemo(() => { const sectionsArr: Sections = []; diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index 628d3262eedc..2bd37cf0b017 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -291,6 +291,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde translate, currentUserAccountID, currentUserEmail, + reports, ]); const optionLength = useMemo(() => { diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 4bf88e727ab8..a35fe0b8c369 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -380,6 +380,7 @@ function MoneyRequestParticipantsSelector({ inputHelperText, currentUserAccountID, currentUserEmail, + reports, ]); /** From 1d50552b38c2786d286849228c9b82a862dcd4ba Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 18:31:57 +0100 Subject: [PATCH 17/40] fixing sentry eslint --- src/pages/Share/ShareDetailsPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index 0fbf0700b851..6f7ef75b6585 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -180,6 +180,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { KeyboardUtils.dismiss(); }} accessible={false} + sentryLabel="ShareDetailsPage-DismissKeyboard" > {shouldShowAttachment && ( <> From 5f5ea131e3d517bd5ccb1125e1a68b6eb07b4250 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 18:39:43 +0100 Subject: [PATCH 18/40] fixing sentry eslint --- src/pages/NewChatPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 74edb0178819..f1d6b438cd42 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -183,6 +183,7 @@ function useOptions() { return; } + // eslint-disable-next-line react-hooks/set-state-in-effect setSelectedOptions((prevSelectedOptions) => { if ( prevSelectedOptions.length === draftSelectedOptions.length && @@ -413,6 +414,7 @@ function NewChatPage({ref}: NewChatPageProps) { accessibilityLabel={item.text ?? ''} accessibilityState={{checked: item.isSelected}} style={[styles.flexRow, styles.alignItemsCenter, styles.ml5, styles.optionSelectCircle]} + sentryLabel="NewChatPage-ToggleOption" > Date: Mon, 2 Feb 2026 19:05:22 +0100 Subject: [PATCH 19/40] adding test cases --- tests/unit/OptionsListUtilsTest.tsx | 270 ++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index e4bbc3ec976a..ed3ac162d286 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -5162,4 +5162,274 @@ describe('OptionsListUtils', () => { expect(typeof result).toBe('string'); }); }); + + describe('reports parameter functionality', () => { + it('getValidOptions should use reports parameter to look up chat reports', () => { + // Given a reports collection + const reportsCollection = { + ...REPORTS, + }; + + // When we call getValidOptions with the reports collection + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, + nvpDismissedProductTraining, + loginList, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + reportsCollection, + ); + + // Then the function should complete without errors and return valid results + expect(results).toBeDefined(); + expect(results.recentReports).toBeDefined(); + expect(results.personalDetails).toBeDefined(); + }); + + it('filterAndOrderOptions should use reports parameter correctly', () => { + // Given a set of options and reports collection + const options = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, + nvpDismissedProductTraining, + loginList, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + REPORTS, + ); + + // When we call filterAndOrderOptions with the reports parameter + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS); + + // Then the function should complete without errors and return valid results + expect(filteredOptions).toBeDefined(); + expect(filteredOptions.recentReports).toBeDefined(); + expect(filteredOptions.personalDetails).toBeDefined(); + }); + + it('getSearchOptions should use reports parameter from config', () => { + // Given a reports collection + const reportsCollection = { + ...REPORTS, + }; + + // When we call getSearchOptions with reports in the config + const options = getSearchOptions({ + options: OPTIONS, + draftComments: {}, + nvpDismissedProductTraining, + loginList, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: reportsCollection, + }); + + // Then the function should complete without errors and return valid results + expect(options).toBeDefined(); + expect(options.recentReports).toBeDefined(); + expect(options.personalDetails).toBeDefined(); + }); + + it('getMemberInviteOptions should use reports parameter correctly', () => { + // Given personal details and a reports collection + const reportsCollection = { + ...REPORTS, + }; + + // When we call getMemberInviteOptions with the reports parameter + const results = getMemberInviteOptions( + OPTIONS.personalDetails, + nvpDismissedProductTraining, + loginList, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + reportsCollection, + [], + ); + + // Then the function should complete without errors and return valid results + expect(results).toBeDefined(); + expect(results.personalDetails).toBeDefined(); + expect(results.recentReports).toEqual([]); + }); + + it('getUserToInviteOption should use reports parameter correctly', () => { + // Given a valid email search value and reports collection + const result = getUserToInviteOption({ + searchValue: 'newuser@example.com', + loginList: {}, + currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, + }); + + // Then the function should return a user to invite + expect(result).not.toBeNull(); + expect(result?.login).toBe('newuser@example.com'); + }); + + it('should work correctly when reports is an empty object', () => { + // Given an empty reports collection + const emptyReports = {}; + + // When we call getValidOptions with empty reports + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, + nvpDismissedProductTraining, + loginList, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + emptyReports, + ); + + // Then the function should still work correctly + expect(results).toBeDefined(); + expect(results.recentReports).toBeDefined(); + expect(results.personalDetails).toBeDefined(); + }); + + it('should work correctly when reports is undefined', () => { + // When we call getValidOptions with undefined reports + const results = getValidOptions( + {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, + allPolicies, + {}, + nvpDismissedProductTraining, + loginList, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + undefined, + ); + + // Then the function should still work correctly + expect(results).toBeDefined(); + expect(results.recentReports).toBeDefined(); + expect(results.personalDetails).toBeDefined(); + }); + + it('createOption should look up chatReport from reports collection when report has chatReportID', async () => { + // This test verifies the core functionality: using reports to look up linked chat reports + const reportID = 'expense-report-123'; + const chatReportID = 'linked-chat-456'; + + const expenseReport: Report = { + ...createRandomReport(0, undefined), + reportID, + chatReportID, + type: CONST.REPORT.TYPE.EXPENSE, + participants: { + 1: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, + }; + + const linkedChatReport: Report = { + ...createRandomReport(1, undefined), + reportID: chatReportID, + type: CONST.REPORT.TYPE.CHAT, + reportName: 'Linked Chat Report', + }; + + const reportsWithLinkedChat = { + [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: expenseReport, + [`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]: linkedChatReport, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, expenseReport); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, linkedChatReport); + await waitForBatchedUpdates(); + + // When we call createOption with a reports collection that includes the linked chat + const result = createOption([1, 2], PERSONAL_DETAILS, expenseReport, CURRENT_USER_ACCOUNT_ID, reportsWithLinkedChat); + + // Then the option should be created successfully + expect(result).toBeDefined(); + expect(result.reportID).toBe(reportID); + }); + + it('getReportDisplayOption should use reports parameter to look up chat report', async () => { + const reportID = 'test-report-789'; + const chatReportID = 'test-chat-101'; + + const report: Report = { + ...createRandomReport(0, undefined), + reportID, + chatReportID, + participants: { + 2: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, + }; + + const chatReport: Report = { + ...createRandomReport(1, undefined), + reportID: chatReportID, + }; + + const reportsCollection = { + [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: report, + [`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]: chatReport, + }; + + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); + await waitForBatchedUpdates(); + + // When we call getReportDisplayOption with reports collection + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined, reportsCollection); + + // Then the option should be created successfully using the reports collection + expect(option).toBeDefined(); + expect(option.reportID).toBe(reportID); + }); + + it('getPolicyExpenseReportOption should use reports parameter correctly', async () => { + const reportID = 'policy-expense-123'; + const testPolicyID = 'test-policy-456'; + + const report: Report = { + reportID, + reportName: 'Test Policy Expense Chat', + type: CONST.REPORT.TYPE.CHAT, + chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, + policyID: testPolicyID, + ownerAccountID: CURRENT_USER_ACCOUNT_ID, + }; + + const policy: Policy = { + id: testPolicyID, + name: 'Test Reports Param Workspace', + type: CONST.POLICY.TYPE.TEAM, + owner: 'owner@test.com', + role: 'admin', + outputCurrency: 'USD', + isPolicyExpenseChatEnabled: true, + }; + + const reportsCollection = { + [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: report, + }; + + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); + await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${testPolicyID}`, policy); + await waitForBatchedUpdates(); + + const participant = { + reportID, + policyID: testPolicyID, + isPolicyExpenseChat: true, + }; + + // When we call getPolicyExpenseReportOption with reports collection + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportsCollection); + + // Then the option should be created successfully + expect(option).toBeDefined(); + expect(option.text).toBe('Test Reports Param Workspace'); + }); + }); }); From 401e7f9c206f5c6f220874b33350ba84480ffb3b Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Mon, 2 Feb 2026 19:09:27 +0100 Subject: [PATCH 20/40] fixing prettier --- tests/unit/OptionsListUtilsTest.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index ed3ac162d286..7ac476d25353 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -5240,15 +5240,7 @@ describe('OptionsListUtils', () => { }; // When we call getMemberInviteOptions with the reports parameter - const results = getMemberInviteOptions( - OPTIONS.personalDetails, - nvpDismissedProductTraining, - loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - reportsCollection, - [], - ); + const results = getMemberInviteOptions(OPTIONS.personalDetails, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, reportsCollection, []); // Then the function should complete without errors and return valid results expect(results).toBeDefined(); From fc7cd0a22f767dd21ca6d12e22c4ddad6cd73ede Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 10 Feb 2026 17:38:02 +0100 Subject: [PATCH 21/40] fix prettier --- src/components/OptionListContextProvider.tsx | 4 +- .../Search/SearchFiltersChatsSelector.tsx | 9 ++- .../SearchFiltersParticipantsSelector.tsx | 14 +++- src/libs/OptionsListUtils/index.ts | 1 - src/pages/Share/ShareTab.tsx | 15 +++- tests/unit/OptionsListUtilsTest.tsx | 77 +++++++++++++++---- 6 files changed, 100 insertions(+), 20 deletions(-) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 6be497c3cd8c..1496cda2ce94 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -227,7 +227,9 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { } const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`]; - const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, privateIsArchived, reportAttributes?.reports, {showPersonalDetails: true}); + const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, privateIsArchived, reportAttributes?.reports, { + showPersonalDetails: true, + }); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); newReportOptions.push({ newReportOption, diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index d86e9f3461b5..b572aeab0b74 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -67,7 +67,14 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const selectedOptions: OptionData[] = selectedReportIDs.map((id) => { const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${id}`]; const report = getSelectedOptionData( - createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails, currentUserAccountID, reports, privateIsArchived, reportAttributesDerived), + createOptionFromReport( + {...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, + personalDetails, + currentUserAccountID, + reports, + privateIsArchived, + reportAttributesDerived, + ), ); const isReportArchived = !!privateIsArchived; const alternateText = getAlternateText(report, {}, isReportArchived, currentUserAccountID, {}, reportAttributesDerived); diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index d0b8d60170f8..f3988ce31a01 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -193,7 +193,19 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, } return filteredOptions; - }, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, shouldAllowNameOnlyOptions, searchTerm, currentUserEmail, currentUserAccountID, reports, personalDetails]); + }, [ + unselectedOptions, + cleanSearchTerm, + countryCode, + loginList, + selectedOptions, + shouldAllowNameOnlyOptions, + searchTerm, + currentUserEmail, + currentUserAccountID, + reports, + personalDetails, + ]); const {sections, headerMessage} = useMemo(() => { const newSections: SelectionListSections = []; diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 010b86c895f5..7555e1b828f6 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -965,7 +965,6 @@ function createOption( const computedReportName = getReportName(report, reportAttributesDerived); - reportName = showPersonalDetails ? getDisplayNameForParticipant({accountID: accountIDs.at(0), formatPhoneNumber: formatPhoneNumberPhoneUtils}) || formatPhoneNumberPhoneUtils(personalDetail?.login ?? '') : computedReportName; diff --git a/src/pages/Share/ShareTab.tsx b/src/pages/Share/ShareTab.tsx index 2f97041b4661..2535cf8e0e3e 100644 --- a/src/pages/Share/ShareTab.tsx +++ b/src/pages/Share/ShareTab.tsx @@ -89,7 +89,20 @@ function ShareTab({ref}: ShareTabProps) { reports, personalDetails, }); - }, [areOptionsInitialized, options, draftComments, nvpDismissedProductTraining, betas, textInputValue, countryCode, loginList, currentUserAccountID, currentUserEmail, reports, personalDetails]); + }, [ + areOptionsInitialized, + options, + draftComments, + nvpDismissedProductTraining, + betas, + textInputValue, + countryCode, + loginList, + currentUserAccountID, + currentUserEmail, + reports, + personalDetails, + ]); const recentReportsOptions = useMemo(() => { if (textInputValue.trim() === '') { diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index b7cb82ae29bb..5465be155f84 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -2655,7 +2655,16 @@ describe('OptionsListUtils', () => { COUNTRY_CODE, ); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions( + options, + 'peterparker@expensify.com', + COUNTRY_CODE, + loginList, + CURRENT_USER_EMAIL, + CURRENT_USER_ACCOUNT_ID, + REPORTS, + PERSONAL_DETAILS, + ); // Then one personal detail should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -3014,7 +3023,16 @@ describe('OptionsListUtils', () => { }); // When we pass the returned options to filterAndOrderOptions with any search value - const filteredOptions = filterAndOrderOptions(options, 'Unknown', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS_WITH_GROUP_CHAT_NO_PARTICIPANTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions( + options, + 'Unknown', + COUNTRY_CODE, + loginList, + CURRENT_USER_EMAIL, + CURRENT_USER_ACCOUNT_ID, + REPORTS_WITH_GROUP_CHAT_NO_PARTICIPANTS, + PERSONAL_DETAILS, + ); // Then the report should still be found by its reportName even if participantsList is empty expect(filteredOptions.recentReports.length).toBe(1); @@ -3078,7 +3096,16 @@ describe('OptionsListUtils', () => { REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions( + options, + 'peter.parker@expensify.com', + COUNTRY_CODE, + loginList, + CURRENT_USER_EMAIL, + CURRENT_USER_ACCOUNT_ID, + REPORTS, + PERSONAL_DETAILS, + ); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3281,9 +3308,19 @@ describe('OptionsListUtils', () => { REPORTS, ); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { - sortByReportTypeInSearch: true, - }); + const filteredOptions = filterAndOrderOptions( + options, + 'peterparker@expensify.com', + COUNTRY_CODE, + loginList, + CURRENT_USER_EMAIL, + CURRENT_USER_ACCOUNT_ID, + REPORTS, + PERSONAL_DETAILS, + { + sortByReportTypeInSearch: true, + }, + ); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3378,14 +3415,24 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, - currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, + currentUserEmail: CURRENT_USER_EMAIL, + reports: REPORTS, personalDetails: PERSONAL_DETAILS_WITH_PERIODS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredResults = filterAndOrderOptions(results, 'barry.allen@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS_WITH_PERIODS, { - sortByReportTypeInSearch: true, - }); + const filteredResults = filterAndOrderOptions( + results, + 'barry.allen@expensify.com', + COUNTRY_CODE, + loginList, + CURRENT_USER_EMAIL, + CURRENT_USER_ACCOUNT_ID, + REPORTS, + PERSONAL_DETAILS_WITH_PERIODS, + { + sortByReportTypeInSearch: true, + }, + ); // Then only one report should be returned expect(filteredResults.recentReports.length).toBe(1); @@ -4212,7 +4259,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, - chatReport: undefined, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallySubmitted'))); }); @@ -4237,7 +4284,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, - chatReport: undefined, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallyApproved'))); }); @@ -4262,7 +4309,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, - chatReport: undefined, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallyForwarded'))); }); @@ -4284,7 +4331,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, - chatReport: undefined, + chatReport: undefined, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'workspaceActions.forcedCorporateUpgrade'))); }); From e3d1ecd7eeb6ec59222c253fb76276095ca1120e Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 10 Feb 2026 17:43:15 +0100 Subject: [PATCH 22/40] fixing missing dependencies --- src/components/OptionListContextProvider.tsx | 4 ++-- src/components/Search/SearchAutocompleteList.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 1496cda2ce94..af5b20905603 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -137,7 +137,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { reports: Array.from(updatedReportsMap.values()), }; }); - }, [changedReportsEntries, personalDetails, currentUserAccountID, reportAttributes?.reports]); + }, [changedReportsEntries, personalDetails, currentUserAccountID, reports, reportAttributes?.reports]); useEffect(() => { if (!changedReportActions || !areOptionsInitialized.current) { @@ -169,7 +169,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { reports: Array.from(updatedReportsMap.values()), }; }); - }, [changedReportActions, personalDetails, currentUserAccountID, reportAttributes?.reports]); + }, [changedReportActions, personalDetails, currentUserAccountID, reports, reportAttributes?.reports]); /** * This effect is used to update the options list when personal details change. diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 0b9b8a0dbc40..2c8ccac0e18c 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -680,6 +680,7 @@ function SearchAutocompleteList({ hasAutocompleteList, isAutocompleteList, personalDetails, + reports, ]); const sortedRecentSearches = useMemo(() => { From 382f5c52282254c9df120d92488dba50d78b189c Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 10 Feb 2026 17:49:15 +0100 Subject: [PATCH 23/40] fix tests --- tests/unit/OptionListContextProviderTest.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/OptionListContextProviderTest.tsx b/tests/unit/OptionListContextProviderTest.tsx index 791238afb865..0de8e00ce3de 100644 --- a/tests/unit/OptionListContextProviderTest.tsx +++ b/tests/unit/OptionListContextProviderTest.tsx @@ -169,6 +169,6 @@ describe('OptionListContextProvider', () => { mockUsePersonalDetails.mockReturnValue(updatedPersonalDetails); rerender({shouldInitialize: false}); - expect(mockCreateOptionFromReport).toHaveBeenCalledWith(report, updatedPersonalDetails, expect.any(Number), 'true', undefined, {showPersonalDetails: true}); + expect(mockCreateOptionFromReport).toHaveBeenCalledWith(report, updatedPersonalDetails, expect.any(Number), {[reportKey]: report}, 'true', undefined, {showPersonalDetails: true}); }); }); From e2c063a8d09dfd27a3a9490e72299138f100bf8c Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 00:02:52 +0100 Subject: [PATCH 24/40] removing reports and using chatreport instead --- Mobile-Expensify | 2 +- src/components/OptionListContextProvider.tsx | 10 +- .../FilterDropdowns/UserSelectPopup.tsx | 7 +- .../Search/SearchAutocompleteList.tsx | 5 - .../Search/SearchFiltersChatsSelector.tsx | 10 +- .../SearchFiltersParticipantsSelector.tsx | 9 +- .../Search/SearchRouter/SearchRouter.tsx | 3 +- src/hooks/useSearchSelector.base.ts | 8 - src/libs/OptionsListUtils/index.ts | 58 ++-- src/pages/NewChatPage.tsx | 5 +- src/pages/RoomInvitePage.tsx | 5 +- src/pages/Share/ShareDetailsPage.tsx | 5 +- src/pages/Share/ShareTab.tsx | 3 - src/pages/iou/SplitBillDetailsPage.tsx | 3 +- .../MoneyRequestAccountantSelector.tsx | 11 +- .../request/MoneyRequestAttendeeSelector.tsx | 5 +- .../MoneyRequestParticipantsSelector.tsx | 5 +- tests/perf-test/OptionsListUtils.perf-test.ts | 9 +- tests/unit/OptionListContextProviderTest.tsx | 2 +- tests/unit/OptionsListUtilsTest.tsx | 247 ++++++------------ 20 files changed, 132 insertions(+), 280 deletions(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index e0b5ad692c30..a4663a30d7b9 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit e0b5ad692c30e0303cb83a42962ef98d8d1a635f +Subproject commit a4663a30d7b948ea34c90f381773c60b8c3ebd0a diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index af5b20905603..81f30ba41e03 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -123,7 +123,8 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { for (const reportKey of changedReportKeys) { const report = changedReportsEntries[reportKey]; const reportID = reportKey.replace(ONYXKEYS.COLLECTION.REPORT, ''); - const {reportOption} = processReport(report, personalDetails, currentUserAccountID, reports, reportAttributes?.reports); + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const {reportOption} = processReport(report, personalDetails, currentUserAccountID, chatReport, reportAttributes?.reports); if (reportOption) { updatedReportsMap.set(reportID, reportOption); @@ -157,7 +158,9 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { } const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, ''); - const {reportOption} = processReport(updatedReportsMap.get(reportID)?.item, personalDetails, currentUserAccountID, reports, reportAttributes?.reports); + const reportItem = updatedReportsMap.get(reportID)?.item; + const chatReport = reportItem?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportItem.chatReportID}`] : undefined; + const {reportOption} = processReport(reportItem, personalDetails, currentUserAccountID, chatReport, reportAttributes?.reports); if (reportOption) { updatedReportsMap.set(reportID, reportOption); @@ -227,7 +230,8 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { } const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`]; - const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, privateIsArchived, reportAttributes?.reports, { + const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, chatReport, privateIsArchived, reportAttributes?.reports, { showPersonalDetails: true, }); const replaceIndex = options.reports.findIndex((option) => option.reportID === report.reportID); diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index d1de0eddeb8b..a6970b67e1e1 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -65,7 +65,6 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele const shouldFocusInputOnScreenFocus = canFocusInputOnScreenFocus(); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [searchTerm, setSearchTerm] = useState(''); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); @@ -110,7 +109,6 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele loginList, currentUserAccountID, currentUserEmail, - reports, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, @@ -129,16 +127,15 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele personalDetails, currentUserAccountID, currentUserEmail, - reports, ]); const filteredOptions = useMemo(() => { - return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, personalDetails, { + return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, canInviteUser: false, }); - }, [optionsList, cleanSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, reports, personalDetails]); + }, [optionsList, cleanSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]); const listData = useMemo(() => { const personalDetailList = filteredOptions.personalDetails.map((participant) => ({ diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index 2c8ccac0e18c..9cb4dcac8fb8 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -222,7 +222,6 @@ function SearchAutocompleteList({ loginList, currentUserAccountID, currentUserEmail, - reports, personalDetails, }); }, [ @@ -236,7 +235,6 @@ function SearchAutocompleteList({ loginList, currentUserAccountID, currentUserEmail, - reports, personalDetails, ]); @@ -456,7 +454,6 @@ function SearchAutocompleteList({ shouldShowGBR: true, currentUserAccountID, currentUserEmail, - reports, personalDetails, }).personalDetails.filter((participant) => participant.text && !alreadyAutocompletedKeys.has(participant.text.toLowerCase())); @@ -491,7 +488,6 @@ function SearchAutocompleteList({ shouldShowGBR: true, currentUserAccountID, currentUserEmail, - reports, personalDetails, }).recentReports.filter((chat) => { if (!chat.text) { @@ -680,7 +676,6 @@ function SearchAutocompleteList({ hasAutocompleteList, isAutocompleteList, personalDetails, - reports, ]); const sortedRecentSearches = useMemo(() => { diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index b572aeab0b74..29c7b633c521 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -66,12 +66,14 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const selectedOptions: OptionData[] = selectedReportIDs.map((id) => { const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${id}`]; + const reportData = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]; + const chatReport = reportData?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportData.chatReportID}`] : undefined; const report = getSelectedOptionData( createOptionFromReport( - {...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, + {...reportData, reportID: id}, personalDetails, currentUserAccountID, - reports, + chatReport, privateIsArchived, reportAttributesDerived, ), @@ -94,11 +96,10 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen loginList, currentUserAccountID, currentUserEmail, - reports, personalDetails, }); - const chatOptions = filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, personalDetails, { + const chatOptions = filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { selectedOptions, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -116,7 +117,6 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen false, undefined, reportAttributesDerived, - reports, ); sections.push(formattedResults.section); diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index f3988ce31a01..160c34c3b8bb 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -86,7 +86,6 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserAccountID = currentUserPersonalDetails.accountID; const currentUserEmail = currentUserPersonalDetails.email ?? ''; @@ -120,7 +119,6 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, loginList, currentUserAccountID, currentUserEmail, - reports, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, includeCurrentUser: true, @@ -146,7 +144,6 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, personalDetails, currentUserAccountID, currentUserEmail, - reports, ]); const unselectedOptions = useMemo(() => { @@ -176,7 +173,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, }, [defaultOptions, selectedOptions, shouldAllowNameOnlyOptions]); const chatOptions = useMemo(() => { - const filteredOptions = filterAndOrderOptions(unselectedOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, personalDetails, { + const filteredOptions = filterAndOrderOptions(unselectedOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { selectedOptions, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, @@ -203,7 +200,6 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, searchTerm, currentUserEmail, currentUserAccountID, - reports, personalDetails, ]); @@ -223,7 +219,6 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, true, undefined, reportAttributesDerived, - reports, ); const selectedCurrentUser = formattedResults.section.data.find((option) => option.accountID === chatOptions.currentUserOption?.accountID); @@ -279,7 +274,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, sections: newSections, headerMessage: message, }; - }, [areOptionsInitialized, cleanSearchTerm, selectedOptions, chatOptions, personalDetails, reportAttributesDerived, translate, formatPhoneNumber, currentUserAccountID, reports]); + }, [areOptionsInitialized, cleanSearchTerm, selectedOptions, chatOptions, personalDetails, reportAttributesDerived, translate, formatPhoneNumber, currentUserAccountID]); const resetChanges = useCallback(() => { setSelectedOptions([]); diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 27a7cf0bd3ad..5c61ad7a55f4 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -115,7 +115,8 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla } const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${contextualReportID}`]; - const option = createOptionFromReport(report, personalDetails, currentUserAccountID, reports, privateIsArchived, undefined, {showPersonalDetails: true}); + const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const option = createOptionFromReport(report, personalDetails, currentUserAccountID, chatReport, privateIsArchived, undefined, {showPersonalDetails: true}); reportForContextualSearch = option; } diff --git a/src/hooks/useSearchSelector.base.ts b/src/hooks/useSearchSelector.base.ts index 7d3bac3b83fc..80d78e9af64a 100644 --- a/src/hooks/useSearchSelector.base.ts +++ b/src/hooks/useSearchSelector.base.ts @@ -170,7 +170,6 @@ function useSearchSelectorBase({ const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); @@ -211,7 +210,6 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, - reports, personalDetails, }); case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_MEMBER_INVITE: @@ -223,7 +221,6 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, - reports, { betas: betas ?? [], includeP2P: true, @@ -250,7 +247,6 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, - reports, { ...getValidOptionsConfig, betas: betas ?? [], @@ -275,7 +271,6 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, - reports, { betas, includeMultipleParticipantReports: true, @@ -303,7 +298,6 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, - reports, { betas, selectedOptions, @@ -335,7 +329,6 @@ function useSearchSelectorBase({ loginList, currentUserAccountID, currentUserEmail, - reports, { ...getValidOptionsConfig, betas: betas ?? [], @@ -382,7 +375,6 @@ function useSearchSelectorBase({ currentUserAccountID, currentUserEmail, personalDetails, - reports, reportAttributesDerived?.reports, trimmedSearchInput, ]); diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 7555e1b828f6..0cac83be0061 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -869,13 +869,12 @@ function createOption( personalDetails: OnyxInputOrEntry, report: OnyxInputOrEntry, currentUserAccountID: number, - reports: OnyxCollection, + chatReport: OnyxEntry, config?: PreviewConfig, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], privateIsArchived?: string, ): SearchOptionData { const {showChatPreviewLine = false, forcePolicyNamePreview = false, showPersonalDetails = false, selected, isSelected, isDisabled} = config ?? {}; - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; // Initialize only the properties that are actually used in SearchOption context const result: SearchOptionData = { @@ -1016,6 +1015,7 @@ function getReportOption( reportDrafts?: OnyxCollection, ): OptionData { const report = getReportOrDraftReport(participant.reportID, undefined, undefined, reportDrafts); + const chatReport = report?.chatReportID ? getReportOrDraftReport(report.chatReportID) : undefined; const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); const option = createOption( @@ -1023,7 +1023,7 @@ function getReportOption( personalDetails ?? {}, !isEmptyObject(report) ? report : undefined, currentUserAccountID, - reportDrafts, + chatReport, { showChatPreviewLine: false, forcePolicyNamePreview: false, @@ -1072,7 +1072,7 @@ function getReportDisplayOption( currentUserAccountID: number, personalDetails: OnyxEntry, privateIsArchived: string | undefined, - reports: OnyxCollection, + chatReport: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], ): OptionData { const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); @@ -1082,7 +1082,7 @@ function getReportDisplayOption( personalDetails ?? {}, !isEmptyObject(report) ? report : undefined, currentUserAccountID, - reports, + chatReport, { showChatPreviewLine: false, forcePolicyNamePreview: false, @@ -1121,10 +1121,10 @@ function getPolicyExpenseReportOption( participant: Participant | SearchOptionData, currentUserAccountID: number, personalDetails: OnyxEntry, - reports: OnyxCollection, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], ): SearchOptionData { const expenseReport = reportUtilsIsPolicyExpenseChat(participant) ? getReportOrDraftReport(participant.reportID) : null; + const chatReport = expenseReport?.chatReportID ? getReportOrDraftReport(expenseReport.chatReportID) : undefined; const visibleParticipantAccountIDs = Object.entries(expenseReport?.participants ?? {}) .filter(([, reportParticipant]) => reportParticipant && !isHiddenForCurrentUser(reportParticipant.notificationPreference)) @@ -1135,7 +1135,7 @@ function getPolicyExpenseReportOption( personalDetails ?? {}, !isEmptyObject(expenseReport) ? expenseReport : null, currentUserAccountID, - reports, + chatReport, { showChatPreviewLine: false, forcePolicyNamePreview: false, @@ -1250,7 +1250,7 @@ function processReport( report: OnyxEntry | null, personalDetails: OnyxEntry, currentUserAccountID: number, - reports: OnyxCollection, + chatReport: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], ): { reportMapEntry?: [number, Report]; // The entry to add to reportMapForAccountIDs if applicable @@ -1275,7 +1275,7 @@ function processReport( reportMapEntry, reportOption: { item: report, - ...createOption(accountIDs, personalDetails, report, currentUserAccountID, reports, undefined, reportAttributesDerived), + ...createOption(accountIDs, personalDetails, report, currentUserAccountID, chatReport, undefined, reportAttributesDerived), }, }; } @@ -1294,7 +1294,8 @@ function createOptionList( if (reports) { for (const report of Object.values(reports)) { - const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reports, reportAttributesDerived); + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, chatReport, reportAttributesDerived); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1310,6 +1311,7 @@ function createOptionList( const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => { const report = reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID]; const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; return { item: personalDetail, @@ -1318,7 +1320,7 @@ function createOptionList( personalDetails, report, currentUserAccountID, - reports, + chatReport, { showPersonalDetails: true, }, @@ -1414,7 +1416,8 @@ function createFilteredOptionList( // Step 5: Process the limited set of reports (performance optimization) const reportOptions: Array> = []; for (const report of limitedReports) { - const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reports, reportAttributesDerived); + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, chatReport, reportAttributesDerived); if (reportMapEntry) { const [accountID, reportValue] = reportMapEntry; @@ -1444,6 +1447,7 @@ function createFilteredOptionList( const report = reportMapForAccountIDs[accountID]; const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; return { item: personalDetail, ...createOption( @@ -1451,7 +1455,7 @@ function createFilteredOptionList( personalDetails, reportMapForAccountIDs[accountID], currentUserAccountID, - reports, + chatReport, {showPersonalDetails: true}, reportAttributesDerived, privateIsArchived, @@ -1470,7 +1474,7 @@ function createOptionFromReport( report: Report, personalDetails: OnyxEntry, currentUserAccountID: number, - reports: OnyxCollection, + chatReport: OnyxEntry, privateIsArchived: string | undefined, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], config?: PreviewConfig, @@ -1479,7 +1483,7 @@ function createOptionFromReport( return { item: report, - ...createOption(accountIDs, personalDetails, report, currentUserAccountID, reports, config, reportAttributesDerived, privateIsArchived), + ...createOption(accountIDs, personalDetails, report, currentUserAccountID, chatReport, config, reportAttributesDerived, privateIsArchived), }; } @@ -1765,8 +1769,7 @@ function getUserToInviteOption({ loginList = {}, currentUserEmail, currentUserAccountID, - reports, -}: GetUserToInviteConfig & {reports: OnyxCollection}): SearchOptionData | null { +}: GetUserToInviteConfig): SearchOptionData | null { if (!searchValue) { return null; } @@ -1797,7 +1800,7 @@ function getUserToInviteOption({ login: searchValue, }, }; - const userToInvite = createOption([optimisticAccountID], personalDetailsExtended, null, currentUserAccountID, reports, { + const userToInvite = createOption([optimisticAccountID], personalDetailsExtended, null, currentUserAccountID, undefined, { showChatPreviewLine, }); userToInvite.isOptimisticAccount = true; @@ -2227,7 +2230,6 @@ function getValidOptions( loginList: OnyxEntry, currentUserAccountID: number, currentUserEmail: string, - reports: OnyxCollection, { excludeLogins = {}, excludeFromSuggestionsOnly = {}, @@ -2470,7 +2472,6 @@ function getValidOptions( loginList, currentUserEmail, currentUserAccountID, - reports, personalDetails, countryCode, { @@ -2510,7 +2511,6 @@ type SearchOptionsConfig = { currentUserAccountID: number; currentUserEmail: string; personalDetails?: OnyxEntry; - reports: OnyxCollection; reportAttributesDerived?: ReportAttributesDerivedValue['reports']; }; @@ -2535,7 +2535,6 @@ function getSearchOptions({ loginList, currentUserAccountID, currentUserEmail, - reports, reportAttributesDerived, personalDetails, }: SearchOptionsConfig): Options { @@ -2549,7 +2548,6 @@ function getSearchOptions({ loginList, currentUserAccountID, currentUserEmail, - reports, { betas, includeRecentReports, @@ -2689,7 +2687,6 @@ function getMemberInviteOptions( loginList: OnyxEntry, currentUserAccountID: number, currentUserEmail: string, - reports: OnyxCollection, personalDetailsCollection: OnyxEntry, betas: Beta[] = [], excludeLogins: Record = {}, @@ -2704,7 +2701,6 @@ function getMemberInviteOptions( loginList, currentUserAccountID, currentUserEmail, - reports, { betas, includeP2P: true, @@ -2784,7 +2780,6 @@ function formatSectionsFromSearchTerm( shouldGetOptionDetails = false, filteredWorkspaceChats: SearchOptionData[] = [], reportAttributesDerived?: ReportAttributesDerivedValue['reports'], - reports?: OnyxCollection, ): SectionForSearchTerm { // We show the selected participants at the top of the list when there is no search term or maximum number of participants has already been selected // However, if there is a search term we remove the selected participants from the top of the list unless they are part of the search results @@ -2798,7 +2793,7 @@ function formatSectionsFromSearchTerm( ? selectedOptions.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; return isReportPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) : selectedOptions, @@ -2826,7 +2821,7 @@ function formatSectionsFromSearchTerm( ? selectedParticipantsWithoutDetails.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; return isReportPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) : selectedParticipantsWithoutDetails, @@ -2953,7 +2948,6 @@ function filterUserToInvite( loginList: OnyxEntry, currentUserEmail: string, currentUserAccountID: number, - reports: OnyxCollection, personalDetails: OnyxEntry, countryCode: number = CONST.DEFAULT_COUNTRY_CODE, config?: FilterUserToInviteConfig, @@ -2986,7 +2980,6 @@ function filterUserToInvite( loginList, currentUserEmail, currentUserAccountID, - reports, ...config, }); } @@ -3028,7 +3021,6 @@ function filterOptions( loginList: OnyxEntry, currentUserEmail: string, currentUserAccountID: number, - reports: OnyxCollection, personalDetailsCollection: OnyxEntry, config?: FilterUserToInviteConfig, ): Options { @@ -3053,7 +3045,6 @@ function filterOptions( loginList, currentUserEmail, currentUserAccountID, - reports, personalDetailsCollection, countryCode, { @@ -3120,13 +3111,12 @@ function filterAndOrderOptions( loginList: OnyxEntry, currentUserEmail: string, currentUserAccountID: number, - reports: OnyxCollection, personalDetails: OnyxEntry, config?: FilterAndOrderConfig, ): Options { let filterResult = options; if (searchInputValue.trim().length > 0) { - filterResult = filterOptions(options, searchInputValue, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, personalDetails, config); + filterResult = filterOptions(options, searchInputValue, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, config); } const orderedOptions = combineOrderingOfReportsAndPersonalDetails(filterResult, searchInputValue, config); diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 80de99968c81..65eab0f48eea 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -90,7 +90,6 @@ function useOptions(reportAttributesDerived: ReportAttributesDerivedValue['repor const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); - const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const reports = listOptions?.reports ?? []; const personalDetails = listOptions?.personalDetails ?? []; @@ -106,7 +105,6 @@ function useOptions(reportAttributesDerived: ReportAttributesDerivedValue['repor loginList, currentUserAccountID, currentUserEmail, - allReports, { betas: betas ?? [], includeSelfDM: true, @@ -121,7 +119,7 @@ function useOptions(reportAttributesDerived: ReportAttributesDerivedValue['repor const areOptionsInitialized = !isLoading; - const options = filterAndOrderOptions(unselectedOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, allReports, allPersonalDetails, { + const options = filterAndOrderOptions(unselectedOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, allPersonalDetails, { selectedOptions, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, }); @@ -168,7 +166,6 @@ function useOptions(reportAttributesDerived: ReportAttributesDerivedValue['repor loginList, currentUserEmail: personalData.email ?? '', currentUserAccountID: personalData.accountID, - reports: allReports, }); if (participantOption) { result.push({ diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index afa2f22f69e9..efabcb48e862 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -72,7 +72,7 @@ function RoomInvitePage({ const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const isReportArchived = useReportIsArchived(report.reportID); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); + const {options, areOptionsInitialized} = useOptionsList(); const allPersonalDetails = usePersonalDetails(); @@ -100,7 +100,6 @@ function RoomInvitePage({ loginList, currentUserAccountID, currentUserEmail, - reports, allPersonalDetails, betas ?? [], excludedUsers, @@ -133,7 +132,7 @@ function RoomInvitePage({ const inviteOptions = debouncedSearchTerm.trim() === '' ? defaultOptions - : filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, allPersonalDetails, { + : filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, allPersonalDetails, { excludeLogins: excludedUsers, }); diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index cdfa3ffa164c..98aa29e49441 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -69,9 +69,10 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const privateIsArchivedMap = usePrivateIsArchivedMap(); const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; const ancestors = useAncestors(report); + const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; const displayReport = useMemo( - () => getReportDisplayOption(report, unknownUserDetails, personalDetail.accountID, personalDetails, privateIsArchived, reports, reportAttributesDerived), - [report, unknownUserDetails, personalDetails, privateIsArchived, reportAttributesDerived, personalDetail.accountID, reports], + () => getReportDisplayOption(report, unknownUserDetails, personalDetail.accountID, personalDetails, privateIsArchived, chatReport, reportAttributesDerived), + [report, unknownUserDetails, personalDetails, privateIsArchived, reportAttributesDerived, personalDetail.accountID, chatReport], ); const shouldShowAttachment = !isTextShared; diff --git a/src/pages/Share/ShareTab.tsx b/src/pages/Share/ShareTab.tsx index 2535cf8e0e3e..2d43b3681b2d 100644 --- a/src/pages/Share/ShareTab.tsx +++ b/src/pages/Share/ShareTab.tsx @@ -67,7 +67,6 @@ function ShareTab({ref}: ShareTabProps) { const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const showLoadingPlaceholder = useMemo(() => !areOptionsInitialized || !didScreenTransitionEnd, [areOptionsInitialized, didScreenTransitionEnd]); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const searchOptions = useMemo(() => { if (!areOptionsInitialized) { return defaultListOptions; @@ -86,7 +85,6 @@ function ShareTab({ref}: ShareTabProps) { loginList, currentUserAccountID, currentUserEmail, - reports, personalDetails, }); }, [ @@ -100,7 +98,6 @@ function ShareTab({ref}: ShareTabProps) { loginList, currentUserAccountID, currentUserEmail, - reports, personalDetails, ]); diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 193a374b5982..0514229b3257 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -66,7 +66,6 @@ function SplitBillDetailsPage({route, report, reportAction}: SplitBillDetailsPag const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, {canBeMissing: true}); const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true}); // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID @@ -74,7 +73,7 @@ function SplitBillDetailsPage({route, report, reportAction}: SplitBillDetailsPag if (isPolicyExpenseChat(report)) { participants = [ getParticipantsOption({accountID: participantAccountIDs.at(0), selected: true, reportID: ''}, personalDetails), - getPolicyExpenseReportOption({...report, selected: true, reportID}, currentUserPersonalDetails.accountID, personalDetails, reports, reportAttributesDerived), + getPolicyExpenseReportOption({...report, selected: true, reportID}, currentUserPersonalDetails.accountID, personalDetails, reportAttributesDerived), ]; } else { participants = participantAccountIDs.map((accountID) => getParticipantsOption({accountID, selected: true, reportID: ''}, personalDetails)); diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index b8417e1519bb..4bd11762780e 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -67,7 +67,6 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserEmail = currentUserPersonalDetails.email ?? ''; const currentUserAccountID = currentUserPersonalDetails.accountID; @@ -93,7 +92,6 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType loginList, currentUserAccountID, currentUserEmail, - reports, { betas, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, @@ -124,7 +122,6 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType currentUserAccountID, currentUserEmail, personalDetails, - reports, ]); const chatOptions = useMemo(() => { @@ -137,12 +134,12 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType headerMessage: '', }; } - const newOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, reports, personalDetails, { + const newOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, }); return newOptions; - }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, reports, personalDetails]); + }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]); /** * Returns the sections needed for the OptionsSelector @@ -166,7 +163,6 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType true, undefined, reportAttributesDerived, - reports, ); // Just a temporary fix to satisfy the type checker // Will be fixed when migrating to use new SelectionListWithSections @@ -197,7 +193,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType data: [chatOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }), shouldShow: true, @@ -227,7 +223,6 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType countryCode, currentUserAccountID, currentUserEmail, - reports, ]); const selectAccountant = useCallback( diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index 359da04cc9d6..ee83c80b547a 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -70,7 +70,6 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserEmail = currentUserPersonalDetails.email ?? ''; const currentUserAccountID = currentUserPersonalDetails.accountID; @@ -223,7 +222,6 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde true, undefined, reportAttributesDerived, - reports, ); newSections.push({ @@ -262,7 +260,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde data: [orderedAvailableOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) as OptionData[], shouldShow: true, @@ -294,7 +292,6 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde translate, currentUserAccountID, currentUserEmail, - reports, ]); const optionLength = useMemo(() => { diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index dd426b4dc4c0..808b0af2e6c3 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -124,7 +124,6 @@ function MoneyRequestParticipantsSelector({ const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [textInputAutoFocus, setTextInputAutoFocus] = useState(!isNative); const selectionListRef = useRef(null); @@ -297,7 +296,6 @@ function MoneyRequestParticipantsSelector({ true, undefined, reportAttributesDerived, - reports, ); // Just a temporary fix to satisfy the type checker // Will be fixed when migrating to use new SelectionListWithSections @@ -348,7 +346,7 @@ function MoneyRequestParticipantsSelector({ data: [availableOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reports, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }), shouldShow: true, @@ -381,7 +379,6 @@ function MoneyRequestParticipantsSelector({ inputHelperText, currentUserAccountID, currentUserEmail, - reports, ]); /** diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index 7feafc0165a6..595eaf469679 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -139,7 +139,6 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, currentUserEmail: MOCK_CURRENT_USER_EMAIL, - reports: {}, personalDetails, }), ); @@ -156,11 +155,10 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, - {}, ValidOptionsConfig, ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}, personalDetails); + filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, personalDetails); }); }); test('[OptionsListUtils] getFilteredOptions with empty search value', async () => { @@ -173,11 +171,10 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, - {}, ValidOptionsConfig, ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, {}, personalDetails); + filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, personalDetails); }); }); @@ -193,7 +190,6 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, - {}, { betas: mockedBetas, includeMultipleParticipantReports: true, @@ -222,7 +218,6 @@ describe('OptionsListUtils', () => { loginList, MOCK_CURRENT_USER_ACCOUNT_ID, MOCK_CURRENT_USER_EMAIL, - {}, personalDetails, mockedBetas, {}, diff --git a/tests/unit/OptionListContextProviderTest.tsx b/tests/unit/OptionListContextProviderTest.tsx index 0de8e00ce3de..2643b761c11a 100644 --- a/tests/unit/OptionListContextProviderTest.tsx +++ b/tests/unit/OptionListContextProviderTest.tsx @@ -169,6 +169,6 @@ describe('OptionListContextProvider', () => { mockUsePersonalDetails.mockReturnValue(updatedPersonalDetails); rerender({shouldInitialize: false}); - expect(mockCreateOptionFromReport).toHaveBeenCalledWith(report, updatedPersonalDetails, expect.any(Number), {[reportKey]: report}, 'true', undefined, {showPersonalDetails: true}); + expect(mockCreateOptionFromReport).toHaveBeenCalledWith(report, updatedPersonalDetails, expect.any(Number), undefined, 'true', undefined, {showPersonalDetails: true}); }); }); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 5465be155f84..cd8ddae45cf7 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -803,7 +803,6 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); @@ -832,7 +831,6 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); @@ -863,7 +861,6 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); @@ -891,7 +888,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call orderOptions() results = orderOptions(results); @@ -931,7 +927,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call orderOptions() results = orderOptions(results); @@ -967,7 +962,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // Then the result should be empty @@ -990,7 +984,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // Then the result should include all personalDetails except the currently logged in user @@ -1013,7 +1006,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, }, @@ -1036,7 +1028,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, }, @@ -1062,7 +1053,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, }, @@ -1090,7 +1080,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeP2P: true, canShowManagerMcTest: true, @@ -1115,7 +1104,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeP2P: true, canShowManagerMcTest: false, @@ -1149,7 +1137,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeP2P: true, canShowManagerMcTest: true, @@ -1207,7 +1194,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeMultipleParticipantReports: true, }, @@ -1262,7 +1248,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeMultipleParticipantReports: true, showRBR: true, @@ -1315,7 +1300,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeMultipleParticipantReports: true, showRBR: false, @@ -1372,7 +1356,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeRecentReports: true, shouldUnreadBeBold: true, @@ -1408,7 +1391,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { personalDetails: customPersonalDetails, }, @@ -1425,7 +1407,7 @@ describe('OptionsListUtils', () => { it('should include all reports by default', () => { // Given a set of reports and personalDetails that includes workspace rooms // When we call getValidOptions() - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1457,7 +1439,7 @@ describe('OptionsListUtils', () => { }; // When we call getValidOptions with shouldSeparateWorkspaceChat and personalDetails config - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1475,7 +1457,7 @@ describe('OptionsListUtils', () => { it('should handle undefined personalDetails config in workspace chat lookups', () => { // Given a set of reports with workspace rooms // When we call getValidOptions with shouldSeparateWorkspaceChat but no personalDetails config - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1492,7 +1474,7 @@ describe('OptionsListUtils', () => { it('should handle empty personalDetails config in workspace chat lookups', () => { // Given a set of reports with workspace rooms // When we call getValidOptions with shouldSeparateWorkspaceChat and empty personalDetails - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1509,7 +1491,7 @@ describe('OptionsListUtils', () => { it('should handle null personalDetails config in workspace chat lookups', () => { // Given a set of reports with workspace rooms // When we call getValidOptions with shouldSeparateWorkspaceChat and null personalDetails - const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS, { + const results = getValidOptions(OPTIONS_WITH_WORKSPACE_ROOM, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, { includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -1536,7 +1518,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); const reportLogins = new Set(results.recentReports.map((reportOption) => reportOption.login)); const personalDetailsOverlapWithReports = results.personalDetails.every((personalDetailOption) => reportLogins.has(personalDetailOption.login)); @@ -1558,7 +1539,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {'peterparker@expensify.com': true}, }, @@ -1580,7 +1560,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // Then the result should include all personalDetails except the currently logged in user @@ -1603,7 +1582,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, }, @@ -1627,7 +1605,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, }, @@ -1654,7 +1631,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, }, @@ -1679,7 +1655,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { maxRecentReportElements: maxRecentReports, }, @@ -1700,7 +1675,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); const resultsWithLimit = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, @@ -1710,7 +1684,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { maxRecentReportElements: 2, }, @@ -1731,7 +1704,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); const resultsWithLimit = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, @@ -1741,7 +1713,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { maxRecentReportElements: 2, }, @@ -1764,7 +1735,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { maxElements: maxTotalElements, maxRecentReportElements: maxRecentReports, @@ -1799,7 +1769,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -1841,7 +1810,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -1873,7 +1841,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, PERSONAL_DETAILS, [], {}, @@ -1904,7 +1871,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, PERSONAL_DETAILS, [], excludeLogins, @@ -1926,7 +1892,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, undefined, [], {}, @@ -1948,7 +1913,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, {}, [], {}, @@ -1970,7 +1934,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, {}, [], {}, @@ -2009,7 +1972,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, partialPersonalDetails, [], {}, @@ -2040,7 +2002,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, modifiedPersonalDetails, [], {}, @@ -2065,7 +2026,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, PERSONAL_DETAILS, [], excludeLogins, @@ -2266,11 +2226,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then all options should be returned expect(filteredOptions.recentReports.length + filteredOptions.personalDetails.length).toBe(14); @@ -2289,11 +2248,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { sortByReportTypeInSearch: true, }); @@ -2321,11 +2279,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2346,11 +2303,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2372,11 +2328,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS_WITH_PERIODS, }); // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS_WITH_PERIODS, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS_WITH_PERIODS, { sortByReportTypeInSearch: true, }); @@ -2398,11 +2353,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2422,11 +2376,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2454,11 +2407,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only two reports should be returned expect(filterOptions.recentReports.length).toBe(2); @@ -2478,11 +2430,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -2503,11 +2454,10 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then the user to invite should be returned expect(filteredOptions.userToInvite?.login).toBe(searchText); @@ -2524,13 +2474,12 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }, ); // When we call filterAndOrderOptions with a search value and excluded logins list - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -2549,11 +2498,10 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value and excludeLogins - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -2572,11 +2520,10 @@ describe('OptionsListUtils', () => { nvpDismissedProductTraining, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 2 - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { maxRecentReportsToShow: 2, }); @@ -2585,7 +2532,7 @@ describe('OptionsListUtils', () => { // Note: in the past maxRecentReportsToShow: 0 would return all recent reports, this has changed, and is expected to return none now // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 0 - const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { maxRecentReportsToShow: 0, }); @@ -2605,11 +2552,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then there should be one matching result expect(filteredOptions.personalDetails.length).toBe(1); @@ -2625,7 +2571,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, PERSONAL_DETAILS, [], {}, @@ -2633,7 +2578,7 @@ describe('OptionsListUtils', () => { COUNTRY_CODE, ); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -2647,7 +2592,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, PERSONAL_DETAILS, [], {}, @@ -2662,7 +2606,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, - REPORTS, PERSONAL_DETAILS, ); @@ -2690,7 +2633,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -2707,7 +2649,7 @@ describe('OptionsListUtils', () => { }, ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2733,7 +2675,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -2750,7 +2691,7 @@ describe('OptionsListUtils', () => { }, ); // When we pass the returned options to filterAndOrderOptions with a search value that matches the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -2776,7 +2717,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { betas: [], includeMultipleParticipantReports: true, @@ -2793,7 +2733,7 @@ describe('OptionsListUtils', () => { }, ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2809,10 +2749,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that matches a personal detail with no existing report - const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -2853,7 +2792,6 @@ describe('OptionsListUtils', () => { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, personalDetails: PERSONAL_DETAILS, - reports: REPORTS_WITH_GROUP_CHAT, searchQuery: 'Spider-Man', }); @@ -2894,7 +2832,6 @@ describe('OptionsListUtils', () => { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, personalDetails: PERSONAL_DETAILS, - reports: REPORTS_WITH_GROUP_CHAT, searchQuery: 'peterparker@expensify.com', }); @@ -2935,7 +2872,6 @@ describe('OptionsListUtils', () => { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, personalDetails: PERSONAL_DETAILS, - reports: REPORTS_WITH_GROUP_CHAT, searchQuery: 'Black Panther', }); @@ -2976,7 +2912,6 @@ describe('OptionsListUtils', () => { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, personalDetails: PERSONAL_DETAILS, - reports: REPORTS_WITH_GROUP_CHAT, searchQuery: 'Wolverine', }); @@ -3019,7 +2954,6 @@ describe('OptionsListUtils', () => { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, personalDetails: PERSONAL_DETAILS, - reports: REPORTS_WITH_GROUP_CHAT_NO_PARTICIPANTS, }); // When we pass the returned options to filterAndOrderOptions with any search value @@ -3030,7 +2964,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, - REPORTS_WITH_GROUP_CHAT_NO_PARTICIPANTS, PERSONAL_DETAILS, ); @@ -3049,10 +2982,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3071,10 +3003,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3093,7 +3024,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite const filteredOptions = filterAndOrderOptions( @@ -3103,7 +3033,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, - REPORTS, PERSONAL_DETAILS, ); @@ -3123,10 +3052,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value without accent mark - const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then one personalDetails with accent mark should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -3142,10 +3070,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3166,10 +3093,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3190,10 +3116,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3214,10 +3139,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3236,14 +3160,13 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeUserToInvite: true, }, ); // When we call filterAndOrderOptions with a plain text name (not email or phone) without shouldAcceptName - const filteredOptions = filterAndOrderOptions(options, 'Jeff Amazon', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filteredOptions = filterAndOrderOptions(options, 'Jeff Amazon', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { shouldAcceptName: false, }); @@ -3261,14 +3184,13 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { includeUserToInvite: true, }, ); // When we call filterAndOrderOptions with a plain text name (not email or phone) with shouldAcceptName - const filteredOptions = filterAndOrderOptions(options, 'Jeff', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filteredOptions = filterAndOrderOptions(options, 'Jeff', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { shouldAcceptName: true, }); @@ -3286,10 +3208,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -3305,7 +3226,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that matches an email const filteredOptions = filterAndOrderOptions( @@ -3315,7 +3235,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, - REPORTS, PERSONAL_DETAILS, { sortByReportTypeInSearch: true, @@ -3340,10 +3259,9 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with a search value that matches both reports and personal details and maxRecentReportsToShow param - const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS, { + const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { maxRecentReportsToShow: 5, }); @@ -3368,11 +3286,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value that matches a personal detail - const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then one personal detail should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3390,11 +3307,10 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value that matches multiple items - const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -3416,7 +3332,6 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS_WITH_PERIODS, }); // When we pass the returned options to filterAndOrderOptions with a search value @@ -3427,7 +3342,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, - REPORTS, PERSONAL_DETAILS_WITH_PERIODS, { sortByReportTypeInSearch: true, @@ -3457,11 +3371,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); const matchingEntries = filteredOptions.personalDetails.filter((detail) => detail.login === login); // Then there should be 2 unique login entries @@ -3483,11 +3396,10 @@ describe('OptionsListUtils', () => { betas: [CONST.BETAS.ALL], currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then the self dm should be on top. expect(filteredOptions.recentReports.at(0)?.isSelfDM).toBe(true); @@ -4088,7 +4000,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction); await waitForBatchedUpdates(); - const result = createOption([1, 2], PERSONAL_DETAILS, report, CURRENT_USER_ACCOUNT_ID, REPORTS, {showChatPreviewLine: true}); + const result = createOption([1, 2], PERSONAL_DETAILS, report, CURRENT_USER_ACCOUNT_ID, undefined, {showChatPreviewLine: true}); expect(result.alternateText).toBe('Iron Man owes ₫34'); }); @@ -4121,7 +4033,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); - const result = createOption([1, 2], PERSONAL_DETAILS, report, 1, reports); + const result = createOption([1, 2], PERSONAL_DETAILS, report, 1, chatReport); expect(result.reportID).toBe(reportID); expect(typeof result.text).toBe('string'); @@ -4787,7 +4699,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, undefined); // Then it should return an option with isSelfDM and alternateText set expect(result.isSelfDM).toBe(true); @@ -4807,7 +4719,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, undefined); // Then it should return an option with invoice room text and alternateText expect(result.isInvoiceRoom).toBe(true); @@ -4829,7 +4741,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, unknownUserDetails, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); + const result = getReportDisplayOption(report, unknownUserDetails, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, undefined); // Then it should return an option with unknownUserDetails data expect(result.text).toBe('Unknown User'); @@ -4850,7 +4762,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, undefined); // Then it should return an option with workspace name expect(result.text).toBe(POLICY.name); @@ -4877,7 +4789,7 @@ describe('OptionsListUtils', () => { }; // When we call getReportDisplayOption with custom personalDetails - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, customPersonalDetails, undefined, REPORTS); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, customPersonalDetails, undefined, undefined); // Then it should use the custom personalDetails parameter expect(result).toBeDefined(); @@ -4894,7 +4806,7 @@ describe('OptionsListUtils', () => { const emptyPersonalDetails: PersonalDetailsList = {}; // When we call getReportDisplayOption - const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, emptyPersonalDetails, undefined, REPORTS); + const result = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, emptyPersonalDetails, undefined, undefined); // Then it should not throw and return a valid option expect(result).toBeDefined(); @@ -4906,7 +4818,7 @@ describe('OptionsListUtils', () => { const personalDetails: PersonalDetailsList = PERSONAL_DETAILS; // When we call getReportDisplayOption with undefined report - const result = getReportDisplayOption(undefined, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, REPORTS); + const result = getReportDisplayOption(undefined, undefined, CURRENT_USER_ACCOUNT_ID, personalDetails, undefined, undefined); // Then it should return a valid option (createOption handles undefined) expect(result).toBeDefined(); @@ -4939,7 +4851,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); expect(results).toBeDefined(); @@ -4949,7 +4860,7 @@ describe('OptionsListUtils', () => { it('should work with undefined policies', () => { const options = {reports: [], personalDetails: []}; - const results = getValidOptions(options, undefined, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); + const results = getValidOptions(options, undefined, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4958,7 +4869,7 @@ describe('OptionsListUtils', () => { it('should work with empty policies collection', () => { const options = {reports: [], personalDetails: []}; - const results = getValidOptions(options, {}, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, REPORTS); + const results = getValidOptions(options, {}, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -4990,7 +4901,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, { betas: [], includeRecentReports: true, @@ -5297,7 +5207,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, undefined); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -5320,7 +5230,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, undefined); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -5340,7 +5250,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined, REPORTS); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined, undefined); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -5364,7 +5274,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, undefined); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -5388,7 +5298,7 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await waitForBatchedUpdates(); - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, REPORTS); + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportNameValuePair?.private_isArchived, undefined); expect(option).toBeDefined(); expect(option.reportID).toBe(reportID); @@ -5699,7 +5609,7 @@ describe('OptionsListUtils', () => { selected: true, }; - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails, REPORTS); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails); expect(option).toBeDefined(); expect(option.text).toBe('Test Workspace Policy'); @@ -5760,7 +5670,7 @@ describe('OptionsListUtils', () => { isPolicyExpenseChat: true, }; - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails, REPORTS); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails); expect(option).toBeDefined(); expect(option.text).toBe('Team Workspace'); @@ -5804,7 +5714,7 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is empty - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, {}, REPORTS); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, {}); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Without Details'); @@ -5848,7 +5758,7 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is undefined - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, undefined, REPORTS); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, undefined); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Undefined Details'); @@ -5900,10 +5810,10 @@ describe('OptionsListUtils', () => { selected: false, }; - const optionSelected = getPolicyExpenseReportOption(participantSelected, CURRENT_USER_ACCOUNT_ID, {}, REPORTS); + const optionSelected = getPolicyExpenseReportOption(participantSelected, CURRENT_USER_ACCOUNT_ID, {}); // eslint-disable-next-line rulesdir/no-negated-variables - const optionNotSelected = getPolicyExpenseReportOption(participantNotSelected, CURRENT_USER_ACCOUNT_ID, {}, REPORTS); + const optionNotSelected = getPolicyExpenseReportOption(participantNotSelected, CURRENT_USER_ACCOUNT_ID, {}); expect(optionSelected.isSelected).toBe(true); expect(optionSelected.selected).toBe(true); @@ -5920,7 +5830,6 @@ describe('OptionsListUtils', () => { loginList: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, }); expect(result).toBeNull(); }); @@ -5933,7 +5842,6 @@ describe('OptionsListUtils', () => { loginList: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, }); expect(result).not.toBeNull(); expect(result?.login).toBe('Jeff Amazon'); @@ -6002,7 +5910,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - reportsCollection, ); // Then the function should complete without errors and return valid results @@ -6021,11 +5928,10 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - REPORTS, ); // When we call filterAndOrderOptions with the reports parameter - const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, REPORTS, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then the function should complete without errors and return valid results expect(filteredOptions).toBeDefined(); @@ -6047,7 +5953,6 @@ describe('OptionsListUtils', () => { loginList, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: reportsCollection, personalDetails: PERSONAL_DETAILS, }); @@ -6070,7 +5975,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - reportsCollection, PERSONAL_DETAILS, [], {}, @@ -6091,7 +5995,6 @@ describe('OptionsListUtils', () => { loginList: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, - reports: REPORTS, personalDetails: PERSONAL_DETAILS, }); @@ -6113,7 +6016,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - emptyReports, ); // Then the function should still work correctly @@ -6123,7 +6025,7 @@ describe('OptionsListUtils', () => { }); it('should work correctly when reports is undefined', () => { - // When we call getValidOptions with undefined reports + // When we call getValidOptions without reports parameter const results = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, allPolicies, @@ -6132,7 +6034,6 @@ describe('OptionsListUtils', () => { loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, - undefined, ); // Then the function should still work correctly @@ -6173,8 +6074,8 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, linkedChatReport); await waitForBatchedUpdates(); - // When we call createOption with a reports collection that includes the linked chat - const result = createOption([1, 2], PERSONAL_DETAILS, expenseReport, CURRENT_USER_ACCOUNT_ID, reportsWithLinkedChat); + // When we call createOption with the linked chat report + const result = createOption([1, 2], PERSONAL_DETAILS, expenseReport, CURRENT_USER_ACCOUNT_ID, linkedChatReport); // Then the option should be created successfully expect(result).toBeDefined(); @@ -6208,8 +6109,8 @@ describe('OptionsListUtils', () => { await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); - // When we call getReportDisplayOption with reports collection - const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined, reportsCollection); + // When we call getReportDisplayOption with chat report + const option = getReportDisplayOption(report, undefined, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, undefined, chatReport); // Then the option should be created successfully using the reports collection expect(option).toBeDefined(); @@ -6254,7 +6155,7 @@ describe('OptionsListUtils', () => { }; // When we call getPolicyExpenseReportOption with reports collection - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, reportsCollection); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then the option should be created successfully expect(option).toBeDefined(); @@ -6274,7 +6175,7 @@ describe('OptionsListUtils', () => { }, }; - const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, REPORTS, undefined); + const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, undefined, undefined); expect(result).toBeDefined(); expect(result.reportID).toBe('1'); @@ -6293,7 +6194,7 @@ describe('OptionsListUtils', () => { }; const privateIsArchived = DateUtils.getDBTime(); - const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, REPORTS, privateIsArchived); + const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, undefined, privateIsArchived); expect(result).toBeDefined(); expect(result.private_isArchived).toBe(privateIsArchived); @@ -6310,7 +6211,7 @@ describe('OptionsListUtils', () => { }, }; - const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, REPORTS, undefined); + const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, undefined, undefined); expect(result).toBeDefined(); expect(result.private_isArchived).toBeUndefined(); @@ -6328,7 +6229,7 @@ describe('OptionsListUtils', () => { }; // Pass undefined for reportAttributesDerived - the function should handle it gracefully - const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, REPORTS, undefined, undefined); + const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, undefined, undefined, undefined); expect(result).toBeDefined(); expect(result.reportID).toBe('1'); @@ -6346,7 +6247,7 @@ describe('OptionsListUtils', () => { }; const config = {showPersonalDetails: true}; - const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, REPORTS, undefined, undefined, config); + const result = createOptionFromReport(report, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, undefined, undefined, undefined, config); expect(result).toBeDefined(); expect(result.reportID).toBe('1'); From ea7f30df2cec2e98f37195e9fa0a5d8798101488 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 00:09:27 +0100 Subject: [PATCH 25/40] Revert accidental Mobile-Expensify submodule change --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index a4663a30d7b9..e0b5ad692c30 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit a4663a30d7b948ea34c90f381773c60b8c3ebd0a +Subproject commit e0b5ad692c30e0303cb83a42962ef98d8d1a635f From a6fdeb29362342800e35d31a6b601579fb616dd4 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 00:16:03 +0100 Subject: [PATCH 26/40] fixing prettier --- .../FilterDropdowns/UserSelectPopup.tsx | 13 +--- .../Search/SearchFiltersChatsSelector.tsx | 9 +-- .../SearchFiltersParticipantsSelector.tsx | 13 +--- src/pages/RoomInvitePage.tsx | 1 - src/pages/Share/ShareTab.tsx | 14 +--- tests/unit/OptionsListUtilsTest.tsx | 65 +++---------------- 6 files changed, 12 insertions(+), 103 deletions(-) diff --git a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx index a6970b67e1e1..1c72a1abfb9a 100644 --- a/src/components/Search/FilterDropdowns/UserSelectPopup.tsx +++ b/src/components/Search/FilterDropdowns/UserSelectPopup.tsx @@ -116,18 +116,7 @@ function UserSelectPopup({value, closeOverlay, onChange, isSearchable}: UserSele }, countryCode, ); - }, [ - options.reports, - options.personalDetails, - allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - countryCode, - personalDetails, - currentUserAccountID, - currentUserEmail, - ]); + }, [options.reports, options.personalDetails, allPolicies, draftComments, nvpDismissedProductTraining, loginList, countryCode, personalDetails, currentUserAccountID, currentUserEmail]); const filteredOptions = useMemo(() => { return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 29c7b633c521..4d1ed3ff87c6 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -69,14 +69,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const reportData = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]; const chatReport = reportData?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportData.chatReportID}`] : undefined; const report = getSelectedOptionData( - createOptionFromReport( - {...reportData, reportID: id}, - personalDetails, - currentUserAccountID, - chatReport, - privateIsArchived, - reportAttributesDerived, - ), + createOptionFromReport({...reportData, reportID: id}, personalDetails, currentUserAccountID, chatReport, privateIsArchived, reportAttributesDerived), ); const isReportArchived = !!privateIsArchived; const alternateText = getAlternateText(report, {}, isReportArchived, currentUserAccountID, {}, reportAttributesDerived); diff --git a/src/components/Search/SearchFiltersParticipantsSelector.tsx b/src/components/Search/SearchFiltersParticipantsSelector.tsx index 160c34c3b8bb..f26ad6b62b72 100644 --- a/src/components/Search/SearchFiltersParticipantsSelector.tsx +++ b/src/components/Search/SearchFiltersParticipantsSelector.tsx @@ -190,18 +190,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate, } return filteredOptions; - }, [ - unselectedOptions, - cleanSearchTerm, - countryCode, - loginList, - selectedOptions, - shouldAllowNameOnlyOptions, - searchTerm, - currentUserEmail, - currentUserAccountID, - personalDetails, - ]); + }, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, shouldAllowNameOnlyOptions, searchTerm, currentUserEmail, currentUserAccountID, personalDetails]); const {sections, headerMessage} = useMemo(() => { const newSections: SelectionListSections = []; diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index efabcb48e862..8c2b70ff2df9 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -73,7 +73,6 @@ function RoomInvitePage({ const isReportArchived = useReportIsArchived(report.reportID); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); - const {options, areOptionsInitialized} = useOptionsList(); const allPersonalDetails = usePersonalDetails(); diff --git a/src/pages/Share/ShareTab.tsx b/src/pages/Share/ShareTab.tsx index 2d43b3681b2d..6cd22e3403d4 100644 --- a/src/pages/Share/ShareTab.tsx +++ b/src/pages/Share/ShareTab.tsx @@ -87,19 +87,7 @@ function ShareTab({ref}: ShareTabProps) { currentUserEmail, personalDetails, }); - }, [ - areOptionsInitialized, - options, - draftComments, - nvpDismissedProductTraining, - betas, - textInputValue, - countryCode, - loginList, - currentUserAccountID, - currentUserEmail, - personalDetails, - ]); + }, [areOptionsInitialized, options, draftComments, nvpDismissedProductTraining, betas, textInputValue, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]); const recentReportsOptions = useMemo(() => { if (textInputValue.trim() === '') { diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index cd8ddae45cf7..15e9ae74dcdf 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -954,15 +954,7 @@ describe('OptionsListUtils', () => { it('should return empty options when no reports or personal details are provided', () => { // Given empty arrays of reports and personalDetails // When we call getValidOptions() - const results = getValidOptions( - {reports: [], personalDetails: []}, - allPolicies, - {}, - nvpDismissedProductTraining, - loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - ); + const results = getValidOptions({reports: [], personalDetails: []}, allPolicies, {}, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); // Then the result should be empty expect(results.personalDetails).toEqual([]); @@ -2599,15 +2591,7 @@ describe('OptionsListUtils', () => { COUNTRY_CODE, ); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions( - options, - 'peterparker@expensify.com', - COUNTRY_CODE, - loginList, - CURRENT_USER_EMAIL, - CURRENT_USER_ACCOUNT_ID, - PERSONAL_DETAILS, - ); + const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then one personal detail should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -2957,15 +2941,7 @@ describe('OptionsListUtils', () => { }); // When we pass the returned options to filterAndOrderOptions with any search value - const filteredOptions = filterAndOrderOptions( - options, - 'Unknown', - COUNTRY_CODE, - loginList, - CURRENT_USER_EMAIL, - CURRENT_USER_ACCOUNT_ID, - PERSONAL_DETAILS, - ); + const filteredOptions = filterAndOrderOptions(options, 'Unknown', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then the report should still be found by its reportName even if participantsList is empty expect(filteredOptions.recentReports.length).toBe(1); @@ -3026,15 +3002,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_EMAIL, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions( - options, - 'peter.parker@expensify.com', - COUNTRY_CODE, - loginList, - CURRENT_USER_EMAIL, - CURRENT_USER_ACCOUNT_ID, - PERSONAL_DETAILS, - ); + const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3228,18 +3196,9 @@ describe('OptionsListUtils', () => { CURRENT_USER_EMAIL, ); // When we call filterAndOrderOptions with a search value that matches an email - const filteredOptions = filterAndOrderOptions( - options, - 'peterparker@expensify.com', - COUNTRY_CODE, - loginList, - CURRENT_USER_EMAIL, - CURRENT_USER_ACCOUNT_ID, - PERSONAL_DETAILS, - { - sortByReportTypeInSearch: true, - }, - ); + const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + sortByReportTypeInSearch: true, + }); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -4843,15 +4802,7 @@ describe('OptionsListUtils', () => { const policies = {[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`]: policy}; // Test that getValidOptions accepts policies collection as second parameter - const results = getValidOptions( - {reports: [], personalDetails: []}, - policies, - undefined, - nvpDismissedProductTraining, - loginList, - CURRENT_USER_ACCOUNT_ID, - CURRENT_USER_EMAIL, - ); + const results = getValidOptions({reports: [], personalDetails: []}, policies, undefined, nvpDismissedProductTraining, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); From 137f43434086a68b816ccab72f66529a67692c11 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 11:14:13 +0100 Subject: [PATCH 27/40] replace getReportOrDraftReport with top-down report params in getPolicyExpenseReportOption --- src/libs/OptionsListUtils/index.ts | 73 ++++++++++--------- src/pages/iou/SplitBillDetailsPage.tsx | 3 +- .../MoneyRequestAccountantSelector.tsx | 9 ++- .../request/MoneyRequestAttendeeSelector.tsx | 9 ++- .../MoneyRequestParticipantsSelector.tsx | 9 ++- tests/unit/OptionsListUtilsTest.tsx | 20 ++--- 6 files changed, 73 insertions(+), 50 deletions(-) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 0cac83be0061..fd73b4fa53f8 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -1121,11 +1121,10 @@ function getPolicyExpenseReportOption( participant: Participant | SearchOptionData, currentUserAccountID: number, personalDetails: OnyxEntry, + expenseReport: OnyxEntry, + chatReport: OnyxEntry, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], ): SearchOptionData { - const expenseReport = reportUtilsIsPolicyExpenseChat(participant) ? getReportOrDraftReport(participant.reportID) : null; - const chatReport = expenseReport?.chatReportID ? getReportOrDraftReport(expenseReport.chatReportID) : undefined; - const visibleParticipantAccountIDs = Object.entries(expenseReport?.participants ?? {}) .filter(([, reportParticipant]) => reportParticipant && !isHiddenForCurrentUser(reportParticipant.notificationPreference)) .map(([accountID]) => Number(accountID)); @@ -2789,44 +2788,50 @@ function formatSectionsFromSearchTerm( section: { title: undefined, sectionIndex: 0, - data: shouldGetOptionDetails + data: shouldGetOptionDetails ? selectedOptions.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; - return isReportPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) - : getParticipantsOption(participant, personalDetails); + if (isReportPolicyExpenseChat) { + const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; + const chatReport = expenseReport?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.chatReportID}`] : undefined; + return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); + } + return getParticipantsOption(participant, personalDetails); }) : selectedOptions, - }, - }; - } + }, + }; +} - const cleanSearchTerm = searchTerm.trim().toLowerCase(); - // If you select a new user you don't have a contact for, they won't get returned as part of a recent report or personal details - // This will add them to the list of options, deduping them if they already exist in the other lists - const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { - const accountID = participant.accountID ?? null; - const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm); - const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID); - const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); +const cleanSearchTerm = searchTerm.trim().toLowerCase(); +// If you select a new user you don't have a contact for, they won't get returned as part of a recent report or personal details +// This will add them to the list of options, deduping them if they already exist in the other lists +const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { + const accountID = participant.accountID ?? null; + const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm); + const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID); + const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); - return isPartOfSearchTerm && !isReportInRecentReports && !isReportInPersonalDetails; - }); + return isPartOfSearchTerm && !isReportInRecentReports && !isReportInPersonalDetails; +}); - return { - section: { - title: undefined, - sectionIndex: 0, - data: shouldGetOptionDetails - ? selectedParticipantsWithoutDetails.map((participant) => { - const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; - return isReportPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) - : getParticipantsOption(participant, personalDetails); - }) - : selectedParticipantsWithoutDetails, - }, - }; +return { + section: { + title: undefined, + sectionIndex: 0, + data: shouldGetOptionDetails + ? selectedParticipantsWithoutDetails.map((participant) => { + const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; + if (isReportPolicyExpenseChat) { + const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; + const chatReport = expenseReport?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.chatReportID}`] : undefined; + return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); + } + return getParticipantsOption(participant, personalDetails); + }) + : selectedParticipantsWithoutDetails, + }, +}; } /** diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 0514229b3257..98ab8caecb22 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -67,13 +67,14 @@ function SplitBillDetailsPage({route, report, reportAction}: SplitBillDetailsPag const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true}); + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(report?.chatReportID)}`, {canBeMissing: true}); // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID let participants: Array; if (isPolicyExpenseChat(report)) { participants = [ getParticipantsOption({accountID: participantAccountIDs.at(0), selected: true, reportID: ''}, personalDetails), - getPolicyExpenseReportOption({...report, selected: true, reportID}, currentUserPersonalDetails.accountID, personalDetails, reportAttributesDerived), + getPolicyExpenseReportOption({...report, selected: true, reportID}, currentUserPersonalDetails.accountID, personalDetails, report, chatReport, reportAttributesDerived), ]; } else { participants = participantAccountIDs.map((accountID) => getParticipantsOption({accountID, selected: true, reportID: ''}, personalDetails)); diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 4bd11762780e..3dab419bb8cf 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -15,6 +15,7 @@ import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import memoize from '@libs/memoize'; import type {Section} from '@libs/OptionsListUtils'; import { @@ -141,6 +142,10 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType return newOptions; }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]); + const userToInviteReportID = chatOptions?.userToInvite?.isPolicyExpenseChat ? chatOptions.userToInvite.reportID : undefined; + const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); + const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + /** * Returns the sections needed for the OptionsSelector */ @@ -193,7 +198,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType data: [chatOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, userToInviteExpenseReport, userToInviteChatReport, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }), shouldShow: true, @@ -217,6 +222,8 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType chatOptions.userToInvite, debouncedSearchTerm, personalDetails, + userToInviteExpenseReport, + userToInviteChatReport, reportAttributesDerived, translate, loginList, diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index ee83c80b547a..66836b490006 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -20,6 +20,7 @@ import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {searchInServer} from '@libs/actions/Report'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import { formatSectionsFromSearchTerm, getFilteredRecentAttendees, @@ -161,6 +162,10 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde }; }, [availableOptions, isPaidGroupPolicy, areOptionsInitialized, searchTerm, action]); + const userToInviteReportID = availableOptions?.userToInvite?.isPolicyExpenseChat ? availableOptions.userToInvite.reportID : undefined; + const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); + const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + const shouldShowErrorMessage = selectedOptions.length < 1; const handleConfirmSelection = useCallback( @@ -260,7 +265,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde data: [orderedAvailableOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, userToInviteExpenseReport, userToInviteChatReport, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }) as OptionData[], shouldShow: true, @@ -286,6 +291,8 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde orderedAvailableOptions.personalDetails, orderedAvailableOptions.userToInvite, personalDetails, + userToInviteExpenseReport, + userToInviteChatReport, reportAttributesDerived, loginList, countryCode, diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 808b0af2e6c3..64023b954098 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -30,6 +30,7 @@ import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionS import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import getPlatform from '@libs/getPlatform'; import goToSettings from '@libs/goToSettings'; import {isMovingTransactionFromTrackExpense} from '@libs/IOUUtils'; @@ -241,6 +242,10 @@ function MoneyRequestParticipantsSelector({ const cleanSearchTerm = useMemo(() => debouncedSearchTerm.trim().toLowerCase(), [debouncedSearchTerm]); + const userToInviteReportID = availableOptions?.userToInvite?.isPolicyExpenseChat ? availableOptions.userToInvite.reportID : undefined; + const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); + const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + useEffect(() => { searchInServer(debouncedSearchTerm.trim()); }, [debouncedSearchTerm]); @@ -346,7 +351,7 @@ function MoneyRequestParticipantsSelector({ data: [availableOptions.userToInvite].map((participant) => { const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived) + ? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, userToInviteExpenseReport, userToInviteChatReport, reportAttributesDerived) : getParticipantsOption(participant, personalDetails); }), shouldShow: true, @@ -372,6 +377,8 @@ function MoneyRequestParticipantsSelector({ availableOptions.userToInvite, availableOptions.recentReports, availableOptions.personalDetails, + userToInviteExpenseReport, + userToInviteChatReport, isWorkspacesOnly, loginList, isPerDiemRequest, diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 15e9ae74dcdf..a880cf7a2d80 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -5560,7 +5560,7 @@ describe('OptionsListUtils', () => { selected: true, }; - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails, report, undefined); expect(option).toBeDefined(); expect(option.text).toBe('Test Workspace Policy'); @@ -5621,7 +5621,7 @@ describe('OptionsListUtils', () => { isPolicyExpenseChat: true, }; - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, testPersonalDetails, report, undefined); expect(option).toBeDefined(); expect(option.text).toBe('Team Workspace'); @@ -5665,7 +5665,7 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is empty - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, {}); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, {}, report, undefined); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Without Details'); @@ -5709,7 +5709,7 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is undefined - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, undefined); + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, undefined, report, undefined); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Undefined Details'); @@ -5761,10 +5761,10 @@ describe('OptionsListUtils', () => { selected: false, }; - const optionSelected = getPolicyExpenseReportOption(participantSelected, CURRENT_USER_ACCOUNT_ID, {}); + const optionSelected = getPolicyExpenseReportOption(participantSelected, CURRENT_USER_ACCOUNT_ID, {}, report, undefined); // eslint-disable-next-line rulesdir/no-negated-variables - const optionNotSelected = getPolicyExpenseReportOption(participantNotSelected, CURRENT_USER_ACCOUNT_ID, {}); + const optionNotSelected = getPolicyExpenseReportOption(participantNotSelected, CURRENT_USER_ACCOUNT_ID, {}, report, undefined); expect(optionSelected.isSelected).toBe(true); expect(optionSelected.selected).toBe(true); @@ -6091,10 +6091,6 @@ describe('OptionsListUtils', () => { isPolicyExpenseChatEnabled: true, }; - const reportsCollection = { - [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: report, - }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${testPolicyID}`, policy); await waitForBatchedUpdates(); @@ -6105,8 +6101,8 @@ describe('OptionsListUtils', () => { isPolicyExpenseChat: true, }; - // When we call getPolicyExpenseReportOption with reports collection - const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + // When we call getPolicyExpenseReportOption with report passed directly + const option = getPolicyExpenseReportOption(participant, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, report, undefined); // Then the option should be created successfully expect(option).toBeDefined(); From 689845950a529048d3d3dba518b740fa2a555a63 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 16:19:27 +0100 Subject: [PATCH 28/40] fixing eslint --- tests/unit/OptionsListUtilsTest.tsx | 33 ----------------------------- 1 file changed, 33 deletions(-) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index a880cf7a2d80..36fbc135e1b5 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -3983,11 +3983,6 @@ describe('OptionsListUtils', () => { reportID: chatReportID, }; - const reports = { - [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: report, - [`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]: chatReport, - }; - await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); @@ -5847,11 +5842,6 @@ describe('OptionsListUtils', () => { describe('reports parameter functionality', () => { it('getValidOptions should use reports parameter to look up chat reports', () => { - // Given a reports collection - const reportsCollection = { - ...REPORTS, - }; - // When we call getValidOptions with the reports collection const results = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, @@ -5891,11 +5881,6 @@ describe('OptionsListUtils', () => { }); it('getSearchOptions should use reports parameter from config', () => { - // Given a reports collection - const reportsCollection = { - ...REPORTS, - }; - // When we call getSearchOptions with reports in the config const options = getSearchOptions({ options: OPTIONS, @@ -5914,11 +5899,6 @@ describe('OptionsListUtils', () => { }); it('getMemberInviteOptions should use reports parameter correctly', () => { - // Given personal details and a reports collection - const reportsCollection = { - ...REPORTS, - }; - // When we call getMemberInviteOptions with the reports parameter const results = getMemberInviteOptions( OPTIONS.personalDetails, @@ -5955,9 +5935,6 @@ describe('OptionsListUtils', () => { }); it('should work correctly when reports is an empty object', () => { - // Given an empty reports collection - const emptyReports = {}; - // When we call getValidOptions with empty reports const results = getValidOptions( {reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails}, @@ -6016,11 +5993,6 @@ describe('OptionsListUtils', () => { reportName: 'Linked Chat Report', }; - const reportsWithLinkedChat = { - [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: expenseReport, - [`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]: linkedChatReport, - }; - await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, expenseReport); await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, linkedChatReport); await waitForBatchedUpdates(); @@ -6051,11 +6023,6 @@ describe('OptionsListUtils', () => { reportID: chatReportID, }; - const reportsCollection = { - [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: report, - [`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]: chatReport, - }; - await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport); await waitForBatchedUpdates(); From bb8ea090e1d4e3a8f3a7de87f54ac7bdc2af7625 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 17:28:33 +0100 Subject: [PATCH 29/40] fixing prettier --- src/libs/OptionsListUtils/index.ts | 62 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index fd73b4fa53f8..6260914700e1 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -2788,7 +2788,7 @@ function formatSectionsFromSearchTerm( section: { title: undefined, sectionIndex: 0, - data: shouldGetOptionDetails + data: shouldGetOptionDetails ? selectedOptions.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; if (isReportPolicyExpenseChat) { @@ -2799,39 +2799,39 @@ function formatSectionsFromSearchTerm( return getParticipantsOption(participant, personalDetails); }) : selectedOptions, - }, - }; -} + }, + }; + } -const cleanSearchTerm = searchTerm.trim().toLowerCase(); -// If you select a new user you don't have a contact for, they won't get returned as part of a recent report or personal details -// This will add them to the list of options, deduping them if they already exist in the other lists -const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { - const accountID = participant.accountID ?? null; - const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm); - const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID); - const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); + const cleanSearchTerm = searchTerm.trim().toLowerCase(); + // If you select a new user you don't have a contact for, they won't get returned as part of a recent report or personal details + // This will add them to the list of options, deduping them if they already exist in the other lists + const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => { + const accountID = participant.accountID ?? null; + const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm); + const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID); + const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID); - return isPartOfSearchTerm && !isReportInRecentReports && !isReportInPersonalDetails; -}); + return isPartOfSearchTerm && !isReportInRecentReports && !isReportInPersonalDetails; + }); -return { - section: { - title: undefined, - sectionIndex: 0, - data: shouldGetOptionDetails - ? selectedParticipantsWithoutDetails.map((participant) => { - const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; - if (isReportPolicyExpenseChat) { - const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; - const chatReport = expenseReport?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.chatReportID}`] : undefined; - return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); - } - return getParticipantsOption(participant, personalDetails); - }) - : selectedParticipantsWithoutDetails, - }, -}; + return { + section: { + title: undefined, + sectionIndex: 0, + data: shouldGetOptionDetails + ? selectedParticipantsWithoutDetails.map((participant) => { + const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; + if (isReportPolicyExpenseChat) { + const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; + const chatReport = expenseReport?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.chatReportID}`] : undefined; + return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); + } + return getParticipantsOption(participant, personalDetails); + }) + : selectedParticipantsWithoutDetails, + }, + }; } /** From f668a7c16030a1f4c782867a959d4f35e14e2602 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Wed, 11 Feb 2026 19:53:55 +0100 Subject: [PATCH 30/40] using allreports instead of getReportOrDraftReport --- src/libs/OptionsListUtils/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 6260914700e1..988011105ca7 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -1015,7 +1015,7 @@ function getReportOption( reportDrafts?: OnyxCollection, ): OptionData { const report = getReportOrDraftReport(participant.reportID, undefined, undefined, reportDrafts); - const chatReport = report?.chatReportID ? getReportOrDraftReport(report.chatReportID) : undefined; + const chatReport = report?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); const option = createOption( From e439bc0324f27084905953772abf2553a8e96859 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Thu, 12 Feb 2026 00:18:27 +0100 Subject: [PATCH 31/40] minor code refactoring --- src/components/LHNOptionsList/LHNOptionsList.tsx | 2 +- src/libs/OptionsListUtils/index.ts | 14 ++++++-------- src/pages/Share/ShareDetailsPage.tsx | 3 +-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index c60e9217b96a..5c42f1eba31c 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -237,7 +237,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio movedFromReport, movedToReport, policy: itemPolicy, - isReportArchived, + isReportArchived: !!itemReportNameValuePairs?.private_isArchived, policyForMovingExpensesID, reportMetadata: itemReportMetadata, chatReport, diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 988011105ca7..a25d2c6acf17 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -465,7 +465,7 @@ function getAlternateText( reportAttributesDerived?: ReportAttributesDerivedValue['reports'], ) { const report = getReportOrDraftReport(option.reportID); - const chatReport = getReportOrDraftReport(report?.chatReportID); + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const isAdminRoom = reportUtilsIsAdminRoom(report); const isAnnounceRoom = reportUtilsIsAnnounceRoom(report); const isGroupChat = reportUtilsIsGroupChat(report); @@ -1015,7 +1015,7 @@ function getReportOption( reportDrafts?: OnyxCollection, ): OptionData { const report = getReportOrDraftReport(participant.reportID, undefined, undefined, reportDrafts); - const chatReport = report?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); const option = createOption( @@ -1293,7 +1293,7 @@ function createOptionList( if (reports) { for (const report of Object.values(reports)) { - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, chatReport, reportAttributesDerived); if (reportMapEntry) { @@ -1310,7 +1310,7 @@ function createOptionList( const allPersonalDetailsOptions = Object.values(personalDetails ?? {}).map((personalDetail) => { const report = reportMapForAccountIDs[personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID]; const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; return { item: personalDetail, @@ -1415,7 +1415,7 @@ function createFilteredOptionList( // Step 5: Process the limited set of reports (performance optimization) const reportOptions: Array> = []; for (const report of limitedReports) { - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, chatReport, reportAttributesDerived); if (reportMapEntry) { @@ -1446,7 +1446,7 @@ function createFilteredOptionList( const report = reportMapForAccountIDs[accountID]; const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; return { item: personalDetail, ...createOption( @@ -2220,7 +2220,6 @@ function getRestrictedLogins( /** * Options are reports and personal details. This function filters out the options that are not valid to be displayed. */ -// eslint-disable-next-line @typescript-eslint/max-params function getValidOptions( options: OptionList, policiesCollection: OnyxCollection, @@ -2679,7 +2678,6 @@ function formatMemberForList(member: SearchOptionData): MemberForList { * Build the options for the Workspace Member Invite view * This method will be removed. See https://github.com/Expensify/App/issues/66615 for more information. */ -// eslint-disable-next-line @typescript-eslint/max-params function getMemberInviteOptions( personalDetails: Array>, nvpDismissedProductTraining: OnyxEntry, diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index 98aa29e49441..0eab7c4ad722 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -56,7 +56,6 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true}); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector}); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const personalDetails = usePersonalDetails(); const personalDetail = useCurrentUserPersonalDetails(); const isTextShared = currentAttachment?.mimeType === CONST.SHARE_FILE_MIMETYPE.TXT; @@ -69,7 +68,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const privateIsArchivedMap = usePrivateIsArchivedMap(); const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; const ancestors = useAncestors(report); - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`, {canBeMissing: true}); const displayReport = useMemo( () => getReportDisplayOption(report, unknownUserDetails, personalDetail.accountID, personalDetails, privateIsArchived, chatReport, reportAttributesDerived), [report, unknownUserDetails, personalDetails, privateIsArchived, reportAttributesDerived, personalDetail.accountID, chatReport], From 78b64f44553075cb7e3fcd0c5cc693f70007c322 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Thu, 12 Feb 2026 00:24:37 +0100 Subject: [PATCH 32/40] fixing ts --- tests/unit/OptionsListUtilsTest.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 93100f1903bc..44be989c59d3 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -4327,6 +4327,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, + chatReport: undefined, }); expect(lastMessage).toBe(translateLocal('report.noActivityYet')); }); @@ -4355,6 +4356,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, + chatReport: undefined, }); const transactions = getReportTransactions(report.reportID); const scanningTransactions = transactions.filter((transaction) => isScanning(transaction)); @@ -4392,6 +4394,7 @@ describe('OptionsListUtils', () => { translate: translateLocal, lastActorDetails: null, isReportArchived: false, + chatReport: undefined, }); expect(result).toBe(''); }); From 65f93f92a68ec7221a3d3614dc350cf3f3e144cf Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Thu, 12 Feb 2026 00:32:48 +0100 Subject: [PATCH 33/40] Simplify chatReport lookups by removing redundant ternaries --- src/components/OptionListContextProvider.tsx | 6 +++--- src/components/Search/SearchFiltersChatsSelector.tsx | 2 +- src/components/Search/SearchRouter/SearchRouter.tsx | 2 +- src/libs/OptionsListUtils/index.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/OptionListContextProvider.tsx b/src/components/OptionListContextProvider.tsx index 81f30ba41e03..41dd1bd2b354 100644 --- a/src/components/OptionListContextProvider.tsx +++ b/src/components/OptionListContextProvider.tsx @@ -123,7 +123,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { for (const reportKey of changedReportKeys) { const report = changedReportsEntries[reportKey]; const reportID = reportKey.replace(ONYXKEYS.COLLECTION.REPORT, ''); - const chatReport = report?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const {reportOption} = processReport(report, personalDetails, currentUserAccountID, chatReport, reportAttributes?.reports); if (reportOption) { @@ -159,7 +159,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, ''); const reportItem = updatedReportsMap.get(reportID)?.item; - const chatReport = reportItem?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportItem.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportItem?.chatReportID}`]; const {reportOption} = processReport(reportItem, personalDetails, currentUserAccountID, chatReport, reportAttributes?.reports); if (reportOption) { @@ -230,7 +230,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) { } const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`]; - const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`]; const newReportOption = createOptionFromReport(report, personalDetails, currentUserAccountID, chatReport, privateIsArchived, reportAttributes?.reports, { showPersonalDetails: true, }); diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 4d1ed3ff87c6..67abb5f356ac 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -67,7 +67,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const selectedOptions: OptionData[] = selectedReportIDs.map((id) => { const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${id}`]; const reportData = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]; - const chatReport = reportData?.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportData.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportData?.chatReportID}`]; const report = getSelectedOptionData( createOptionFromReport({...reportData, reportID: id}, personalDetails, currentUserAccountID, chatReport, privateIsArchived, reportAttributesDerived), ); diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 5c61ad7a55f4..601cae417ee1 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -115,7 +115,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla } const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${contextualReportID}`]; - const chatReport = report.chatReportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`] : undefined; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`]; const option = createOptionFromReport(report, personalDetails, currentUserAccountID, chatReport, privateIsArchived, undefined, {showPersonalDetails: true}); reportForContextualSearch = option; } diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 927c1d613586..380841606586 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -2806,7 +2806,7 @@ function formatSectionsFromSearchTerm( const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; if (isReportPolicyExpenseChat) { const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; - const chatReport = expenseReport?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.chatReportID}`] : undefined; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport?.chatReportID}`]; return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); } return getParticipantsOption(participant, personalDetails); @@ -2837,7 +2837,7 @@ function formatSectionsFromSearchTerm( const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; if (isReportPolicyExpenseChat) { const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; - const chatReport = expenseReport?.chatReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.chatReportID}`] : undefined; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport?.chatReportID}`]; return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); } return getParticipantsOption(participant, personalDetails); From aab30a3db963b4a900c0d2f46351f2b613067115 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 17 Feb 2026 22:50:27 +0100 Subject: [PATCH 34/40] Add TODO comments for temporary allReports usages --- src/libs/OptionsListUtils/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 380841606586..8841a269a192 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -467,6 +467,7 @@ function getAlternateText( reportAttributesDerived?: ReportAttributesDerivedValue['reports'], ) { const report = getReportOrDraftReport(option.reportID); + // TODO: This allReports usage is temporary and will be removed once the full Onyx.connect() refactor is complete (https://github.com/Expensify/App/issues/66378) const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const isAdminRoom = reportUtilsIsAdminRoom(report); const isAnnounceRoom = reportUtilsIsAnnounceRoom(report); @@ -1030,6 +1031,7 @@ function getReportOption( reportDrafts?: OnyxCollection, ): OptionData { const report = getReportOrDraftReport(participant.reportID, undefined, undefined, reportDrafts); + // TODO: This allReports usage is temporary and will be removed once the full Onyx.connect() refactor is complete (https://github.com/Expensify/App/issues/66378) const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); @@ -2331,6 +2333,7 @@ function getValidOptions( } const draftComment = draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${report.reportID}`]; + // TODO: This allReports usage is temporary and will be removed once the full Onyx.connect() refactor is complete (https://github.com/Expensify/App/issues/66378) const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.item.chatReportID}`]; return isValidReport( @@ -2805,6 +2808,7 @@ function formatSectionsFromSearchTerm( ? selectedOptions.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; if (isReportPolicyExpenseChat) { + // TODO: This allReports usage is temporary and will be removed once the full Onyx.connect() refactor is complete (https://github.com/Expensify/App/issues/66378) const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport?.chatReportID}`]; return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); @@ -2836,6 +2840,7 @@ function formatSectionsFromSearchTerm( ? selectedParticipantsWithoutDetails.map((participant) => { const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false; if (isReportPolicyExpenseChat) { + // TODO: This allReports usage is temporary and will be removed once the full Onyx.connect() refactor is complete (https://github.com/Expensify/App/issues/66378) const expenseReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`]; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${expenseReport?.chatReportID}`]; return getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, expenseReport, chatReport, reportAttributesDerived); From 262b81993467adfcce4de0f8f2e3c22c2bcc64db Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Thu, 19 Feb 2026 00:42:11 +0100 Subject: [PATCH 35/40] fixing typescript --- tests/unit/OptionsListUtilsTest.tsx | 1 + tests/unit/SidebarUtilsTest.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 5e6a05f191ce..6062adc732a6 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -6084,6 +6084,7 @@ describe('OptionsListUtils', () => { draftComments: {}, nvpDismissedProductTraining, loginList, + policyCollection: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, currentUserEmail: CURRENT_USER_EMAIL, personalDetails: PERSONAL_DETAILS, diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index 4f4d71e18e0d..f7c91f331a4a 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -2529,6 +2529,7 @@ describe('SidebarUtils', () => { invoiceReceiverPolicy: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); // Then isConciergeChat should be true @@ -2560,6 +2561,7 @@ describe('SidebarUtils', () => { invoiceReceiverPolicy: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); // Then isConciergeChat should be false @@ -2590,6 +2592,7 @@ describe('SidebarUtils', () => { invoiceReceiverPolicy: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, }); // Then isConciergeChat should be false From b0d51447530605b4f9357fbe386692a2e0c4bfca Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Fri, 20 Feb 2026 18:40:45 +0100 Subject: [PATCH 36/40] adding tests to the OptionListContextProvider --- tests/unit/OptionListContextProviderTest.tsx | 151 ++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-) diff --git a/tests/unit/OptionListContextProviderTest.tsx b/tests/unit/OptionListContextProviderTest.tsx index 2643b761c11a..abcbfebb4a48 100644 --- a/tests/unit/OptionListContextProviderTest.tsx +++ b/tests/unit/OptionListContextProviderTest.tsx @@ -5,7 +5,7 @@ import OptionListContextProvider, {useOptionsList} from '@components/OptionListC import useOnyx from '@hooks/useOnyx'; import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap'; import type {OptionList, SearchOption} from '@libs/OptionsListUtils'; -import {createOptionFromReport, createOptionList} from '@libs/OptionsListUtils'; +import {createOptionFromReport, createOptionList, processReport} from '@libs/OptionsListUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Report} from '@src/types/onyx'; @@ -29,6 +29,7 @@ jest.mock('@components/OnyxListItemProvider', () => ({ const mockCreateOptionList = createOptionList as jest.MockedFunction; const mockCreateOptionFromReport = createOptionFromReport as jest.MockedFunction; +const mockProcessReport = processReport as jest.MockedFunction; const mockUseOnyx = useOnyx as jest.MockedFunction; const mockUsePersonalDetails = usePersonalDetails as jest.MockedFunction; const mockUsePrivateIsArchivedMap = usePrivateIsArchivedMap as jest.MockedFunction; @@ -171,4 +172,152 @@ describe('OptionListContextProvider', () => { expect(mockCreateOptionFromReport).toHaveBeenCalledWith(report, updatedPersonalDetails, expect.any(Number), undefined, 'true', undefined, {showPersonalDetails: true}); }); + + it('passes resolved chatReport to processReport when changed reports have chatReportID', () => { + const reportID = '1'; + const chatReportID = '2'; + const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; + const chatReportKey = `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`; + const report = {reportID, chatReportID, participants: {}} as unknown as Report; + const chatReport = {reportID: chatReportID, participants: {}} as unknown as Report; + + const {result, rerender} = renderHook(({shouldInitialize}) => useOptionsList({shouldInitialize}), { + initialProps: {shouldInitialize: false}, + wrapper, + }); + + act(() => { + result.current.initializeOptions(); + }); + + mockProcessReport.mockClear(); + + onyxState = { + ...onyxState, + [ONYXKEYS.COLLECTION.REPORT]: { + [reportKey]: report, + [chatReportKey]: chatReport, + }, + }; + onyxSourceValues = { + ...onyxSourceValues, + [ONYXKEYS.COLLECTION.REPORT]: { + [reportKey]: report, + [chatReportKey]: chatReport, + }, + }; + + rerender({shouldInitialize: false}); + + expect(mockProcessReport).toHaveBeenCalledWith(report, {}, expect.any(Number), chatReport, undefined); + }); + + it('passes resolved chatReport to processReport when report actions change', () => { + const reportID = '1'; + const chatReportID = '2'; + const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; + const chatReportKey = `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`; + const report = {reportID, chatReportID, participants: {}} as unknown as Report; + const chatReport = {reportID: chatReportID, participants: {}} as unknown as Report; + + onyxState = { + ...onyxState, + [ONYXKEYS.COLLECTION.REPORT]: { + [reportKey]: report, + [chatReportKey]: chatReport, + }, + }; + onyxSourceValues = { + ...onyxSourceValues, + [ONYXKEYS.COLLECTION.REPORT]: { + [reportKey]: report, + [chatReportKey]: chatReport, + }, + }; + + const mockReportOption = {reportID, item: report, text: 'Report', keyForList: reportID} as unknown as SearchOption; + mockCreateOptionList.mockReturnValue({ + reports: [mockReportOption], + personalDetails: [], + } as OptionList); + + const {result, rerender} = renderHook(({shouldInitialize}) => useOptionsList({shouldInitialize}), { + initialProps: {shouldInitialize: false}, + wrapper, + }); + + act(() => { + result.current.initializeOptions(); + }); + + mockProcessReport.mockClear(); + + const reportActionsKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; + onyxSourceValues = { + ...onyxSourceValues, + [ONYXKEYS.COLLECTION.REPORT_ACTIONS]: { + [reportActionsKey]: {someAction: {reportActionID: '100'}}, + }, + }; + + rerender({shouldInitialize: false}); + + expect(mockProcessReport).toHaveBeenCalledWith(report, {}, expect.any(Number), chatReport, undefined); + }); + + it('passes resolved chatReport to createOptionFromReport when personal details change and report has chatReportID', () => { + const reportID = '1'; + const chatReportID = '2'; + const accountID = '12345'; + const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; + const chatReportKey = `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`; + const report = { + reportID, + chatReportID, + participants: {[accountID]: {notificationPreference: 'always'}}, + }; + const chatReport = {reportID: chatReportID, participants: {}} as unknown as Report; + + const initialPersonalDetails = {[accountID]: {accountID: Number(accountID), firstName: 'John', lastName: 'Doe', login: 'john@test.com', displayName: 'John Doe'}}; + mockUsePersonalDetails.mockReturnValue(initialPersonalDetails); + + onyxState = { + ...onyxState, + [ONYXKEYS.COLLECTION.REPORT]: { + [reportKey]: report, + [chatReportKey]: chatReport, + }, + }; + onyxSourceValues = { + ...onyxSourceValues, + [ONYXKEYS.COLLECTION.REPORT]: { + [reportKey]: report, + [chatReportKey]: chatReport, + }, + }; + + const mockReportOption = {reportID, item: report, text: 'John Doe', keyForList: reportID} as unknown as SearchOption; + mockCreateOptionList.mockReturnValue({ + reports: [mockReportOption], + personalDetails: [], + } as OptionList); + mockCreateOptionFromReport.mockReturnValue(mockReportOption); + + const {result, rerender} = renderHook(({shouldInitialize}) => useOptionsList({shouldInitialize}), { + initialProps: {shouldInitialize: false}, + wrapper, + }); + + act(() => { + result.current.initializeOptions(); + }); + + mockCreateOptionFromReport.mockClear(); + + const updatedPersonalDetails = {[accountID]: {accountID: Number(accountID), firstName: 'Jane', lastName: 'Doe', login: 'john@test.com', displayName: 'Jane Doe'}}; + mockUsePersonalDetails.mockReturnValue(updatedPersonalDetails); + rerender({shouldInitialize: false}); + + expect(mockCreateOptionFromReport).toHaveBeenCalledWith(report, updatedPersonalDetails, expect.any(Number), chatReport, undefined, undefined, {showPersonalDetails: true}); + }); }); From 9930f0200a51a68671d24989c3223495dbf359ad Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Fri, 20 Feb 2026 19:55:44 +0100 Subject: [PATCH 37/40] Extract useUserToInviteReports hook to deduplicate chatReport lookups --- src/hooks/useUserToInviteReports.ts | 15 +++++++++++++++ .../request/MoneyRequestAccountantSelector.tsx | 6 ++---- .../iou/request/MoneyRequestAttendeeSelector.tsx | 6 ++---- .../request/MoneyRequestParticipantsSelector.tsx | 6 ++---- 4 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 src/hooks/useUserToInviteReports.ts diff --git a/src/hooks/useUserToInviteReports.ts b/src/hooks/useUserToInviteReports.ts new file mode 100644 index 000000000000..11d58ada6220 --- /dev/null +++ b/src/hooks/useUserToInviteReports.ts @@ -0,0 +1,15 @@ +import useOnyx from '@hooks/useOnyx'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import type {SearchOptionData} from '@libs/OptionsListUtils/types'; +import ONYXKEYS from '@src/ONYXKEYS'; + +/** + * For policy expense chat invitees, resolves the expense report and its associated chat report. + */ +export default function useUserToInviteReports(userToInvite: SearchOptionData | null | undefined) { + const userToInviteReportID = userToInvite?.isPolicyExpenseChat ? userToInvite.reportID : undefined; + const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); + const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + + return {userToInviteExpenseReport, userToInviteChatReport}; +} diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 68be1458812d..feed3d197e31 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -14,7 +14,7 @@ import useOnyx from '@hooks/useOnyx'; import useReportAttributes from '@hooks/useReportAttributes'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; -import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import useUserToInviteReports from '@hooks/useUserToInviteReports'; import memoize from '@libs/memoize'; import { filterAndOrderOptions, @@ -141,9 +141,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType return newOptions; }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]); - const userToInviteReportID = chatOptions?.userToInvite?.isPolicyExpenseChat ? chatOptions.userToInvite.reportID : undefined; - const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); - const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + const {userToInviteExpenseReport, userToInviteChatReport} = useUserToInviteReports(chatOptions?.userToInvite); /** * Returns the sections needed for the OptionsSelector diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index b29b5b300768..5da9438d50e3 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -19,7 +19,7 @@ import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {searchInServer} from '@libs/actions/Report'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; -import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import useUserToInviteReports from '@hooks/useUserToInviteReports'; import { formatSectionsFromSearchTerm, getFilteredRecentAttendees, @@ -152,9 +152,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde }; } - const userToInviteReportID = availableOptions?.userToInvite?.isPolicyExpenseChat ? availableOptions.userToInvite.reportID : undefined; - const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); - const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + const {userToInviteExpenseReport, userToInviteChatReport} = useUserToInviteReports(availableOptions?.userToInvite); const shouldShowErrorMessage = selectedOptions.length < 1; diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index faf5d0bf93bd..9119a104c840 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -30,7 +30,7 @@ import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionS import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; -import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import useUserToInviteReports from '@hooks/useUserToInviteReports'; import getPlatform from '@libs/getPlatform'; import goToSettings from '@libs/goToSettings'; import {isMovingTransactionFromTrackExpense} from '@libs/IOUUtils'; @@ -239,9 +239,7 @@ function MoneyRequestParticipantsSelector({ const cleanSearchTerm = useMemo(() => debouncedSearchTerm.trim().toLowerCase(), [debouncedSearchTerm]); - const userToInviteReportID = availableOptions?.userToInvite?.isPolicyExpenseChat ? availableOptions.userToInvite.reportID : undefined; - const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); - const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + const {userToInviteExpenseReport, userToInviteChatReport} = useUserToInviteReports(availableOptions?.userToInvite); useEffect(() => { searchInServer(debouncedSearchTerm.trim()); From 452ca95de581365d815ca77a0525b1bd3b6a3190 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 24 Feb 2026 01:10:58 +0100 Subject: [PATCH 38/40] Address review comments: fix relative import, use ordered options, add chatReport to deps --- src/components/LHNOptionsList/OptionRowLHNData.tsx | 1 + src/hooks/useUserToInviteReports.ts | 2 +- src/pages/iou/request/MoneyRequestAttendeeSelector.tsx | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index 7f648e1b0859..bf21fcb5d6c9 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -121,6 +121,7 @@ function OptionRowLHNData({ movedFromReport, movedToReport, currentUserAccountID, + chatReport, reportAttributesDerived, ]); diff --git a/src/hooks/useUserToInviteReports.ts b/src/hooks/useUserToInviteReports.ts index 11d58ada6220..73d95dfca560 100644 --- a/src/hooks/useUserToInviteReports.ts +++ b/src/hooks/useUserToInviteReports.ts @@ -1,4 +1,4 @@ -import useOnyx from '@hooks/useOnyx'; +import useOnyx from './useOnyx'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import type {SearchOptionData} from '@libs/OptionsListUtils/types'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index 5da9438d50e3..8466d8386861 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -152,7 +152,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde }; } - const {userToInviteExpenseReport, userToInviteChatReport} = useUserToInviteReports(availableOptions?.userToInvite); + const {userToInviteExpenseReport, userToInviteChatReport} = useUserToInviteReports(orderedAvailableOptions?.userToInvite); const shouldShowErrorMessage = selectedOptions.length < 1; From eb615f380686225d2a6f4c61b5b753b5cfb5b759 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 24 Feb 2026 01:33:40 +0100 Subject: [PATCH 39/40] fixing ts --- src/components/LHNOptionsList/LHNOptionsList.tsx | 1 + src/hooks/useUserToInviteReports.ts | 6 +++--- src/pages/Share/ShareDetailsPage.tsx | 2 +- tests/unit/OptionListContextProviderTest.tsx | 5 ++--- tests/unit/OptionsListUtilsTest.tsx | 3 +++ tests/unit/SidebarUtilsTest.ts | 3 +++ 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 24c25dfad8cb..fd90762c894a 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -219,6 +219,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio } const movedFromReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastReportAction, CONST.REPORT.MOVE_TYPE.FROM)}`]; const movedToReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastReportAction, CONST.REPORT.MOVE_TYPE.TO)}`]; + const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item?.chatReportID}`]; const itemReportMetadata = reportMetadataCollection?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`]; const lastMessageTextFromReport = getLastMessageTextForReport({ translate, diff --git a/src/hooks/useUserToInviteReports.ts b/src/hooks/useUserToInviteReports.ts index 73d95dfca560..1fe6f6edf904 100644 --- a/src/hooks/useUserToInviteReports.ts +++ b/src/hooks/useUserToInviteReports.ts @@ -1,15 +1,15 @@ -import useOnyx from './useOnyx'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import type {SearchOptionData} from '@libs/OptionsListUtils/types'; import ONYXKEYS from '@src/ONYXKEYS'; +import useOnyx from './useOnyx'; /** * For policy expense chat invitees, resolves the expense report and its associated chat report. */ export default function useUserToInviteReports(userToInvite: SearchOptionData | null | undefined) { const userToInviteReportID = userToInvite?.isPolicyExpenseChat ? userToInvite.reportID : undefined; - const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`, {canBeMissing: true}); - const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`, {canBeMissing: true}); + const [userToInviteExpenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteReportID)}`); + const [userToInviteChatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(userToInviteExpenseReport?.chatReportID)}`); return {userToInviteExpenseReport, userToInviteChatReport}; } diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index 8d75de3315a5..e03e1832f308 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -68,7 +68,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const privateIsArchivedMap = usePrivateIsArchivedMap(); const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]; const ancestors = useAncestors(report); - const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`, {canBeMissing: true}); + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`); const displayReport = useMemo( () => getReportDisplayOption(report, unknownUserDetails, personalDetail.accountID, personalDetails, privateIsArchived, chatReport, reportAttributesDerived), [report, unknownUserDetails, personalDetails, privateIsArchived, reportAttributesDerived, personalDetail.accountID, chatReport], diff --git a/tests/unit/OptionListContextProviderTest.tsx b/tests/unit/OptionListContextProviderTest.tsx index 04d9151b1fab..3d4274e624b9 100644 --- a/tests/unit/OptionListContextProviderTest.tsx +++ b/tests/unit/OptionListContextProviderTest.tsx @@ -30,7 +30,6 @@ jest.mock('@components/OnyxListItemProvider', () => ({ const mockCreateOptionList = createOptionList as jest.MockedFunction; const mockProcessReport = processReport as jest.MockedFunction; const mockCreateOptionFromReport = createOptionFromReport as jest.MockedFunction; -const mockProcessReport = processReport as jest.MockedFunction; const mockUseOnyx = useOnyx as jest.MockedFunction; const mockUsePersonalDetails = usePersonalDetails as jest.MockedFunction; const mockUsePrivateIsArchivedMap = usePrivateIsArchivedMap as jest.MockedFunction; @@ -263,7 +262,7 @@ describe('OptionListContextProvider', () => { rerender({shouldInitialize: false}); - expect(mockProcessReport).toHaveBeenCalledWith(report, {}, expect.any(Number), chatReport, undefined); + expect(mockProcessReport).toHaveBeenCalledWith(report, {}, undefined, expect.any(Number), chatReport, undefined); }); it('passes resolved chatReport to processReport when report actions change', () => { @@ -316,7 +315,7 @@ describe('OptionListContextProvider', () => { rerender({shouldInitialize: false}); - expect(mockProcessReport).toHaveBeenCalledWith(report, {}, expect.any(Number), chatReport, undefined); + expect(mockProcessReport).toHaveBeenCalledWith(report, {}, undefined, expect.any(Number), chatReport, undefined); }); it('passes resolved chatReport to createOptionFromReport when personal details change and report has chatReportID', () => { diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 0c37971074c8..082732450972 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -4444,6 +4444,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, + chatReport: undefined, }); expect(lastMessage).toBe(getCustomTaxNameUpdateMessage(translateLocal, action)); }); @@ -4463,6 +4464,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, + chatReport: undefined, }); expect(lastMessage).toBe(getCurrencyDefaultTaxUpdateMessage(translateLocal, action)); }); @@ -4482,6 +4484,7 @@ describe('OptionsListUtils', () => { report, lastActorDetails: null, isReportArchived: false, + chatReport: undefined, }); expect(lastMessage).toBe(getForeignCurrencyDefaultTaxUpdateMessage(translateLocal, action)); }); diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index 9a463d680628..a5b424dbac22 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -1452,6 +1452,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, reportAttributesDerived: undefined, }); @@ -1491,6 +1492,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, reportAttributesDerived: undefined, }); @@ -1530,6 +1532,7 @@ describe('SidebarUtils', () => { lastActionReport: undefined, isReportArchived: undefined, currentUserAccountID: 0, + chatReport: undefined, reportAttributesDerived: undefined, }); From 3e21c2ee3a03823000ed4574c2e799c11a54d891 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 24 Feb 2026 01:42:00 +0100 Subject: [PATCH 40/40] fixing prettier --- src/components/AvatarCropModal/AvatarCropModal.tsx | 2 +- src/components/HeaderWithBackButton/index.tsx | 2 +- src/components/Lightbox/index.tsx | 2 +- src/components/PDFThumbnail/index.native.tsx | 2 +- src/components/TransactionItemRow/ReceiptPreview/index.tsx | 2 +- src/pages/iou/request/MoneyRequestAccountantSelector.tsx | 2 +- src/pages/iou/request/MoneyRequestAttendeeSelector.tsx | 2 +- src/pages/iou/request/MoneyRequestParticipantsSelector.tsx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/AvatarCropModal/AvatarCropModal.tsx b/src/components/AvatarCropModal/AvatarCropModal.tsx index 033279932f39..ac77934485a9 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.tsx +++ b/src/components/AvatarCropModal/AvatarCropModal.tsx @@ -7,7 +7,6 @@ import ImageSize from 'react-native-image-size'; import {interpolate, useSharedValue} from 'react-native-reanimated'; import {scheduleOnUI} from 'react-native-worklets'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import Button from '@components/Button'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; @@ -24,6 +23,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import cropOrRotateImage from '@libs/cropOrRotateImage'; import type {CustomRNImageManipulatorResult} from '@libs/cropOrRotateImage/types'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import CONST from '@src/CONST'; import type IconAsset from '@src/types/utils/IconAsset'; import ImageCropView from './ImageCropView'; diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 2d81005e4feb..96c2c9c6b7f9 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -2,7 +2,6 @@ import React, {useMemo} from 'react'; import {Keyboard, StyleSheet, View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import Avatar from '@components/Avatar'; import AvatarWithDisplayName from '@components/AvatarWithDisplayName'; import Header from '@components/Header'; @@ -21,6 +20,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useThrottledButtonState from '@hooks/useThrottledButtonState'; import getButtonState from '@libs/getButtonState'; import Navigation from '@libs/Navigation/Navigation'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; diff --git a/src/components/Lightbox/index.tsx b/src/components/Lightbox/index.tsx index 6ad732981b18..63cfeb4fbc79 100644 --- a/src/components/Lightbox/index.tsx +++ b/src/components/Lightbox/index.tsx @@ -3,7 +3,6 @@ import type {LayoutChangeEvent, StyleProp, ViewStyle} from 'react-native'; import {PixelRatio, StyleSheet, View} from 'react-native'; import {useSharedValue} from 'react-native-reanimated'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import AttachmentOfflineIndicator from '@components/AttachmentOfflineIndicator'; import {useAttachmentCarouselPagerActions, useAttachmentCarouselPagerState} from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext'; import type {Attachment} from '@components/Attachments/types'; @@ -17,6 +16,7 @@ import usePrevious from '@hooks/usePrevious'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {isLocalFile} from '@libs/fileDownload/FileUtils'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import CONST from '@src/CONST'; import type {Dimensions} from '@src/types/utils/Layout'; import NUMBER_OF_CONCURRENT_LIGHTBOXES from './numberOfConcurrentLightboxes'; diff --git a/src/components/PDFThumbnail/index.native.tsx b/src/components/PDFThumbnail/index.native.tsx index 09778fde3194..024bbad2a627 100644 --- a/src/components/PDFThumbnail/index.native.tsx +++ b/src/components/PDFThumbnail/index.native.tsx @@ -2,9 +2,9 @@ import React, {useState} from 'react'; import {View} from 'react-native'; import Pdf from 'react-native-pdf'; import LoadingIndicator from '@components/LoadingIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import PDFThumbnailError from './PDFThumbnailError'; import type PDFThumbnailProps from './types'; diff --git a/src/components/TransactionItemRow/ReceiptPreview/index.tsx b/src/components/TransactionItemRow/ReceiptPreview/index.tsx index f2ffbb0c8da2..c102d9fdfc6f 100644 --- a/src/components/TransactionItemRow/ReceiptPreview/index.tsx +++ b/src/components/TransactionItemRow/ReceiptPreview/index.tsx @@ -4,7 +4,6 @@ import type {LayoutChangeEvent} from 'react-native'; import {StyleSheet, View} from 'react-native'; import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'; import ActivityIndicator from '@components/ActivityIndicator'; -import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import DistanceEReceipt from '@components/DistanceEReceipt'; import EReceiptWithSizeCalculation from '@components/EReceiptWithSizeCalculation'; import type {ImageOnLoadEvent} from '@components/Image/types'; @@ -12,6 +11,7 @@ import useDebouncedState from '@hooks/useDebouncedState'; import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {hasReceiptSource, isDistanceRequest, isManualDistanceRequest, isPerDiemRequest} from '@libs/TransactionUtils'; import variables from '@styles/variables'; import Image from '@src/components/Image'; diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 8cd03cc863c7..91d27223c2a8 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -13,8 +13,8 @@ import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useReportAttributes from '@hooks/useReportAttributes'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; -import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import useUserToInviteReports from '@hooks/useUserToInviteReports'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import memoize from '@libs/memoize'; import { filterAndOrderOptions, diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index 446a4f67d525..5f863d1f7c3c 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -17,9 +17,9 @@ import useReportAttributes from '@hooks/useReportAttributes'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; +import useUserToInviteReports from '@hooks/useUserToInviteReports'; import {searchInServer} from '@libs/actions/Report'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; -import useUserToInviteReports from '@hooks/useUserToInviteReports'; import { formatSectionsFromSearchTerm, getFilteredRecentAttendees, diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index a4e659c16ecd..5e7c9125eb01 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -29,8 +29,8 @@ import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionS import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import useTransactionDraftValues from '@hooks/useTransactionDraftValues'; -import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import useUserToInviteReports from '@hooks/useUserToInviteReports'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import getPlatform from '@libs/getPlatform'; import goToSettings from '@libs/goToSettings'; import {isMovingTransactionFromTrackExpense} from '@libs/IOUUtils';