diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index ddb593f259abb..05123725c9af3 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 [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID, {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]); @@ -68,6 +69,7 @@ function OptionRowLHNData({ personalDetails, policy, parentReportAction, + conciergeReportID, lastMessageTextFromReport, invoiceReceiverPolicy, card, @@ -104,6 +106,7 @@ function OptionRowLHNData({ preferredLocale, policy, parentReportAction, + conciergeReportID, iouReportReportActions, transaction, receiptTransactions, diff --git a/src/hooks/useSidebarOrderedReports.tsx b/src/hooks/useSidebarOrderedReports.tsx index 02b7ff1fc9afd..64ccd2d1deb34 100644 --- a/src/hooks/useSidebarOrderedReports.tsx +++ b/src/hooks/useSidebarOrderedReports.tsx @@ -73,6 +73,7 @@ function SidebarOrderedReportsContextProvider({ const [reportNameValuePairs, {sourceValue: reportNameValuePairsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, {canBeMissing: true}); const [reportsDrafts, {sourceValue: reportsDraftsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true}); const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true}); + const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID, {canBeMissing: true}); const reportAttributes = useReportAttributes(); const [currentReportsToDisplay, setCurrentReportsToDisplay] = useState({}); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -230,10 +231,11 @@ function SidebarOrderedReportsContextProvider({ }, [reportsToDisplayInLHN]); const getOrderedReportIDs = useCallback( - () => SidebarUtils.sortReportsToDisplayInLHN(deepComparedReportsToDisplayInLHN ?? {}, priorityMode, localeCompare, deepComparedReportsDrafts, reportNameValuePairs), + () => + SidebarUtils.sortReportsToDisplayInLHN(deepComparedReportsToDisplayInLHN ?? {}, priorityMode, localeCompare, deepComparedReportsDrafts, reportNameValuePairs, conciergeReportID), // Rule disabled intentionally - reports should be sorted only when the reportsToDisplayInLHN changes // eslint-disable-next-line react-hooks/exhaustive-deps - [deepComparedReportsToDisplayInLHN, localeCompare, deepComparedReportsDrafts], + [deepComparedReportsToDisplayInLHN, localeCompare, deepComparedReportsDrafts, conciergeReportID], ); const orderedReportIDs = useMemo(() => getOrderedReportIDs(), [getOrderedReportIDs]); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0712d2280b1a6..11df176bfe2fa 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5750,6 +5750,7 @@ function getReportActionMessage({ * Get the title for a report. * @deprecated Moved to src/libs/ReportNameUtils.ts. */ +// eslint-disable-next-line @typescript-eslint/max-params function getReportName( report: OnyxEntry, policy?: OnyxEntry, @@ -5761,6 +5762,7 @@ function getReportName( isReportArchived?: boolean, reports?: Report[], policies?: Policy[], + conciergeReportID?: string, ): string { // Check if we can use report name in derived values - only when we have report but no other params const canUseDerivedValue = @@ -5935,7 +5937,7 @@ function getReportName( }); } - if (isConciergeChatReport(report)) { + if (isConciergeChatReport(report, conciergeReportID)) { formattedName = CONST.CONCIERGE_DISPLAY_NAME; } diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 01ed9720915a4..4a75fbc26f665 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -375,7 +375,12 @@ function updateReportsToDisplayInLHN({ /** * Categorizes reports into their respective LHN groups */ -function categorizeReportsForLHN(reportsToDisplay: ReportsToDisplayInLHN, reportsDrafts: OnyxCollection | undefined, reportNameValuePairs?: OnyxCollection) { +function categorizeReportsForLHN( + reportsToDisplay: ReportsToDisplayInLHN, + reportsDrafts: OnyxCollection | undefined, + conciergeReportID: string | undefined, + reportNameValuePairs?: OnyxCollection, +) { const pinnedAndGBRReports: MiniReport[] = []; const errorReports: MiniReport[] = []; const draftReports: MiniReport[] = []; @@ -401,7 +406,7 @@ function categorizeReportsForLHN(reportsToDisplay: ReportsToDisplayInLHN, report const reportID = report.reportID; // eslint-disable-next-line @typescript-eslint/no-deprecated - const displayName = getReportName(report); + const displayName = getReportName(report, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, conciergeReportID); const miniReport: MiniReport = { reportID, displayName, @@ -536,7 +541,8 @@ function sortReportsToDisplayInLHN( priorityMode: OnyxEntry, localeCompare: LocaleContextProps['localeCompare'], reportsDrafts: OnyxCollection | undefined, - reportNameValuePairs?: OnyxCollection, + reportNameValuePairs: OnyxCollection | undefined, + conciergeReportID: string | undefined, ): string[] { Performance.markStart(CONST.TIMING.GET_ORDERED_REPORT_IDS); @@ -554,7 +560,7 @@ function sortReportsToDisplayInLHN( // - Sorted by reportDisplayName in GSD (focus) view mode // Step 1: Categorize reports - const categories = categorizeReportsForLHN(reportsToDisplay, reportsDrafts, reportNameValuePairs); + const categories = categorizeReportsForLHN(reportsToDisplay, reportsDrafts, conciergeReportID, reportNameValuePairs); // Step 2: Sort each category const sortedCategories = sortCategorizedReports(categories, isInDefaultMode, localeCompare); @@ -660,6 +666,7 @@ function getOptionData({ personalDetails, policy, parentReportAction, + conciergeReportID, invoiceReceiverPolicy, lastMessageTextFromReport: lastMessageTextFromReportProp, card, @@ -679,6 +686,7 @@ function getOptionData({ personalDetails: OnyxEntry; policy: OnyxEntry; parentReportAction: OnyxEntry | undefined; + conciergeReportID: string | undefined; invoiceReceiverPolicy: OnyxEntry; lastMessageTextFromReport?: string; reportAttributes: OnyxEntry; @@ -778,7 +786,7 @@ function getOptionData({ result.tooltipText = getReportParticipantsTitle(visibleParticipantAccountIDs); result.hasOutstandingChildTask = report.hasOutstandingChildTask; result.hasParentAccess = report.hasParentAccess; - result.isConciergeChat = isConciergeChatReport(report); + result.isConciergeChat = isConciergeChatReport(report, conciergeReportID); result.participants = report.participants; const isExpense = isExpenseReport(report); @@ -1115,7 +1123,7 @@ function getOptionData({ } // eslint-disable-next-line @typescript-eslint/no-deprecated - const reportName = getReportName(report, policy, undefined, undefined, invoiceReceiverPolicy, undefined, undefined, isReportArchived); + const reportName = getReportName(report, policy, undefined, undefined, invoiceReceiverPolicy, undefined, undefined, isReportArchived, undefined, undefined, conciergeReportID); result.text = reportName; result.subtitle = subtitle; diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index 8f7ad66b9b441..9947b3bdcbbb5 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -84,6 +84,7 @@ describe('SidebarUtils', () => { policy, invoiceReceiverPolicy: undefined, parentReportAction, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, lastAction: undefined, diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 5e28dd1c7e6a8..8a54228003f28 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -1643,6 +1643,44 @@ describe('ReportUtils', () => { const reportName = computeReportName(conciergeReport); expect(reportName).toBe(CONST.CONCIERGE_DISPLAY_NAME); }); + + test('should return Concierge display name when explicit conciergeReportID matches report ID', () => { + const explicitConciergeReportID = 'explicit-concierge-456'; + const report: Report = { + reportID: explicitConciergeReportID, + participants: buildParticipantsFromAccountIDs([currentUserAccountID, CONST.ACCOUNT_ID.CONCIERGE]), + }; + + // eslint-disable-next-line @typescript-eslint/no-deprecated + const reportName = getReportNameDeprecated(report, policy, undefined, participantsPersonalDetails, undefined, undefined, [], false, [], [], explicitConciergeReportID); + expect(reportName).toBe(CONST.CONCIERGE_DISPLAY_NAME); + }); + + test('should not return Concierge display name when explicit conciergeReportID does not match report ID', () => { + const explicitConciergeReportID = 'explicit-concierge-456'; + const report: Report = { + reportID: 'different-report-789', + participants: buildParticipantsFromAccountIDs([currentUserAccountID, 1]), + }; + + // eslint-disable-next-line @typescript-eslint/no-deprecated + const reportName = getReportNameDeprecated(report, policy, undefined, participantsPersonalDetails, undefined, undefined, [], false, [], [], explicitConciergeReportID); + expect(reportName).not.toBe(CONST.CONCIERGE_DISPLAY_NAME); + // Should generate name from participants instead + expect(reportName).toBe('Ragnar Lothbrok'); + }); + + test('should use Onyx-connected conciergeReportID when explicit parameter is undefined', () => { + // conciergeReportID is already set in beforeAll to 'concierge-123' + const report: Report = { + reportID: conciergeReportID, + participants: buildParticipantsFromAccountIDs([currentUserAccountID, CONST.ACCOUNT_ID.CONCIERGE]), + }; + + // eslint-disable-next-line @typescript-eslint/no-deprecated + const reportName = getReportNameDeprecated(report, policy, undefined, participantsPersonalDetails); + expect(reportName).toBe(CONST.CONCIERGE_DISPLAY_NAME); + }); }); describe('Money Request', () => { diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index 04c9a03ffaa95..cf4f9a800a911 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -347,6 +347,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -365,6 +366,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -1332,6 +1334,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -1396,6 +1399,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -1463,6 +1467,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -1514,6 +1519,7 @@ describe('SidebarUtils', () => { policy, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', lastMessageTextFromReport: 'test message', oneTransactionThreadReport: undefined, card: undefined, @@ -1556,6 +1562,7 @@ describe('SidebarUtils', () => { policy, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', lastMessageTextFromReport: 'test message', oneTransactionThreadReport: undefined, card: undefined, @@ -1596,6 +1603,7 @@ describe('SidebarUtils', () => { policy, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', lastMessageTextFromReport: 'test message', oneTransactionThreadReport: undefined, card: undefined, @@ -1735,6 +1743,7 @@ describe('SidebarUtils', () => { policy, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, lastAction: undefined, @@ -1779,6 +1788,7 @@ describe('SidebarUtils', () => { policy, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', lastMessageTextFromReport: 'test message', oneTransactionThreadReport: undefined, card: undefined, @@ -1853,6 +1863,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -1915,6 +1926,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -1967,6 +1979,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -2046,6 +2059,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -2166,6 +2180,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -2253,6 +2268,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, translate: translateLocal, @@ -2352,6 +2368,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, lastAction: lastReportPreviewAction, @@ -2452,6 +2469,7 @@ describe('SidebarUtils', () => { policy: undefined, invoiceReceiverPolicy: undefined, parentReportAction: undefined, + conciergeReportID: '', oneTransactionThreadReport: undefined, card: undefined, lastAction: lastReportPreviewAction, @@ -2466,6 +2484,100 @@ describe('SidebarUtils', () => { expect(result?.alternateText).toBe(reportPreviewMessage); }); }); + + describe('conciergeReportID parameter', () => { + it('returns isConciergeChat as true when conciergeReportID matches the report reportID', () => { + // Given a report with a specific reportID + const MOCK_REPORT: OnyxEntry = { + reportID: '123456', + }; + const conciergeReportID = '123456'; + + // When getOptionData is called with matching conciergeReportID + const result = SidebarUtils.getOptionData({ + report: MOCK_REPORT, + reportAttributes: undefined, + reportNameValuePairs: {}, + personalDetails: {}, + policy: undefined, + parentReportAction: undefined, + conciergeReportID, + oneTransactionThreadReport: undefined, + card: undefined, + translate: translateLocal, + localeCompare, + lastAction: undefined, + lastActionReport: undefined, + invoiceReceiverPolicy: undefined, + isReportArchived: undefined, + currentUserAccountID: 0, + }); + + // Then isConciergeChat should be true + expect(result?.isConciergeChat).toBe(true); + }); + + it('returns isConciergeChat as false when conciergeReportID does not match the report reportID', () => { + // Given a report with a specific reportID + const MOCK_REPORT: OnyxEntry = { + reportID: '123456', + }; + const conciergeReportID = '999999'; + + // When getOptionData is called with non-matching conciergeReportID + const result = SidebarUtils.getOptionData({ + report: MOCK_REPORT, + reportAttributes: undefined, + reportNameValuePairs: {}, + personalDetails: {}, + policy: undefined, + parentReportAction: undefined, + conciergeReportID, + oneTransactionThreadReport: undefined, + card: undefined, + translate: translateLocal, + localeCompare, + lastAction: undefined, + lastActionReport: undefined, + invoiceReceiverPolicy: undefined, + isReportArchived: undefined, + currentUserAccountID: 0, + }); + + // Then isConciergeChat should be false + expect(result?.isConciergeChat).toBe(false); + }); + + it('returns isConciergeChat as false when conciergeReportID is empty string', () => { + // Given a report with a specific reportID + const MOCK_REPORT: OnyxEntry = { + reportID: '123456', + }; + + // When getOptionData is called with empty conciergeReportID + const result = SidebarUtils.getOptionData({ + report: MOCK_REPORT, + reportAttributes: undefined, + reportNameValuePairs: {}, + personalDetails: {}, + policy: undefined, + parentReportAction: undefined, + conciergeReportID: '', + oneTransactionThreadReport: undefined, + card: undefined, + translate: translateLocal, + localeCompare, + lastAction: undefined, + lastActionReport: undefined, + invoiceReceiverPolicy: undefined, + isReportArchived: undefined, + currentUserAccountID: 0, + }); + + // Then isConciergeChat should be false + expect(result?.isConciergeChat).toBe(false); + }); + }); }); describe('sortReportsToDisplayInLHN', () => { @@ -2479,7 +2591,7 @@ describe('SidebarUtils', () => { }; // When the reports are categorized - const result = SidebarUtils.categorizeReportsForLHN(reports, reportsDrafts, reportNameValuePairs); + const result = SidebarUtils.categorizeReportsForLHN(reports, reportsDrafts, '', reportNameValuePairs); // Then the reports are categorized into the correct groups expect(result.pinnedAndGBRReports).toHaveLength(1); @@ -2506,7 +2618,7 @@ describe('SidebarUtils', () => { ]); // When the reports are categorized - const result = SidebarUtils.categorizeReportsForLHN(reports, undefined, undefined); + const result = SidebarUtils.categorizeReportsForLHN(reports, undefined, '', undefined); // Then the reports are categorized into the correct groups expect(result.pinnedAndGBRReports).toHaveLength(1); @@ -2533,7 +2645,7 @@ describe('SidebarUtils', () => { }; // When the reports are categorized - const result = SidebarUtils.categorizeReportsForLHN(reports, {}); + const result = SidebarUtils.categorizeReportsForLHN(reports, {}, ''); // Then the reports are categorized into the correct groups expect(result.pinnedAndGBRReports).toHaveLength(0); @@ -2547,7 +2659,7 @@ describe('SidebarUtils', () => { it('should handle empty reports object', () => { // Given the reports are empty - const result = SidebarUtils.categorizeReportsForLHN({}, {}); + const result = SidebarUtils.categorizeReportsForLHN({}, {}, ''); // Then the reports are categorized into the correct groups expect(result.pinnedAndGBRReports).toHaveLength(0); @@ -2784,7 +2896,7 @@ describe('SidebarUtils', () => { const priorityMode = CONST.PRIORITY_MODE.DEFAULT; // When the reports are sorted - const result = SidebarUtils.sortReportsToDisplayInLHN(reports, priorityMode, mockLocaleCompare, undefined); + const result = SidebarUtils.sortReportsToDisplayInLHN(reports, priorityMode, mockLocaleCompare, undefined, undefined, ''); // Then the reports are sorted in the correct order expect(result).toEqual(['0', '1', '2']); // Pinned first, Error second, Normal third @@ -2810,10 +2922,10 @@ describe('SidebarUtils', () => { const mockLocaleCompare = (a: string, b: string) => a.localeCompare(b); // When the reports are sorted in default mode - const defaultResult = SidebarUtils.sortReportsToDisplayInLHN(reports, CONST.PRIORITY_MODE.DEFAULT, mockLocaleCompare, undefined); + const defaultResult = SidebarUtils.sortReportsToDisplayInLHN(reports, CONST.PRIORITY_MODE.DEFAULT, mockLocaleCompare, undefined, undefined, ''); // When the reports are sorted in GSD mode - const gsdResult = SidebarUtils.sortReportsToDisplayInLHN(reports, CONST.PRIORITY_MODE.GSD, mockLocaleCompare, undefined); + const gsdResult = SidebarUtils.sortReportsToDisplayInLHN(reports, CONST.PRIORITY_MODE.GSD, mockLocaleCompare, undefined, undefined, ''); // Then the reports are sorted in the correct order expect(defaultResult).toEqual(['1', '0']); // Most recent first (index 1 has later date) diff --git a/tests/unit/useSidebarOrderedReportsTest.tsx b/tests/unit/useSidebarOrderedReportsTest.tsx index 98c7004ca966f..ebf3bd91557b4 100644 --- a/tests/unit/useSidebarOrderedReportsTest.tsx +++ b/tests/unit/useSidebarOrderedReportsTest.tsx @@ -202,6 +202,7 @@ describe('useSidebarOrderedReports', () => { expect.any(Function), // localeCompare expect.any(Object), // reportsDrafts expect.any(Object), // reportNameValuePairs + undefined, // conciergeReportID - undefined when not set in Onyx ); });