diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 3f5b2f9cdbd1..7a5fe8f7cb74 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1322,6 +1322,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 getReportForHeader(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. @@ -13325,6 +13336,7 @@ export { isOneTransactionReport, isTrackExpenseReportNew, shouldHideSingleReportField, + getReportForHeader, }; export type { diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 04d396c6e24c..963a0b3bd19e 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -70,6 +70,7 @@ import { getParticipantsList, getReportDescription, getReportFieldKey, + getReportForHeader, isAdminOwnerApproverOrReportOwner, isArchivedNonExpenseReport, isCanceledTaskReport as isCanceledTaskReportUtil, @@ -342,8 +343,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)); + const reportForHeader = useMemo(() => getReportForHeader(report), [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 39218a0d7874..ab569650ae08 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -38,7 +38,15 @@ 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} from '@libs/ReportUtils'; +import { + getReportForHeader, + getReportName, + getReportPersonalDetailsParticipants, + isChatThread, + isDefaultRoom, + isPolicyExpenseChat as isPolicyExpenseChatUtils, + isUserCreatedPolicyRoom, +} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import {clearAddRoomMemberError, openRoomMembersPage, removeFromRoom} from '@userActions/Report'; import CONST from '@src/CONST'; @@ -71,6 +79,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { const isPolicyExpenseChat = useMemo(() => isPolicyExpenseChatUtils(report), [report]); const backTo = route.params.backTo; const isReportArchived = useReportIsArchived(report.reportID); + const reportForSubtitle = useMemo(() => getReportForHeader(report), [report]); const {chatParticipants: participants, personalDetailsParticipants} = useMemo( () => getReportPersonalDetailsParticipants(report, personalDetails, reportMetadata, true), @@ -417,7 +426,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) { { if (isMobileSelectionModeEnabled) { setSelectedMembers([]); diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index f415b2ec3491..86e18454748a 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -30,6 +30,7 @@ import { getParentNavigationSubtitle, getParticipantsAccountIDsForDisplay, getPolicyName, + getReportForHeader, getReportName, isExpenseReport, isMoneyRequestReport, @@ -99,8 +100,10 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) { return currentUserPersonalDetails.login; }, [report, currentUserPersonalDetails.login, isReport, isReportArchived, isParentReportArchived, formatPhoneNumber]); + const reportForTitle = useMemo(() => getReportForHeader(report), [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 699d249accd4..22b7934d13a2 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -48,6 +48,8 @@ import { getPolicyName, getReportDescription, getReportName, + getReportStatusColorStyle, + getReportStatusTranslation, hasReportNameError, isAdminRoom, isArchivedReport, @@ -59,6 +61,7 @@ import { isDeprecatedGroupDM, isExpenseRequest, isGroupChat as isGroupChatReportUtils, + isInvoiceReport, isInvoiceRoom, isOneTransactionThread, isOpenTaskReport, @@ -139,7 +142,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); @@ -148,6 +153,11 @@ 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)); @@ -320,6 +330,9 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, {!isEmptyObject(parentNavigationSubtitleData) && (