Skip to content

Commit 38548f5

Browse files
authored
Merge pull request Expensify#85421 from dukenv0307/fix/66411-part-10
refactor parseReportActionHtmlToText and getParentNavigationSubtitle to use conciergeReportID from useOnyx
2 parents d1f626f + 934dc89 commit 38548f5

9 files changed

Lines changed: 112 additions & 16 deletions

File tree

src/components/AvatarWithDisplayName.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ function AvatarWithDisplayName({
186186
const {localeCompare, formatPhoneNumber} = useLocalize();
187187
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.parentReportID}`, {canEvict: false});
188188
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST) ?? CONST.EMPTY_OBJECT;
189+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
189190
const theme = useTheme();
190191
const styles = useThemeStyles();
191192
const StyleUtils = useStyleUtils();
@@ -199,7 +200,7 @@ function AvatarWithDisplayName({
199200
const title = getReportName(report, reportAttributes);
200201
const isParentReportArchived = useReportIsArchived(report?.parentReportID);
201202
const subtitle = getChatRoomSubtitle(report, true, isReportArchived);
202-
const parentNavigationSubtitleData = getParentNavigationSubtitle(report, isParentReportArchived, reportAttributes);
203+
const parentNavigationSubtitleData = getParentNavigationSubtitle(report, conciergeReportID, isParentReportArchived, reportAttributes);
203204
const isMoneyRequestOrReport = isMoneyRequestReport(report) || isMoneyRequest(report) || isTrackExpenseReport(report) || isInvoiceReport(report);
204205
const ownerPersonalDetails = getPersonalDetailsForAccountIDs(report?.ownerAccountID ? [report.ownerAccountID] : [], personalDetails);
205206
const displayNamesWithTooltips = getDisplayNamesWithTooltips(Object.values(ownerPersonalDetails), false, localeCompare, formatPhoneNumber);

src/components/SelectionListWithSections/Search/ExpenseReportListItemRow.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {SearchColumnType} from '@components/Search/types';
99
import type {ExpenseReportListItemType} from '@components/SelectionListWithSections/types';
1010
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
1111
import useLocalize from '@hooks/useLocalize';
12+
import useOnyx from '@hooks/useOnyx';
1213
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1314
import useStyleUtils from '@hooks/useStyleUtils';
1415
import useTheme from '@hooks/useTheme';
@@ -19,6 +20,7 @@ import {getParentNavigationSubtitle, getReportStatusTranslation} from '@libs/Rep
1920
import {isCorrectSearchUserName} from '@libs/SearchUIUtils';
2021
import variables from '@styles/variables';
2122
import CONST from '@src/CONST';
23+
import ONYXKEYS from '@src/ONYXKEYS';
2224
import type {ReportAction} from '@src/types/onyx';
2325
import ActionCell from './ActionCell';
2426
import DateCell from './DateCell';
@@ -67,6 +69,7 @@ function ExpenseReportListItemRow({
6769
const styles = useThemeStyles();
6870
const theme = useTheme();
6971
const {translate} = useLocalize();
72+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
7073
const {isLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
7174
const expensifyIcons = useMemoizedLazyExpensifyIcons(['ArrowRight']);
7275

@@ -232,7 +235,7 @@ function ExpenseReportListItemRow({
232235
const isInMobileSelectionMode = shouldUseNarrowLayout && !!canSelectMultiple;
233236

234237
// Compute accessible group label (user name, subtitle, report title, status, amount)
235-
const parentNavigationSubtitleData = getParentNavigationSubtitle(item);
238+
const parentNavigationSubtitleData = getParentNavigationSubtitle(item, conciergeReportID);
236239
const subtitleLabel = translate('threads.parentNavigationSummary', parentNavigationSubtitleData);
237240
const statusLabel = getReportStatusTranslation({stateNum: item.stateNum, statusNum: item.statusNum, translate});
238241
const amountLabel = convertToDisplayString(totalDisplaySpend, currency);

src/libs/ReportUtils.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5677,7 +5677,7 @@ function getAdminRoomInvitedParticipants(translate: LocalizedTranslate, parentRe
56775677
/**
56785678
* Parse html of reportAction into text
56795679
*/
5680-
function parseReportActionHtmlToText(reportAction: OnyxEntry<ReportAction>, reportID: string | undefined, childReportID?: string): string {
5680+
function parseReportActionHtmlToText(reportAction: OnyxEntry<ReportAction>, reportID: string | undefined, conciergeReportID: string | undefined, childReportID?: string): string {
56815681
if (!reportAction) {
56825682
return '';
56835683
}
@@ -5701,7 +5701,7 @@ function parseReportActionHtmlToText(reportAction: OnyxEntry<ReportAction>, repo
57015701
if (match[1] !== childReportID) {
57025702
// This will be fixed as follow up https://github.com/Expensify/App/pull/75357
57035703
// eslint-disable-next-line @typescript-eslint/no-use-before-define, @typescript-eslint/no-deprecated
5704-
reportIDToName[match[1]] = getReportName({report: getReportOrDraftReport(match[1])}) ?? '';
5704+
reportIDToName[match[1]] = getReportName({report: getReportOrDraftReport(match[1]), conciergeReportID}) ?? '';
57055705
}
57065706
}
57075707

@@ -5733,6 +5733,7 @@ function getReportActionMessage({
57335733
childReportID,
57345734
reports,
57355735
personalDetails,
5736+
conciergeReportID,
57365737
}: {
57375738
reportAction: OnyxEntry<ReportAction>;
57385739
translate: LocalizedTranslate;
@@ -5741,6 +5742,7 @@ function getReportActionMessage({
57415742
childReportID?: string;
57425743
reports?: Report[];
57435744
personalDetails?: Partial<PersonalDetailsList>;
5745+
conciergeReportID: string | undefined;
57445746
}) {
57455747
if (isEmptyObject(reportAction)) {
57465748
return '';
@@ -5786,7 +5788,7 @@ function getReportActionMessage({
57865788
return getReimbursementDeQueuedOrCanceledActionMessage(translate, reportAction, getReportOrDraftReport(reportID, reports));
57875789
}
57885790

5789-
return parseReportActionHtmlToText(reportAction, reportID, childReportID);
5791+
return parseReportActionHtmlToText(reportAction, reportID, conciergeReportID, childReportID);
57905792
}
57915793

57925794
/**
@@ -5880,6 +5882,7 @@ function getReportName(reportNameInformation: GetReportNameParams): string {
58805882
childReportID: report?.reportID,
58815883
reports,
58825884
personalDetails,
5885+
conciergeReportID,
58835886
}).replaceAll(/(\n+|\r\n|\n|\r)/gm, ' ');
58845887
if (isAttachment && reportActionMessage) {
58855888
// eslint-disable-next-line @typescript-eslint/no-deprecated
@@ -6148,7 +6151,12 @@ function getPendingChatMembers(accountIDs: number[], previousPendingChatMembers:
61486151
/**
61496152
* Gets the parent navigation subtitle for the report
61506153
*/
6151-
function getParentNavigationSubtitle(report: OnyxEntry<Report>, isParentReportArchived = false, reportAttributes?: ReportAttributesDerivedValue['reports']): ParentNavigationSummaryParams {
6154+
function getParentNavigationSubtitle(
6155+
report: OnyxEntry<Report>,
6156+
conciergeReportID: string | undefined,
6157+
isParentReportArchived = false,
6158+
reportAttributes?: ReportAttributesDerivedValue['reports'],
6159+
): ParentNavigationSummaryParams {
61526160
const parentReport = getParentReport(report);
61536161

61546162
if (isEmptyObject(parentReport)) {
@@ -6187,7 +6195,7 @@ function getParentNavigationSubtitle(report: OnyxEntry<Report>, isParentReportAr
61876195
return {
61886196
// This will be fixed as follow up https://github.com/Expensify/App/pull/75357
61896197
// eslint-disable-next-line @typescript-eslint/no-deprecated
6190-
reportName: getReportName({report: parentReport, reportAttributes}),
6198+
reportName: getReportName({report: parentReport, reportAttributes, conciergeReportID}),
61916199
workspaceName: getPolicyName({report: parentReport, returnEmptyIfNotFound: true}),
61926200
};
61936201
}

src/libs/actions/Task.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,7 @@ function getShareDestination(
10681068
reports: OnyxCollection<OnyxTypes.Report>,
10691069
personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>,
10701070
localeCompare: LocaleContextProps['localeCompare'],
1071+
conciergeReportID: string | undefined,
10711072
): ShareDestination {
10721073
const report = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
10731074

@@ -1097,7 +1098,7 @@ function getShareDestination(
10971098
icons: ReportUtils.getIcons(report, LocalePhoneNumber.formatPhoneNumber, personalDetails, Expensicons.FallbackAvatar),
10981099
// Will be fixed in https://github.com/Expensify/App/issues/76852
10991100
// eslint-disable-next-line @typescript-eslint/no-deprecated
1100-
displayName: ReportUtils.getReportName({report}),
1101+
displayName: ReportUtils.getReportName({report, conciergeReportID}),
11011102
subtitle,
11021103
displayNamesWithTooltips,
11031104
shouldUseFullTitleToDisplay: ReportUtils.shouldUseFullTitleToDisplay(report),

src/pages/ReportDetailsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail
223223
const isReportArchived = useReportIsArchived(report?.reportID);
224224
const isArchivedRoom = useMemo(() => isArchivedNonExpenseReport(report, isReportArchived), [report, isReportArchived]);
225225
const shouldDisableRename = useMemo(() => shouldDisableRenameUtil(report, isReportArchived), [report, isReportArchived]);
226-
const parentNavigationSubtitleData = getParentNavigationSubtitle(report, isParentReportArchived);
226+
const parentNavigationSubtitleData = getParentNavigationSubtitle(report, conciergeReportID, isParentReportArchived);
227227
const base62ReportID = getBase62ReportID(Number(report.reportID));
228228
const ancestors = useAncestors(report);
229229
// eslint-disable-next-line 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

src/pages/ShareCodePage.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
1515
import useEnvironment from '@hooks/useEnvironment';
1616
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
1717
import useLocalize from '@hooks/useLocalize';
18+
import useOnyx from '@hooks/useOnyx';
1819
import useReportAttributes from '@hooks/useReportAttributes';
1920
import useReportIsArchived from '@hooks/useReportIsArchived';
2021
import useStyleUtils from '@hooks/useStyleUtils';
@@ -38,6 +39,7 @@ import shouldAllowDownloadQRCode from '@libs/shouldAllowDownloadQRCode';
3839
import addTrailingForwardSlash from '@libs/UrlUtils';
3940
import {getAvatarURL} from '@libs/UserAvatarUtils';
4041
import CONST from '@src/CONST';
42+
import ONYXKEYS from '@src/ONYXKEYS';
4143
import ROUTES from '@src/ROUTES';
4244
import type {Policy, Report} from '@src/types/onyx';
4345

@@ -77,6 +79,7 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) {
7779
const qrCodeRef = useRef<QRShareWithDownloadHandle>(null);
7880

7981
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
82+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
8083
const reportAttributes = useReportAttributes();
8184
const isParentReportArchived = useReportIsArchived(report?.parentReportID);
8285
const isReportArchived = useReportIsArchived(report?.reportID);
@@ -94,11 +97,11 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) {
9497
.join(' & ');
9598
}
9699

97-
return getParentNavigationSubtitle(report, isParentReportArchived).workspaceName ?? getChatRoomSubtitle(report, false, isReportArchived);
100+
return getParentNavigationSubtitle(report, conciergeReportID, isParentReportArchived).workspaceName ?? getChatRoomSubtitle(report, false, isReportArchived);
98101
}
99102

100103
return currentUserPersonalDetails.login;
101-
}, [report, currentUserPersonalDetails.login, isReport, isReportArchived, isParentReportArchived, formatPhoneNumber]);
104+
}, [report, currentUserPersonalDetails.login, isReport, isReportArchived, isParentReportArchived, formatPhoneNumber, conciergeReportID]);
102105

103106
const reportForTitle = useMemo(() => getReportForHeader(report), [report]);
104107

src/pages/inbox/HeaderView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
123123
const isReportArchived = isArchivedReport(reportNameValuePairs);
124124
const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {selector: reportsSelector});
125125
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
126+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
126127

127128
const {translate, localeCompare, formatPhoneNumber} = useLocalize();
128129
const theme = useTheme();
@@ -159,7 +160,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
159160
: undefined;
160161
const statusColorForInvoiceReport = isParentInvoiceAndIsChatThread ? getReportStatusColorStyle(theme, reportHeaderData?.stateNum, reportHeaderData?.statusNum) : {};
161162
const isParentReportHeaderDataArchived = useReportIsArchived(reportHeaderData?.parentReportID);
162-
const parentNavigationSubtitleData = getParentNavigationSubtitle(parentNavigationReport, isParentReportHeaderDataArchived);
163+
const parentNavigationSubtitleData = getParentNavigationSubtitle(parentNavigationReport, conciergeReportID, isParentReportHeaderDataArchived);
163164
const reportDescription = Parser.htmlToText(getReportDescription(report));
164165
const policyName = getPolicyName({report, returnEmptyIfNotFound: true});
165166
const policyDescription = getPolicyDescriptionText(policy);
@@ -242,7 +243,6 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
242243
const isReportInRHP = route.name === SCREENS.RIGHT_MODAL.SEARCH_REPORT;
243244
const shouldDisplaySearchRouter = !isInSidePanel && (!isReportInRHP || isSmallScreenWidth);
244245
const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED);
245-
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
246246
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboarding, conciergeReportID, onboardingPurposeSelected);
247247
const shouldShowRegisterForWebinar =
248248
introSelected?.companySize === CONST.ONBOARDING_COMPANY_SIZE.MICRO && (isChatUsedForOnboarding || (isAdminRoom(report) && !isChatThread)) && !isInSidePanel;

src/pages/tasks/NewTaskPage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ function NewTaskPage({route}: NewTaskPageProps) {
3535
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
3636
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
3737
const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE);
38+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
3839
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
3940
const styles = useThemeStyles();
4041
const {translate, formatPhoneNumber, localeCompare} = useLocalize();
@@ -45,7 +46,7 @@ function NewTaskPage({route}: NewTaskPageProps) {
4546
localeCompare,
4647
formatPhoneNumber,
4748
);
48-
const shareDestination = task?.shareDestination ? getShareDestination(task.shareDestination, reports, personalDetails, localeCompare) : undefined;
49+
const shareDestination = task?.shareDestination ? getShareDestination(task.shareDestination, reports, personalDetails, localeCompare, conciergeReportID) : undefined;
4950
const parentReport = task?.shareDestination ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${task.shareDestination}`] : undefined;
5051
const ancestors = useAncestors(parentReport);
5152
const taskKey = `${task?.assignee}|${task?.assigneeAccountID}|${task?.description}|${task?.parentReportID}|${task?.shareDestination}|${task?.title}`;

tests/unit/ReportUtilsTest.ts

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ import {
115115
isRootGroupChat,
116116
isSelfDMOrSelfDMThread,
117117
isWorkspaceMemberLeavingWorkspaceRoom,
118+
parseReportActionHtmlToText,
118119
parseReportRouteParams,
119120
prepareOnboardingOnyxData,
120121
pushTransactionViolationsOnyxData,
@@ -2820,16 +2821,94 @@ describe('ReportUtils', () => {
28202821
});
28212822

28222823
it('should return the correct parent navigation subtitle for the archived invoice report', () => {
2823-
const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, true);
2824+
const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, undefined, true);
28242825
const normalizedActual = {...actual, reportName: actual.reportName?.replaceAll('\u00A0', ' ')};
28252826
expect(normalizedActual).toEqual({reportName: 'A workspace & Ragnar Lothbrok (archived)'});
28262827
});
28272828

28282829
it('should return the correct parent navigation subtitle for the non archived invoice report', () => {
2829-
const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, false);
2830+
const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, undefined, false);
28302831
const normalizedActual = {...actual, reportName: actual.reportName?.replaceAll('\u00A0', ' ')};
28312832
expect(normalizedActual).toEqual({reportName: 'A workspace & Ragnar Lothbrok'});
28322833
});
2834+
2835+
it('should return empty object when report has no parent and is not expense or IOU', () => {
2836+
const chatReport: Report = {
2837+
reportID: '100',
2838+
lastReadTime: '2024-02-01 04:56:47.233',
2839+
reportName: 'Chat Report',
2840+
type: CONST.REPORT.TYPE.CHAT,
2841+
};
2842+
const actual = getParentNavigationSubtitle(chatReport, undefined);
2843+
expect(actual).toEqual({});
2844+
});
2845+
2846+
it('should pass conciergeReportID through to getReportName for parent report name resolution', () => {
2847+
const conciergeReportID = '999';
2848+
const conciergeParentReport: Report = {
2849+
reportID: conciergeReportID,
2850+
lastReadTime: '2024-02-01 04:56:47.233',
2851+
reportName: 'Concierge',
2852+
type: CONST.REPORT.TYPE.CHAT,
2853+
};
2854+
const childReport: Report = {
2855+
reportID: '1000',
2856+
lastReadTime: '2024-02-01 04:56:47.233',
2857+
parentReportID: conciergeReportID,
2858+
parentReportActionID: '1',
2859+
reportName: 'Child Thread',
2860+
type: CONST.REPORT.TYPE.CHAT,
2861+
};
2862+
2863+
const reportCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.REPORT, [conciergeParentReport, childReport], (report) => report.reportID);
2864+
return Onyx.multiSet({
2865+
...reportCollectionDataSet,
2866+
})
2867+
.then(waitForBatchedUpdates)
2868+
.then(() => {
2869+
const actual = getParentNavigationSubtitle(childReport, conciergeReportID);
2870+
expect(actual.reportName).toBe('Concierge');
2871+
});
2872+
});
2873+
2874+
it('should return reportName and workspaceName when parent report exists and conciergeReportID is undefined', () => {
2875+
const actual = getParentNavigationSubtitle(baseArchivedPolicyExpenseChat, undefined, false);
2876+
expect(actual).toHaveProperty('reportName');
2877+
});
2878+
});
2879+
2880+
describe('parseReportActionHtmlToText', () => {
2881+
it('should return empty string for undefined reportAction', () => {
2882+
const result = parseReportActionHtmlToText(undefined, '123', undefined);
2883+
expect(result).toBe('');
2884+
});
2885+
2886+
it('should return text from reportAction message when no html', () => {
2887+
const reportAction = {
2888+
...createRandomReportAction(1),
2889+
message: [{type: 'COMMENT', text: 'Hello world'}],
2890+
} as unknown as ReportAction;
2891+
const result = parseReportActionHtmlToText(reportAction, '123', undefined);
2892+
expect(result).toBe('Hello world');
2893+
});
2894+
2895+
it('should parse html to text with conciergeReportID', () => {
2896+
const reportAction = {
2897+
...createRandomReportAction(1),
2898+
message: [{type: 'COMMENT', html: '<p>Hello world</p>', text: 'Hello world'}],
2899+
} as unknown as ReportAction;
2900+
const result = parseReportActionHtmlToText(reportAction, '123', '999');
2901+
expect(result).toBe('Hello world');
2902+
});
2903+
2904+
it('should handle conciergeReportID being undefined', () => {
2905+
const reportAction = {
2906+
...createRandomReportAction(1),
2907+
message: [{type: 'COMMENT', html: '<p>Test message</p>', text: 'Test message'}],
2908+
} as unknown as ReportAction;
2909+
const result = parseReportActionHtmlToText(reportAction, '456', undefined);
2910+
expect(result).toBe('Test message');
2911+
});
28332912
});
28342913

28352914
describe('requiresAttentionFromCurrentUser', () => {

0 commit comments

Comments
 (0)