From 3bb114b80887b6da5ef4d85d767f5eb6b3cae9a8 Mon Sep 17 00:00:00 2001
From: Qichen Zhu <57348009+QichenZhu@users.noreply.github.com>
Date: Thu, 20 Nov 2025 01:25:35 +1300
Subject: [PATCH] Revert #74928
---
src/components/DisplayNames/index.native.tsx | 9 +-
src/components/DisplayNames/index.tsx | 5 +-
src/components/DisplayNames/types.ts | 3 -
src/libs/ReportUtils.ts | 2 +-
src/pages/ReportDetailsPage.tsx | 9 +-
.../unit/DisplayNamesShouldParseHTMLTest.tsx | 113 ------------------
tests/unit/ReportUtilsTest.ts | 27 -----
7 files changed, 9 insertions(+), 159 deletions(-)
delete mode 100644 tests/unit/DisplayNamesShouldParseHTMLTest.tsx
diff --git a/src/components/DisplayNames/index.native.tsx b/src/components/DisplayNames/index.native.tsx
index ab0e659cdb6f..cae91c80272e 100644
--- a/src/components/DisplayNames/index.native.tsx
+++ b/src/components/DisplayNames/index.native.tsx
@@ -8,11 +8,8 @@ import TextWithEmojiFragment from '@pages/home/report/comment/TextWithEmojiFragm
import type DisplayNamesProps from './types';
// As we don't have to show tooltips of the Native platform so we simply render the full display names list.
-function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1, renderAdditionalText, forwardedFSClass, testID, shouldParseHtml = false}: DisplayNamesProps) {
+function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1, renderAdditionalText, forwardedFSClass, testID}: DisplayNamesProps) {
const {translate} = useLocalize();
- const title = shouldParseHtml
- ? StringUtils.lineBreaksToSpaces(Parser.htmlToText(fullTitle)) || translate('common.hidden')
- : StringUtils.lineBreaksToSpaces(fullTitle) || translate('common.hidden');
const titleContainsTextAndCustomEmoji = useMemo(() => containsCustomEmoji(fullTitle) && !containsOnlyCustomEmoji(fullTitle), [fullTitle]);
return (
{titleContainsTextAndCustomEmoji ? (
) : (
- title
+ StringUtils.lineBreaksToSpaces(Parser.htmlToText(fullTitle)) || translate('common.hidden')
)}
{renderAdditionalText?.()}
diff --git a/src/components/DisplayNames/index.tsx b/src/components/DisplayNames/index.tsx
index 5e1a82104501..5158747e4c25 100644
--- a/src/components/DisplayNames/index.tsx
+++ b/src/components/DisplayNames/index.tsx
@@ -16,12 +16,9 @@ function DisplayNames({
displayNamesWithTooltips,
renderAdditionalText,
forwardedFSClass,
- shouldParseHtml = false,
}: DisplayNamesProps) {
const {translate} = useLocalize();
- const title = shouldParseHtml
- ? StringUtils.lineBreaksToSpaces(Parser.htmlToText(fullTitle)) || translate('common.hidden')
- : StringUtils.lineBreaksToSpaces(fullTitle) || translate('common.hidden');
+ const title = StringUtils.lineBreaksToSpaces(Parser.htmlToText(fullTitle)) || translate('common.hidden');
if (!tooltipEnabled) {
return (
diff --git a/src/components/DisplayNames/types.ts b/src/components/DisplayNames/types.ts
index a1c3e1d4960b..1b9a69510da3 100644
--- a/src/components/DisplayNames/types.ts
+++ b/src/components/DisplayNames/types.ts
@@ -49,9 +49,6 @@ type DisplayNamesProps = ForwardedFSClassProps & {
/** TestID indicating order */
testID?: number;
-
- /** Whether to parse HTML in the fullTitle */
- shouldParseHtml?: boolean;
};
export default DisplayNamesProps;
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 37b9a27dc267..0b1712e3a07a 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5682,7 +5682,7 @@ function getReportName(
}
if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION)) {
- return Parser.htmlToText(getUnreportedTransactionMessage());
+ return getUnreportedTransactionMessage();
}
if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT_NO_RECEIPT)) {
diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx
index 3900c1deeb18..8b645d1ace3b 100644
--- a/src/pages/ReportDetailsPage.tsx
+++ b/src/pages/ReportDetailsPage.tsx
@@ -10,6 +10,7 @@ import ConfirmModal from '@components/ConfirmModal';
import DisplayNames from '@components/DisplayNames';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import MentionReportContext from '@components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext';
+import * as Expensicons from '@components/Icon/Expensicons';
import MenuItem from '@components/MenuItem';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
@@ -26,7 +27,6 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useDeleteTransactions from '@hooks/useDeleteTransactions';
import useDuplicateTransactionsAndViolations from '@hooks/useDuplicateTransactionsAndViolations';
import useGetIOUReportFromReportAction from '@hooks/useGetIOUReportFromReportAction';
-import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
@@ -41,6 +41,7 @@ import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types';
import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils';
+import Parser from '@libs/Parser';
import Permissions from '@libs/Permissions';
import {isPolicyAdmin as isPolicyAdminUtil, isPolicyEmployee as isPolicyEmployeeUtil, shouldShowPolicy} from '@libs/PolicyUtils';
import {getOneTransactionThreadReportID, getOriginalMessage, getTrackExpenseActionableWhisper, isDeletedAction, isMoneyRequestAction, isTrackExpenseAction} from '@libs/ReportActionsUtils';
@@ -148,7 +149,6 @@ const CASES = {
type CaseID = ValueOf;
function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetailsPageProps) {
- const Expensicons = useMemoizedLazyExpensifyIcons(['Bug', 'Building', 'Camera', 'Checkmark', 'Exit', 'Folder', 'Gear', 'Pencil', 'Send', 'Trashcan', 'UserPlus', 'Users'] as const);
const {translate, localeCompare} = useLocalize();
const {isOffline} = useNetwork();
const {isRestrictedToPreferredPolicy, preferredPolicyID} = usePreferredPolicy();
@@ -332,7 +332,8 @@ 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 = getReportName(report, undefined, undefined, undefined, undefined, reportAttributes);
+
+ const reportName = Parser.htmlToText(getReportName(report, undefined, undefined, undefined, undefined, reportAttributes));
const additionalRoomDetails =
(isPolicyExpenseChat && !!report?.isOwnPolicyExpenseChat) || isExpenseReportUtil(report) || isPolicyExpenseChat || isInvoiceRoom
@@ -577,7 +578,6 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail
isRestrictedToPreferredPolicy,
preferredPolicyID,
introSelected,
- Expensicons,
]);
const displayNamesWithTooltips = useMemo(() => {
@@ -660,7 +660,6 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail
policy,
participants,
moneyRequestReport?.reportID,
- Expensicons,
]);
const canJoin = canJoinChat(report, parentReportAction, policy, !!reportNameValuePairs?.private_isArchived);
diff --git a/tests/unit/DisplayNamesShouldParseHTMLTest.tsx b/tests/unit/DisplayNamesShouldParseHTMLTest.tsx
deleted file mode 100644
index 95c99a3ce4c2..000000000000
--- a/tests/unit/DisplayNamesShouldParseHTMLTest.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import {render, screen} from '@testing-library/react-native';
-import React from 'react';
-import DisplayNames from '@components/DisplayNames';
-
-jest.mock('@hooks/useLocalize', () => ({
- // eslint-disable-next-line @typescript-eslint/naming-convention
- __esModule: true,
- default: () => ({
- translate: jest.fn((key: string): string => {
- if (key === 'common.hidden') {
- return 'hidden';
- }
- return key;
- }),
- }),
-}));
-
-jest.mock('@libs/Parser', () => ({
- // eslint-disable-next-line @typescript-eslint/naming-convention
- __esModule: true,
- default: {
- htmlToText: jest.fn((html: string) => {
- // Simulate stripTag behavior: remove anything that looks like HTML tags
- return html.replaceAll(/(<([^>]+)>)/gi, '');
- }),
- },
-}));
-
-jest.mock('@libs/StringUtils', () => ({
- // eslint-disable-next-line @typescript-eslint/naming-convention
- __esModule: true,
- default: {
- lineBreaksToSpaces: jest.fn((text: string) => text),
- },
-}));
-
-describe('DisplayNames - shouldParseHtml prop', () => {
- const testTitle = '< >';
-
- afterEach(() => {
- jest.clearAllMocks();
- });
-
- it('should NOT parse HTML by default (shouldParseHtml defaults to false)', () => {
- render(
- ,
- );
-
- // With shouldParseHtml = false (default), "< >" should be preserved
- expect(screen.getByText('< >')).toBeTruthy();
- });
-
- it('should parse HTML when shouldParseHtml is explicitly set to true', () => {
- const htmlTitle = 'Bold Text';
- render(
- ,
- );
-
- // With shouldParseHtml = true, HTML tags should be stripped
- expect(screen.getByText('Bold Text')).toBeTruthy();
- expect(screen.queryByText('Bold Text')).toBeNull();
- });
-
- it('should preserve special characters when shouldParseHtml is false', () => {
- const specialCharsTitle = '< > & " \' test';
- render(
- ,
- );
-
- // Special characters should be preserved when not parsing HTML
- expect(screen.getByText(specialCharsTitle)).toBeTruthy();
- });
-
- it('should show "hidden" when title is empty and HTML parsing is disabled', () => {
- render(
- ,
- );
-
- expect(screen.getByText('hidden')).toBeTruthy();
- });
-
- it('should show "hidden" when title becomes empty after HTML parsing', () => {
- const onlyTagsTitle = '';
- render(
- ,
- );
-
- // After parsing, only tags remain which get stripped to empty string
- expect(screen.getByText('hidden')).toBeTruthy();
- });
-});
diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts
index 1acf4cc5fbc4..82607086fef6 100644
--- a/tests/unit/ReportUtilsTest.ts
+++ b/tests/unit/ReportUtilsTest.ts
@@ -1125,33 +1125,6 @@ describe('ReportUtils', () => {
);
});
});
-
- describe('Unreported transaction thread', () => {
- test('HTML is stripped from unreported transaction message', () => {
- const transactionThread = {
- ...LHNTestUtils.getFakeReport(),
- type: CONST.REPORT.TYPE.CHAT,
- reportID: '123',
- parentReportID: '456',
- };
-
- const unreportedTransactionAction = {
- actionName: CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION,
- originalMessage: {
- fromReportID: '789',
- },
- } as ReportAction;
-
- const reportName = getReportName(transactionThread, undefined, unreportedTransactionAction);
-
- // Should NOT contain HTML tags
- expect(reportName).not.toContain('');
- // Should contain the text content
- expect(reportName).toContain('moved this expense');
- expect(reportName).toContain('personal space');
- });
- });
});
// Need to merge the same tests