From a1ff3d44c2b4f941b351fdb868bac050dfb79bd9 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 2 Mar 2026 11:07:31 +0700 Subject: [PATCH 1/2] refactor getSections to use conciergeReportID from useOnyx --- src/components/Search/index.tsx | 5 + .../Search/TransactionGroupListItem.tsx | 2 + src/hooks/useSearchSections.ts | 2 + src/libs/SearchUIUtils.ts | 7 +- tests/unit/Search/SearchUIUtilsTest.ts | 354 ++++++++++++++++++ 5 files changed, 368 insertions(+), 2 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 7d819f989a1a0..8a7aa285f57a4 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -254,6 +254,7 @@ function Search({ const [visibleColumns] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {selector: columnsSelector}); const [customCardNames] = useOnyx(ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES); const [cardList] = useOnyx(ONYXKEYS.CARD_LIST); + const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); const isExpenseReportType = type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; const {markReportIDAsMultiTransactionExpense, unmarkReportIDAsMultiTransactionExpense} = useWideRHPActions(); @@ -439,6 +440,7 @@ function Search({ customCardNames, allReportMetadata, cardList, + conciergeReportID, }); return [filteredData1, filteredData1.length, allLength]; }, [ @@ -463,6 +465,7 @@ function Search({ customCardNames, allReportMetadata, cardList, + conciergeReportID, ]); // For group-by views, each grouped item has a transactionsQueryJSON with a hash pointing to a separate snapshot @@ -501,6 +504,7 @@ function Search({ cardFeeds, allReportMetadata, cardList, + conciergeReportID, }); return {...item, transactions: transactions1 as TransactionListItemType[]}; }); @@ -520,6 +524,7 @@ function Search({ bankAccountList, allReportMetadata, cardList, + conciergeReportID, ]); const hasLoadedAllTransactions = useMemo(() => { diff --git a/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx b/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx index a487e000d2c9b..9d6de716269dd 100644 --- a/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx +++ b/src/components/SelectionListWithSections/Search/TransactionGroupListItem.tsx @@ -116,6 +116,7 @@ function TransactionGroupListItem({ const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); const [cardFeeds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER); const [cardList] = useOnyx(ONYXKEYS.CARD_LIST); + const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); let transactions: TransactionListItemType[]; if (isExpenseReportType) { @@ -135,6 +136,7 @@ function TransactionGroupListItem({ allReportMetadata, cardFeeds, cardList, + conciergeReportID, }) as [TransactionListItemType[], number]; transactions = sectionData.map((transactionItem) => ({ ...transactionItem, diff --git a/src/hooks/useSearchSections.ts b/src/hooks/useSearchSections.ts index 91a65110fd04a..446f2c3101d65 100644 --- a/src/hooks/useSearchSections.ts +++ b/src/hooks/useSearchSections.ts @@ -33,6 +33,7 @@ function useSearchSections(): UseSearchSectionsResult { const [cardList] = useOnyx(ONYXKEYS.CARD_LIST); const archivedReportsIdSet = useArchivedReportsIdSet(); + const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); const {type, status, sortBy, sortOrder, groupBy} = lastSearchQuery?.queryJSON ?? {}; const searchResultsData = currentSearchResults?.data; @@ -59,6 +60,7 @@ function useSearchSections(): UseSearchSectionsResult { cardFeeds, allReportMetadata, cardList, + conciergeReportID, }); allReports = getSortedSections(type, status ?? '', searchData, localeCompare, translate, sortBy, sortOrder, groupBy).map((value) => value.reportID); } diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index a691595351a07..0e9d6e2a676ee 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -487,6 +487,7 @@ type GetSectionsParams = { allTransactionViolations?: OnyxCollection; visibleReportActionsData?: OnyxTypes.VisibleReportActionsDerivedValue; allReportMetadata: OnyxCollection; + conciergeReportID: string | undefined; }; const GROUP_BY_TO_SORT_COLUMN: Partial, string>> = { @@ -1968,6 +1969,7 @@ function getActions( function getTaskSections( data: OnyxTypes.SearchResults['data'], formatPhoneNumber: LocaleContextProps['formatPhoneNumber'], + conciergeReportID: string | undefined, archivedReportsIDList?: ArchivedReportsIDSet, ): [TaskListItemType[], number] { const tasks = Object.keys(data) @@ -2007,7 +2009,7 @@ function getTaskSections( const policy = data[`${ONYXKEYS.COLLECTION.POLICY}${parentReport.policyID}`]; const isParentReportArchived = archivedReportsIDList?.has(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${parentReport?.reportID}`); // eslint-disable-next-line @typescript-eslint/no-deprecated - const parentReportName = getReportName({report: parentReport, policy, isReportArchived: isParentReportArchived}); + const parentReportName = getReportName({report: parentReport, policy, isReportArchived: isParentReportArchived, conciergeReportID}); const icons = getIcons(parentReport, formatPhoneNumber, personalDetails, null, '', -1, policy, undefined, isParentReportArchived); const parentReportIcon = icons?.at(0); @@ -2802,12 +2804,13 @@ function getSections({ visibleReportActionsData, allReportMetadata, cardList, + conciergeReportID, }: GetSectionsParams) { if (type === CONST.SEARCH.DATA_TYPES.CHAT) { return getReportActionsSections(data, visibleReportActionsData); } if (type === CONST.SEARCH.DATA_TYPES.TASK) { - return getTaskSections(data, formatPhoneNumber, archivedReportsIDList); + return getTaskSections(data, formatPhoneNumber, conciergeReportID, archivedReportsIDList); } if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index f643e4a9820ac..daefe75833e9b 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -9,6 +9,7 @@ import TransactionGroupListItem from '@components/SelectionListWithSections/Sear import TransactionListItem from '@components/SelectionListWithSections/Search/TransactionListItem'; import type { ReportActionListItemType, + TaskListItemType, TransactionCardGroupListItemType, TransactionCategoryGroupListItemType, TransactionGroupListItemType, @@ -2416,6 +2417,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, }); expect(filteredReportActions).toStrictEqual(reportActionListItems); expect(allReportActionsLength).toBe(6); @@ -2432,6 +2434,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toEqual(transactionsListItems); }); @@ -2459,6 +2462,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, })[0] as TransactionListItemType[]; const distanceTransaction = result.find((item) => item.transactionID === distanceTransactionID); @@ -2493,6 +2497,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, })[0] as TransactionGroupListItemType[]; const reportGroup = result.find((group) => group.transactions?.some((transaction) => transaction.transactionID === distanceTransactionID)); @@ -2517,6 +2522,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionReportGroupListItems); }); @@ -2559,6 +2565,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, })[0]; const resultReportFirst = SearchUIUtils.getSections({ type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, @@ -2569,6 +2576,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, })[0]; expect(resultTransactionFirst).toBeDefined(); @@ -2593,6 +2601,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.FROM, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionMemberGroupListItems); }); @@ -2621,6 +2630,7 @@ describe('SearchUIUtils', () => { cardFeeds: mockCardFeeds, cardList: cardListMock, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionCardGroupListItems); }); @@ -2637,6 +2647,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionWithdrawalIDGroupListItems); }); @@ -2662,6 +2673,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionWithdrawalIDGroupListItemType[], number]; expect(result).toHaveLength(0); @@ -2679,6 +2691,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionCategoryGroupListItems); }); @@ -2710,6 +2723,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionCategoryGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -2771,6 +2785,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MONTH, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionMonthGroupListItems); }); @@ -2804,6 +2819,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MONTH, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionMonthGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -2822,6 +2838,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MONTH, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionMonthGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -2898,6 +2915,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.YEAR, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionYearGroupListItems); }); @@ -2929,6 +2947,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.YEAR, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionYearGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -2947,6 +2966,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.YEAR, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionYearGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -3316,6 +3336,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.QUARTER, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionQuarterGroupListItems); }); @@ -3349,6 +3370,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.QUARTER, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionQuarterGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -3367,6 +3389,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.QUARTER, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionQuarterGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -3425,6 +3448,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.WEEK, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionWeekGroupListItems); }); @@ -3456,6 +3480,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.WEEK, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionWeekGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -3510,6 +3535,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionCategoryGroupListItemType[], number]; // Each category section should have a transactionsQueryJSON with a hash @@ -3553,6 +3579,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionCategoryGroupListItemType[], number]; expect(result).toHaveLength(3); @@ -3594,6 +3621,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionCategoryGroupListItemType[], number]; expect(result).toHaveLength(3); @@ -3624,6 +3652,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionCategoryGroupListItemType[], number]; expect(result).toHaveLength(1); @@ -3659,6 +3688,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionCategoryGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -3683,6 +3713,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MERCHANT, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionMerchantGroupListItems); }); @@ -3715,6 +3746,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MERCHANT, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -3761,6 +3793,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(1); @@ -3809,6 +3842,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(1); @@ -3857,6 +3891,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(1); @@ -3905,6 +3940,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(1); @@ -3972,6 +4008,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; // Each merchant section should have a transactionsQueryJSON with a hash @@ -4016,6 +4053,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MERCHANT, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(3); @@ -4058,6 +4096,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.MERCHANT, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionMerchantGroupListItemType[], number]; expect(result).toHaveLength(3); @@ -4079,6 +4118,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.TAG, allReportMetadata: {}, + conciergeReportID: undefined, })[0], ).toStrictEqual(transactionTagGroupListItems); }); @@ -4106,6 +4146,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.TAG, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionTagGroupListItemType[], number]; // formattedTag should have unescaped colons for display @@ -4141,6 +4182,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.TAG, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionTagGroupListItemType[], number]; expect(result).toHaveLength(2); @@ -4169,6 +4211,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.TAG, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionTagGroupListItemType[], number]; expect(result).toHaveLength(1); @@ -4233,6 +4276,7 @@ describe('SearchUIUtils', () => { right: CONST.SEARCH.DATA_TYPES.EXPENSE, }, }, + conciergeReportID: undefined, }) as [TransactionTagGroupListItemType[], number]; // Each tag section should have a transactionsQueryJSON with a hash @@ -4242,6 +4286,315 @@ describe('SearchUIUtils', () => { expect(typeof item.transactionsQueryJSON?.hash).toBe('number'); } }); + + it('should return getTaskSections result when type is TASK', () => { + const taskReportID = 'task_report_100'; + const parentReportID = 'parent_report_200'; + const taskCreatorAccountID = 11111; + const taskAssigneeAccountID = 22222; + + const taskReport = { + type: CONST.REPORT.TYPE.TASK, + reportID: taskReportID, + reportName: 'Fix the login bug', + description: 'The login page has a bug that needs fixing', + accountID: taskCreatorAccountID, + managerID: taskAssigneeAccountID, + parentReportID, + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + created: '2025-01-15 10:00:00', + } as const; + + const taskData: OnyxTypes.SearchResults['data'] = { + personalDetailsList: { + [taskCreatorAccountID]: { + accountID: taskCreatorAccountID, + avatar: '', + displayName: 'Task Creator', + login: 'creator@test.com', + }, + [taskAssigneeAccountID]: { + accountID: taskAssigneeAccountID, + avatar: '', + displayName: 'Task Assignee', + login: 'assignee@test.com', + }, + }, + [`report_${taskReportID}`]: taskReport, + }; + + const [result, count] = SearchUIUtils.getSections({ + type: CONST.SEARCH.DATA_TYPES.TASK, + data: taskData, + currentAccountID: taskCreatorAccountID, + currentUserEmail: 'creator@test.com', + translate: translateLocal, + formatPhoneNumber, + bankAccountList: {}, + allReportMetadata: {}, + conciergeReportID: '999', + }) as [TaskListItemType[], number]; + + expect(result).toHaveLength(1); + expect(count).toBe(1); + expect(result.at(0)?.reportName).toBe('Fix the login bug'); + // formatPhoneNumber replaces regular spaces with non-breaking spaces (\u00A0) + expect(result.at(0)?.formattedAssignee).toBe('Task\u00A0Assignee'); + expect(result.at(0)?.formattedCreatedBy).toBe('Task\u00A0Creator'); + expect(result.at(0)?.keyForList).toBe(taskReportID); + }); + + it('should return empty task sections when no task reports exist in data', () => { + const nonTaskData: OnyxTypes.SearchResults['data'] = { + personalDetailsList: {}, + }; + + const [result, count] = SearchUIUtils.getSections({ + type: CONST.SEARCH.DATA_TYPES.TASK, + data: nonTaskData, + currentAccountID: 1, + currentUserEmail: 'test@test.com', + translate: translateLocal, + formatPhoneNumber, + bankAccountList: {}, + allReportMetadata: {}, + conciergeReportID: '999', + }) as [TaskListItemType[], number]; + + expect(result).toHaveLength(0); + expect(count).toBe(0); + }); + + it('should handle multiple tasks in getSections with TASK type', () => { + const taskReportID1 = 'task_report_301'; + const taskReportID2 = 'task_report_302'; + const creatorID = 33333; + const assigneeID = 44444; + + const taskReportA = { + type: CONST.REPORT.TYPE.TASK, + reportID: taskReportID1, + reportName: 'First task', + description: 'First task description', + accountID: creatorID, + managerID: assigneeID, + parentReportID: 'parent_1', + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + created: '2025-01-10 10:00:00', + } as const; + + const taskReportB = { + type: CONST.REPORT.TYPE.TASK, + reportID: taskReportID2, + reportName: 'Second task', + description: 'Second task description', + accountID: assigneeID, + managerID: creatorID, + parentReportID: 'parent_2', + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + created: '2025-01-11 10:00:00', + } as const; + + const multiTaskData: OnyxTypes.SearchResults['data'] = { + personalDetailsList: { + [creatorID]: { + accountID: creatorID, + avatar: '', + displayName: 'Creator User', + login: 'creator@test.com', + }, + [assigneeID]: { + accountID: assigneeID, + avatar: '', + displayName: 'Assignee User', + login: 'assignee@test.com', + }, + }, + [`report_${taskReportID1}`]: taskReportA, + [`report_${taskReportID2}`]: taskReportB, + }; + + const [result, count] = SearchUIUtils.getSections({ + type: CONST.SEARCH.DATA_TYPES.TASK, + data: multiTaskData, + currentAccountID: creatorID, + currentUserEmail: 'creator@test.com', + translate: translateLocal, + formatPhoneNumber, + bankAccountList: {}, + allReportMetadata: {}, + conciergeReportID: '999', + }) as [TaskListItemType[], number]; + + expect(result).toHaveLength(2); + expect(count).toBe(2); + expect(result.some((item) => item.reportName === 'First task')).toBe(true); + expect(result.some((item) => item.reportName === 'Second task')).toBe(true); + }); + + it('should pass conciergeReportID through to getTaskSections and strip HTML from task names', () => { + const taskReportID = 'task_report_400'; + const creatorID = 55555; + const assigneeID = 66666; + + const htmlTaskReport = { + type: CONST.REPORT.TYPE.TASK, + reportID: taskReportID, + reportName: 'Bold task name', + description: 'Italic description', + accountID: creatorID, + managerID: assigneeID, + parentReportID: 'parent_html', + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + created: '2025-01-20 10:00:00', + } as const; + + const taskDataWithHTML: OnyxTypes.SearchResults['data'] = { + personalDetailsList: { + [creatorID]: { + accountID: creatorID, + avatar: '', + displayName: 'HTML Creator', + login: 'creator@test.com', + }, + [assigneeID]: { + accountID: assigneeID, + avatar: '', + displayName: 'HTML Assignee', + login: 'assignee@test.com', + }, + }, + [`report_${taskReportID}`]: htmlTaskReport, + }; + + const [result] = SearchUIUtils.getSections({ + type: CONST.SEARCH.DATA_TYPES.TASK, + data: taskDataWithHTML, + currentAccountID: creatorID, + currentUserEmail: 'creator@test.com', + translate: translateLocal, + formatPhoneNumber, + bankAccountList: {}, + allReportMetadata: {}, + conciergeReportID: '999', + }) as [TaskListItemType[], number]; + + expect(result).toHaveLength(1); + // HTML should be stripped from reportName and description + expect(result.at(0)?.reportName).toBe('Bold task name'); + expect(result.at(0)?.description).toBe('Italic description'); + }); + + it('should filter out non-task reports when type is TASK', () => { + const taskReportID = 'task_report_500'; + const nonTaskReportID = 'non_task_report_501'; + const creatorID = 77777; + + const realTaskReport = { + type: CONST.REPORT.TYPE.TASK, + reportID: taskReportID, + reportName: 'A real task', + description: 'This is a task', + accountID: creatorID, + managerID: creatorID, + parentReportID: 'parent_mixed', + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + created: '2025-01-25 10:00:00', + } as const; + + const mixedData: OnyxTypes.SearchResults['data'] = { + personalDetailsList: { + [creatorID]: { + accountID: creatorID, + avatar: '', + displayName: 'Mixed Creator', + login: 'creator@test.com', + }, + }, + [`report_${taskReportID}`]: realTaskReport, + [`report_${nonTaskReportID}`]: { + type: CONST.REPORT.TYPE.CHAT, + reportID: nonTaskReportID, + reportName: 'Not a task', + }, + }; + + const [result, count] = SearchUIUtils.getSections({ + type: CONST.SEARCH.DATA_TYPES.TASK, + data: mixedData, + currentAccountID: creatorID, + currentUserEmail: 'creator@test.com', + translate: translateLocal, + formatPhoneNumber, + bankAccountList: {}, + allReportMetadata: {}, + conciergeReportID: '999', + }) as [TaskListItemType[], number]; + + // Only the task report should be included + expect(result).toHaveLength(1); + expect(count).toBe(1); + expect(result.at(0)?.reportName).toBe('A real task'); + }); + + it('should handle task with conciergeReportID as undefined', () => { + const taskReportID = 'task_report_600'; + const creatorID = 88888; + const assigneeID = 99999; + + const noConciergeTaskReport = { + type: CONST.REPORT.TYPE.TASK, + reportID: taskReportID, + reportName: 'Task without concierge', + description: 'No concierge here', + accountID: creatorID, + managerID: assigneeID, + parentReportID: 'parent_no_concierge', + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + created: '2025-02-01 10:00:00', + } as const; + + const taskData: OnyxTypes.SearchResults['data'] = { + personalDetailsList: { + [creatorID]: { + accountID: creatorID, + avatar: '', + displayName: 'Creator', + login: 'creator@test.com', + }, + [assigneeID]: { + accountID: assigneeID, + avatar: '', + displayName: 'Assignee', + login: 'assignee@test.com', + }, + }, + [`report_${taskReportID}`]: noConciergeTaskReport, + }; + + // conciergeReportID is undefined, simulating the case where it hasn't been loaded from Onyx yet + const [result, count] = SearchUIUtils.getSections({ + type: CONST.SEARCH.DATA_TYPES.TASK, + data: taskData, + currentAccountID: creatorID, + currentUserEmail: 'creator@test.com', + translate: translateLocal, + formatPhoneNumber, + bankAccountList: {}, + allReportMetadata: {}, + conciergeReportID: undefined, + }) as [TaskListItemType[], number]; + + expect(result).toHaveLength(1); + expect(count).toBe(1); + expect(result.at(0)?.reportName).toBe('Task without concierge'); + }); }); describe('Test getSortedSections', () => { @@ -4682,6 +5035,7 @@ describe('SearchUIUtils', () => { bankAccountList: {}, groupBy: CONST.SEARCH.GROUP_BY.TAG, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionTagGroupListItemType[], number]; // Then sort the sections From 35d57f717880a6287420d99a1ff9bc56a66b082a Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 19 Mar 2026 10:25:05 +0700 Subject: [PATCH 2/2] update test --- tests/unit/Search/SearchUIUtilsTest.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index 984e332de1edf..944d1c60a9fea 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -2611,6 +2611,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionReportGroupListItemType[], number]; expect(resultWithoutOnyx.at(0)?.primaryAvatar?.source).not.toBe(customAvatarUrl); @@ -2625,6 +2626,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, onyxPersonalDetailsList, }) as [TransactionReportGroupListItemType[], number]; @@ -2664,6 +2666,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, onyxPersonalDetailsList, }) as [TransactionReportGroupListItemType[], number]; @@ -2706,6 +2709,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionReportGroupListItemType[], number]; const reportWithoutOnyx = resultWithoutOnyx.find((item) => item.reportID === reportID2); @@ -2720,6 +2724,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, onyxPersonalDetailsList, }) as [TransactionReportGroupListItemType[], number]; @@ -2753,6 +2758,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, }) as [TransactionReportGroupListItemType[], number]; const reportGroupWithoutOnyx = resultWithoutOnyx.find((item) => item.reportID === reportID); @@ -2768,6 +2774,7 @@ describe('SearchUIUtils', () => { formatPhoneNumber, bankAccountList: {}, allReportMetadata: {}, + conciergeReportID: undefined, onyxPersonalDetailsList, }) as [TransactionReportGroupListItemType[], number]; @@ -2807,6 +2814,7 @@ describe('SearchUIUtils', () => { translate: translateLocal, formatPhoneNumber, bankAccountList: {}, + conciergeReportID: undefined, allReportMetadata: {}, onyxPersonalDetailsList, }) as [TransactionReportGroupListItemType[], number];