From ca95a62b423ee43a02b976f585b310189ce7a6b0 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 14 Aug 2025 13:16:19 +0700 Subject: [PATCH 1/5] fix: remove call to getReportNameValuePairs() in method getParentNavigationSubtitle --- src/components/AvatarWithDisplayName.tsx | 4 +++- src/libs/ReportUtils.ts | 6 ++---- src/pages/ReportDetailsPage.tsx | 2 +- src/pages/ShareCodePage.tsx | 6 ++++-- src/pages/home/HeaderView.tsx | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index c3eb57f10989..1566da321c66 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -5,6 +5,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useReportIsArchived from '@hooks/useReportIsArchived'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -169,7 +170,8 @@ function AvatarWithDisplayName({ const parentReportActionParam = report?.parentReportActionID ? parentReportActions?.[report.parentReportActionID] : undefined; const title = getReportName(report, undefined, parentReportActionParam, personalDetails, invoiceReceiverPolicy, reportAttributes); const subtitle = getChatRoomSubtitle(report, {isCreateExpenseFlow: true}); - const parentNavigationSubtitleData = getParentNavigationSubtitle(report); + const isReportArchived = useReportIsArchived(report?.reportID); + const parentNavigationSubtitleData = getParentNavigationSubtitle(report, isReportArchived); const isMoneyRequestOrReport = isMoneyRequestReport(report) || isMoneyRequest(report) || isTrackExpenseReport(report) || isInvoiceReport(report); const ownerPersonalDetails = getPersonalDetailsForAccountIDs(report?.ownerAccountID ? [report.ownerAccountID] : [], personalDetails); const displayNamesWithTooltips = getDisplayNamesWithTooltips(Object.values(ownerPersonalDetails), false, localeCompare); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b0ea02db04a0..248fdb90f971 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5496,7 +5496,7 @@ function getPendingChatMembers(accountIDs: number[], previousPendingChatMembers: /** * Gets the parent navigation subtitle for the report */ -function getParentNavigationSubtitle(report: OnyxEntry): ParentNavigationSummaryParams { +function getParentNavigationSubtitle(report: OnyxEntry, isReportArchived = false): ParentNavigationSummaryParams { const parentReport = getParentReport(report); if (isEmptyObject(parentReport)) { const ownerAccountID = report?.ownerAccountID; @@ -5520,9 +5520,7 @@ function getParentNavigationSubtitle(report: OnyxEntry): ParentNavigatio if (isInvoiceReport(report) || isInvoiceRoom(parentReport)) { let reportName = `${getPolicyName({report: parentReport})} & ${getInvoicePayerName(parentReport)}`; - // This will get removed as part of https://github.com/Expensify/App/issues/59961 - // eslint-disable-next-line deprecation/deprecation - if (isArchivedNonExpenseReport(parentReport, !!getReportNameValuePairs(parentReport?.reportID)?.private_isArchived)) { + if (isArchivedNonExpenseReport(parentReport, isReportArchived)) { reportName += ` (${translateLocal('common.archived')})`; } diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index e22e313fd2eb..e175cf41a6d5 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -198,7 +198,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const isReportArchived = useReportIsArchived(report?.reportID); const isArchivedRoom = useMemo(() => isArchivedNonExpenseReport(report, isReportArchived), [report, isReportArchived]); const shouldDisableRename = useMemo(() => shouldDisableRenameUtil(report, isReportArchived), [report, isReportArchived]); - const parentNavigationSubtitleData = getParentNavigationSubtitle(report); + const parentNavigationSubtitleData = getParentNavigationSubtitle(report, isReportArchived); const base62ReportID = getBase62ReportID(Number(report.reportID)); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx const chatRoomSubtitle = useMemo(() => { diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 5e226db9e7bd..244deaa11347 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -15,6 +15,7 @@ import ScrollView from '@components/ScrollView'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; +import useReportIsArchived from '@hooks/useReportIsArchived'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import Clipboard from '@libs/Clipboard'; @@ -75,6 +76,7 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const isReport = !!report?.reportID; + const isReportArchived = useReportIsArchived(report?.reportID); const subtitle = useMemo(() => { if (isReport) { @@ -88,11 +90,11 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) { .join(' & '); } - return getParentNavigationSubtitle(report).workspaceName ?? getChatRoomSubtitle(report); + return getParentNavigationSubtitle(report, isReportArchived).workspaceName ?? getChatRoomSubtitle(report); } return currentUserPersonalDetails.login; - }, [report, currentUserPersonalDetails, isReport]); + }, [isReport, currentUserPersonalDetails.login, report, isReportArchived]); const title = isReport ? getReportName(report) : (currentUserPersonalDetails.displayName ?? ''); const urlWithTrailingSlash = addTrailingForwardSlash(environmentURL); diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 8673a71f515a..fc8a8c35dcf2 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -133,7 +133,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, // Use sorted display names for the title for group chats on native small screen widths const title = getReportName(reportHeaderData, policy, parentReportAction, personalDetails, invoiceReceiverPolicy); const subtitle = getChatRoomSubtitle(reportHeaderData); - const parentNavigationSubtitleData = getParentNavigationSubtitle(reportHeaderData); + const parentNavigationSubtitleData = getParentNavigationSubtitle(reportHeaderData, isReportArchived); const reportDescription = Parser.htmlToText(getReportDescription(report)); const policyName = getPolicyName({report, returnEmptyIfNotFound: true}); const policyDescription = getPolicyDescriptionText(policy); From be1de282146eaa460c6fb24c0baf9e0c7cae2c71 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 18 Aug 2025 13:32:52 +0700 Subject: [PATCH 2/5] fix: use report header data to get is archived --- src/pages/home/HeaderView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index fc8a8c35dcf2..e3089352dcb3 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -26,6 +26,7 @@ import useLoadingBarVisibility from '@hooks/useLoadingBarVisibility'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; +import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSubscriptionPlan from '@hooks/useSubscriptionPlan'; import useTheme from '@hooks/useTheme'; @@ -133,7 +134,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, // Use sorted display names for the title for group chats on native small screen widths const title = getReportName(reportHeaderData, policy, parentReportAction, personalDetails, invoiceReceiverPolicy); const subtitle = getChatRoomSubtitle(reportHeaderData); - const parentNavigationSubtitleData = getParentNavigationSubtitle(reportHeaderData, isReportArchived); + const parentNavigationSubtitleData = getParentNavigationSubtitle(reportHeaderData, useReportIsArchived(reportHeaderData?.reportID)); const reportDescription = Parser.htmlToText(getReportDescription(report)); const policyName = getPolicyName({report, returnEmptyIfNotFound: true}); const policyDescription = getPolicyDescriptionText(policy); From 8d2a04fed16470c766ec4e78a94eb9505f9b47f5 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 18 Aug 2025 14:28:45 +0700 Subject: [PATCH 3/5] add unit test for getParentNavigationSubtitle --- tests/unit/ReportUtilsTest.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index dc2fa175ac2e..4cf1b91efc1f 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -43,6 +43,7 @@ import { getInvoiceChatByParticipants, getMoneyReportPreviewName, getMostRecentlyVisitedReport, + getParentNavigationSubtitle, getParticipantsList, getPolicyExpenseChat, getReasonAndReportActionThatRequiresAttention, @@ -920,6 +921,40 @@ describe('ReportUtils', () => { }); }); + describe('getParentNavigationSubtitle', () => { + const baseArchivedPolicyExpenseChat = { + reportID: '2', + lastReadTime: '2024-02-01 04:56:47.233', + parentReportActionID: '1', + parentReportID: '1', + reportName: 'Base Report', + type: CONST.REPORT.TYPE.INVOICE, + }; + + const reports: Report[] = [ + { + reportID: '1', + lastReadTime: '2024-02-01 04:56:47.233', + reportName: 'Report', + policyName: 'A workspace', + invoiceReceiver: {type: CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL, accountID: 1}, + }, + baseArchivedPolicyExpenseChat, + ]; + + beforeAll(() => { + const reportCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.REPORT, reports, (report) => report.reportID); + Onyx.multiSet({ + ...reportCollectionDataSet, + }); + return waitForBatchedUpdates(); + }); + + it('should return the correct parent navigation subtitle for the archived invoice report', () => { + expect(getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, true)).toEqual({reportName: 'A workspace & Ragnar Lothbrok (archived)'}); + }); + }); + describe('requiresAttentionFromCurrentUser', () => { afterEach(async () => { await Onyx.clear(); From a921d86e4112a6290f808775f025d4a64c9f2dbb Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 18 Aug 2025 16:54:20 +0700 Subject: [PATCH 4/5] add new variable --- src/pages/home/HeaderView.tsx | 3 ++- tests/unit/ReportUtilsTest.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index e3089352dcb3..8a09d940897f 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -134,7 +134,8 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, // Use sorted display names for the title for group chats on native small screen widths const title = getReportName(reportHeaderData, policy, parentReportAction, personalDetails, invoiceReceiverPolicy); const subtitle = getChatRoomSubtitle(reportHeaderData); - const parentNavigationSubtitleData = getParentNavigationSubtitle(reportHeaderData, useReportIsArchived(reportHeaderData?.reportID)); + const isReportHeaderDataArchived = useReportIsArchived(reportHeaderData?.reportID); + const parentNavigationSubtitleData = getParentNavigationSubtitle(reportHeaderData, isReportHeaderDataArchived); const reportDescription = Parser.htmlToText(getReportDescription(report)); const policyName = getPolicyName({report, returnEmptyIfNotFound: true}); const policyDescription = getPolicyDescriptionText(policy); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 4cf1b91efc1f..131463bd1f27 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -951,7 +951,9 @@ describe('ReportUtils', () => { }); it('should return the correct parent navigation subtitle for the archived invoice report', () => { - expect(getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, true)).toEqual({reportName: 'A workspace & Ragnar Lothbrok (archived)'}); + const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, true); + const normalizedActual = {...actual, reportName: actual.reportName?.replace(/\u00A0/g, ' ')}; + expect(normalizedActual).toEqual({reportName: 'A workspace & Ragnar Lothbrok (archived)'}); }); }); From ca29359f692ae0d04067f36c2ab6b2a56bca91ba Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 20 Aug 2025 00:13:22 +0700 Subject: [PATCH 5/5] add new test case --- tests/unit/ReportUtilsTest.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 131463bd1f27..91ae1964855c 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -955,6 +955,12 @@ describe('ReportUtils', () => { const normalizedActual = {...actual, reportName: actual.reportName?.replace(/\u00A0/g, ' ')}; expect(normalizedActual).toEqual({reportName: 'A workspace & Ragnar Lothbrok (archived)'}); }); + + it('should return the correct parent navigation subtitle for the non archived invoice report', () => { + const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, false); + const normalizedActual = {...actual, reportName: actual.reportName?.replace(/\u00A0/g, ' ')}; + expect(normalizedActual).toEqual({reportName: 'A workspace & Ragnar Lothbrok'}); + }); }); describe('requiresAttentionFromCurrentUser', () => {