From 657344212606b24843dd051b72043f3ca83a99e8 Mon Sep 17 00:00:00 2001 From: suhailpthaj Date: Wed, 7 Jan 2026 15:55:07 +0530 Subject: [PATCH 1/3] fix: Invoice report title in message preview shows an incorrect report title --- src/pages/ReportDetailsPage.tsx | 6 ++++-- src/pages/RoomMembersPage.tsx | 8 ++++++-- src/pages/ShareCodePage.tsx | 11 ++++++++++- src/pages/home/HeaderView.tsx | 13 ++++++++++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 2cd9b591b64b..bcae1a49f674 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -338,8 +338,10 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const shouldShowLeaveButton = canLeaveChat(report, policy, !!reportNameValuePairs?.private_isArchived); const shouldShowGoToWorkspace = shouldShowPolicy(policy, false, currentUserPersonalDetails?.email) && !policy?.isJoinRequestPending; - - const reportName = isGroupChat ? getReportNameFromReportNameUtils(report, reportAttributes) : Parser.htmlToText(getReportNameFromReportNameUtils(report, reportAttributes)); + // Calculating the report title with parent report if parent report is invoice and current report is chat thread. + const isParentInvoiceAndIsChatThread = useMemo(() => isChatThread && isInvoiceReportUtil(parentReport), [isChatThread, parentReport]); + const reportForHeader = isParentInvoiceAndIsChatThread ? parentReport : report; + const reportName = isGroupChat ? getReportNameFromReportNameUtils(reportForHeader, reportAttributes) : Parser.htmlToText(getReportNameFromReportNameUtils(reportForHeader, reportAttributes)); const additionalRoomDetails = (isPolicyExpenseChat && !!report?.isOwnPolicyExpenseChat) || isExpenseReportUtil(report) || isPolicyExpenseChat || isInvoiceRoom ? chatRoomSubtitle diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index e6871ddcb7eb..1a64f77eb916 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -36,7 +36,7 @@ import type {RoomMembersNavigatorParamList} from '@libs/Navigation/types'; import {isPersonalDetailsReady, isSearchStringMatchUserDetails} from '@libs/OptionsListUtils'; import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import {isPolicyEmployee as isPolicyEmployeeUtils, isUserPolicyAdmin} from '@libs/PolicyUtils'; -import {getReportName, getReportPersonalDetailsParticipants, isChatThread, isDefaultRoom, isPolicyExpenseChat as isPolicyExpenseChatUtils, isUserCreatedPolicyRoom} from '@libs/ReportUtils'; +import {getReportName, getReportPersonalDetailsParticipants, isChatThread, isDefaultRoom, isPolicyExpenseChat as isPolicyExpenseChatUtils, isUserCreatedPolicyRoom, isInvoiceReport} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import {clearAddRoomMemberError, openRoomMembersPage, removeFromRoom} from '@userActions/Report'; import CONST from '@src/CONST'; @@ -67,6 +67,10 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { const isPolicyExpenseChat = useMemo(() => isPolicyExpenseChatUtils(report), [report]); const backTo = route.params.backTo; const isReportArchived = useReportIsArchived(report.reportID); + const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`, {canBeMissing: true}); + // Calculating the report title with parent report if parent report is invoice and current report is chat thread. + const isParentInvoiceAndIsChatThread = useMemo(() => isChatThread(report) && isInvoiceReport(parentReport), [report, parentReport]); + const reportForSubtitle = isParentInvoiceAndIsChatThread ? parentReport : report; const {chatParticipants: participants, personalDetailsParticipants} = useMemo( () => getReportPersonalDetailsParticipants(report, personalDetails, reportMetadata, true), @@ -405,7 +409,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { { if (isMobileSelectionModeEnabled) { setSelectedMembers([]); diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index f415b2ec3491..c1d36bafea5c 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -33,6 +33,8 @@ import { getReportName, isExpenseReport, isMoneyRequestReport, + isChatThread, + isInvoiceReport, } from '@libs/ReportUtils'; import shouldAllowDownloadQRCode from '@libs/shouldAllowDownloadQRCode'; import addTrailingForwardSlash from '@libs/UrlUtils'; @@ -40,6 +42,8 @@ import {getAvatarURL} from '@libs/UserAvatarUtils'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Policy, Report} from '@src/types/onyx'; +import {useOnyx} from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; type ShareCodePageOnyxProps = { /** The report currently being looked at */ @@ -99,8 +103,13 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) { return currentUserPersonalDetails.login; }, [report, currentUserPersonalDetails.login, isReport, isReportArchived, isParentReportArchived, formatPhoneNumber]); + const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`, {canBeMissing: true}); + // Calculating the report title with parent report if parent report is invoice and current report is chat thread. + const isParentInvoiceAndIsChatThread = useMemo(() => isChatThread(report) && isInvoiceReport(parentReport), [report, parentReport]); + const reportForTitle = isParentInvoiceAndIsChatThread ? parentReport : report; + // eslint-disable-next-line @typescript-eslint/no-deprecated - const title = isReport ? getReportName(report) : (currentUserPersonalDetails.displayName ?? ''); + const title = isReport ? getReportName(reportForTitle) : (currentUserPersonalDetails.displayName ?? ''); const urlWithTrailingSlash = addTrailingForwardSlash(environmentURL); const url = isReport ? `${urlWithTrailingSlash}${ROUTES.REPORT_WITH_ID.getRoute(report.reportID)}` diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 1ff2b57ea9a7..9b7f93ec0c2a 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -70,6 +70,9 @@ import { navigateToDetailsPage, shouldDisableDetailPage as shouldDisableDetailPageReportUtils, shouldReportShowSubscript, + getReportStatusColorStyle, + getReportStatusTranslation, + isInvoiceReport, } from '@libs/ReportUtils'; import {shouldShowDiscountBanner} from '@libs/SubscriptionUtils'; import EarlyDiscountBanner from '@pages/settings/Subscription/CardSection/BillingBanner/EarlyDiscountBanner'; @@ -145,7 +148,9 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, const isChatRoom = isChatRoomReportUtils(report); const isPolicyExpenseChat = isPolicyExpenseChatReportUtils(report); const isTaskReport = isTaskReportReportUtils(report); - const reportHeaderData = !isTaskReport && !isChatThread && report?.parentReportID ? parentReport : report; + // This is used to check if the report is a chat thread and has a parent invoice report. + const isParentInvoiceAndIsChatThread = isChatThread && !!parentReport && isInvoiceReport(parentReport); + const reportHeaderData = (!isTaskReport && !isChatThread && report?.parentReportID) || isParentInvoiceAndIsChatThread ? parentReport : report; const isParentOneTransactionThread = isOneTransactionThread(parentReport, grandParentReport, grandParentReportActions?.[`${parentReport?.parentReportActionID}`]); const parentNavigationReport = isParentOneTransactionThread ? parentReport : reportHeaderData; const isReportHeaderDataArchived = useReportIsArchived(reportHeaderData?.reportID); @@ -153,6 +158,9 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, // eslint-disable-next-line @typescript-eslint/no-deprecated const title = getReportName(reportHeaderData, policy, parentReportAction, personalDetails, invoiceReceiverPolicy, undefined, undefined, isReportHeaderDataArchived); const subtitle = getChatRoomSubtitle(reportHeaderData, false, isReportHeaderDataArchived); + // This is used to get the status badge for invoice report subtitle. + const statusTextForInvoiceReport = isParentInvoiceAndIsChatThread ? getReportStatusTranslation({stateNum: reportHeaderData?.stateNum, statusNum: reportHeaderData?.statusNum, translate}) : undefined; + const statusColorForInvoiceReport = isParentInvoiceAndIsChatThread ? getReportStatusColorStyle(theme, reportHeaderData?.stateNum, reportHeaderData?.statusNum) : {}; const isParentReportHeaderDataArchived = useReportIsArchived(reportHeaderData?.parentReportID); const parentNavigationSubtitleData = getParentNavigationSubtitle(parentNavigationReport, isParentReportHeaderDataArchived); const reportDescription = Parser.htmlToText(getReportDescription(report)); @@ -323,6 +331,9 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, {!isEmptyObject(parentNavigationSubtitleData) && ( Date: Sun, 11 Jan 2026 14:07:01 +0530 Subject: [PATCH 2/3] Added a utility to get the report to display title --- src/libs/ReportUtils.ts | 12 ++++++++++++ src/pages/ReportDetailsPage.tsx | 5 ++--- src/pages/RoomMembersPage.tsx | 7 ++----- src/pages/ShareCodePage.tsx | 10 ++-------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2d9dc2abe992..8d10e24afac9 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1327,6 +1327,17 @@ function getParentReport(report: OnyxEntry): OnyxEntry { return getReport(report.parentReportID, allReports); } +/** + * Returns the appropriate report to use for display. + * For invoice chat threads, returns the parent invoice report. + * For other cases, returns the provided report. + */ +function getReportForDisplay(report: OnyxEntry): OnyxEntry { + const parentReport = getParentReport(report); + const isParentInvoiceAndIsChatThread = isChatThread(report) && isInvoiceReport(parentReport); + return isParentInvoiceAndIsChatThread ? parentReport : report; +} + /** * Returns the root parentReport if the given report is nested. * Uses recursion to iterate any depth of nested reports. @@ -13214,6 +13225,7 @@ export { isOneTransactionReport, isTrackExpenseReportNew, shouldHideSingleReportField, + getReportForDisplay, }; export type { diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index a3c326eb6c22..1ecad5314a53 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -102,6 +102,7 @@ import { navigateToPrivateNotes, shouldDisableRename as shouldDisableRenameUtil, shouldUseFullTitleToDisplay, + getReportForDisplay, } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import {isDemoTransaction} from '@libs/TransactionUtils'; @@ -345,9 +346,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const shouldShowLeaveButton = canLeaveChat(report, policy, !!reportNameValuePairs?.private_isArchived); const shouldShowGoToWorkspace = shouldShowPolicy(policy, false, currentUserPersonalDetails?.email) && !policy?.isJoinRequestPending; - // Calculating the report title with parent report if parent report is invoice and current report is chat thread. - const isParentInvoiceAndIsChatThread = useMemo(() => isChatThread && isInvoiceReportUtil(parentReport), [isChatThread, parentReport]); - const reportForHeader = isParentInvoiceAndIsChatThread ? parentReport : report; + const reportForHeader = useMemo(() => getReportForDisplay(report), [report]); const reportName = isGroupChat ? getReportNameFromReportNameUtils(reportForHeader, reportAttributes) : Parser.htmlToText(getReportNameFromReportNameUtils(reportForHeader, reportAttributes)); const additionalRoomDetails = (isPolicyExpenseChat && !!report?.isOwnPolicyExpenseChat) || isExpenseReportUtil(report) || isPolicyExpenseChat || isInvoiceRoom diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index a1a7603cbf24..f9796e3eedaa 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -37,7 +37,7 @@ import Parser from '@libs/Parser'; import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; import {isPolicyEmployee as isPolicyEmployeeUtils, isUserPolicyAdmin} from '@libs/PolicyUtils'; import {getReportAction} from '@libs/ReportActionsUtils'; -import {getReportName, getReportPersonalDetailsParticipants, isChatThread, isDefaultRoom, isPolicyExpenseChat as isPolicyExpenseChatUtils, isUserCreatedPolicyRoom, isInvoiceReport} from '@libs/ReportUtils'; +import {getReportName, getReportPersonalDetailsParticipants, isChatThread, isDefaultRoom, isPolicyExpenseChat as isPolicyExpenseChatUtils, isUserCreatedPolicyRoom, getReportForDisplay} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import {clearAddRoomMemberError, openRoomMembersPage, removeFromRoom} from '@userActions/Report'; import CONST from '@src/CONST'; @@ -70,10 +70,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { const isPolicyExpenseChat = useMemo(() => isPolicyExpenseChatUtils(report), [report]); const backTo = route.params.backTo; const isReportArchived = useReportIsArchived(report.reportID); - const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`, {canBeMissing: true}); - // Calculating the report title with parent report if parent report is invoice and current report is chat thread. - const isParentInvoiceAndIsChatThread = useMemo(() => isChatThread(report) && isInvoiceReport(parentReport), [report, parentReport]); - const reportForSubtitle = isParentInvoiceAndIsChatThread ? parentReport : report; + const reportForSubtitle = useMemo(() => getReportForDisplay(report), [report]); const {chatParticipants: participants, personalDetailsParticipants} = useMemo( () => getReportPersonalDetailsParticipants(report, personalDetails, reportMetadata, true), diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index c1d36bafea5c..0abd4fc2915c 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -33,8 +33,7 @@ import { getReportName, isExpenseReport, isMoneyRequestReport, - isChatThread, - isInvoiceReport, + getReportForDisplay, } from '@libs/ReportUtils'; import shouldAllowDownloadQRCode from '@libs/shouldAllowDownloadQRCode'; import addTrailingForwardSlash from '@libs/UrlUtils'; @@ -42,8 +41,6 @@ import {getAvatarURL} from '@libs/UserAvatarUtils'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Policy, Report} from '@src/types/onyx'; -import {useOnyx} from 'react-native-onyx'; -import ONYXKEYS from '@src/ONYXKEYS'; type ShareCodePageOnyxProps = { /** The report currently being looked at */ @@ -103,10 +100,7 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) { return currentUserPersonalDetails.login; }, [report, currentUserPersonalDetails.login, isReport, isReportArchived, isParentReportArchived, formatPhoneNumber]); - const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`, {canBeMissing: true}); - // Calculating the report title with parent report if parent report is invoice and current report is chat thread. - const isParentInvoiceAndIsChatThread = useMemo(() => isChatThread(report) && isInvoiceReport(parentReport), [report, parentReport]); - const reportForTitle = isParentInvoiceAndIsChatThread ? parentReport : report; + const reportForTitle = useMemo(() => getReportForDisplay(report), [report]); // eslint-disable-next-line @typescript-eslint/no-deprecated const title = isReport ? getReportName(reportForTitle) : (currentUserPersonalDetails.displayName ?? ''); From 8b29ced566d32769aaf7fd1c2a3d4a8d7b5b9073 Mon Sep 17 00:00:00 2001 From: suhailpthaj Date: Wed, 14 Jan 2026 00:03:38 +0530 Subject: [PATCH 3/3] replace report with reportForSubtitle in RoomMembersPage --- src/pages/RoomMembersPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index b34318ef3125..af60aeed3ca2 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -414,7 +414,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { { if (isMobileSelectionModeEnabled) { setSelectedMembers([]);