Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 314 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5705,6 +5705,318 @@
return isArchivedNonExpense ? generateArchivedReportName(finalName) : finalName;
}

function computeReportName(
report: OnyxEntry<Report>,
policy?: OnyxEntry<Policy> | SearchPolicy,
parentReportActionParam?: OnyxInputOrEntry<ReportAction>,
personalDetails?: Partial<PersonalDetailsList>,
invoiceReceiverPolicy?: OnyxEntry<Policy> | SearchPolicy,
reportAttributes?: ReportAttributesDerivedValue['reports'],
transactions?: SearchTransaction[],
isReportArchived?: boolean,
reports?: SearchReport[],
policies?: SearchPolicy[],
): string {
// Check if we can use report name in derived values - only when we have report but no other params
const canUseDerivedValue =
report && policy === undefined && parentReportActionParam === undefined && personalDetails === undefined && invoiceReceiverPolicy === undefined && isReportArchived === undefined;
const attributes = reportAttributes ?? reportAttributesDerivedValue;
const derivedNameExists = report && !!attributes?.[report.reportID]?.reportName;
if (canUseDerivedValue && derivedNameExists) {
return attributes[report.reportID].reportName;
}

let formattedName: string | undefined;
let parentReportAction: OnyxEntry<ReportAction>;
const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`];
if (parentReportActionParam) {
parentReportAction = parentReportActionParam;
} else {
parentReportAction = isThread(report) ? allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.parentReportID}`]?.[report.parentReportActionID] : undefined;
}
const parentReportActionMessage = getReportActionMessageReportUtils(parentReportAction);
const isArchivedNonExpense = isArchivedNonExpenseReport(report, isReportArchived);

if (
isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) ||
isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED) ||
isMarkAsClosedAction(parentReportAction)
) {
const harvesting = !isMarkAsClosedAction(parentReportAction) ? (getOriginalMessage(parentReportAction)?.harvesting ?? false) : false;
if (harvesting) {
return translateLocal('iou.automaticallySubmitted');

Check failure on line 5747 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
return translateLocal('iou.submitted', {memo: getOriginalMessage(parentReportAction)?.message});

Check failure on line 5749 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) {
const {automaticAction} = getOriginalMessage(parentReportAction) ?? {};
if (automaticAction) {
return translateLocal('iou.automaticallyForwarded');

Check failure on line 5754 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
return translateLocal('iou.forwarded');

Check failure on line 5756 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) {
return getRejectedReportMessage();
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RETRACTED) {
return getRetractedMessage();
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REOPENED) {
return getReopenedMessage();
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.CORPORATE_UPGRADE) {
return getUpgradeWorkspaceMessage();
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.TEAM_DOWNGRADE) {
return getDowngradeWorkspaceMessage();
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_CURRENCY) {
return getWorkspaceCurrencyUpdateMessage(parentReportAction);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_FIELD) {
return getWorkspaceUpdateFieldMessage(parentReportAction);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) {
return translateLocal('systemMessage.mergedWithCashTransaction');

Check failure on line 5780 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_NAME) {
return Str.htmlDecode(getWorkspaceNameUpdatedMessage(parentReportAction));
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_AUTO_REPORTING_FREQUENCY) {
return getWorkspaceFrequencyUpdateMessage(parentReportAction);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.ADD_REPORT_FIELD) {
return getWorkspaceReportFieldAddMessage(parentReportAction);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_REPORT_FIELD) {
return getWorkspaceReportFieldUpdateMessage(parentReportAction);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.DELETE_REPORT_FIELD) {
return getWorkspaceReportFieldDeleteMessage(parentReportAction);
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION)) {
return getUnreportedTransactionMessage();
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT_NO_RECEIPT)) {
return getPolicyChangeLogMaxExpenseAmountNoReceiptMessage(parentReportAction);
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_BILLABLE)) {
return getPolicyChangeLogDefaultBillableMessage(parentReportAction);
}
if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_REIMBURSABLE)) {
return getPolicyChangeLogDefaultReimbursableMessage(parentReportAction);
}
if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_TITLE_ENFORCED)) {
return getPolicyChangeLogDefaultTitleEnforcedMessage(parentReportAction);
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT) && getOriginalMessage(parentReportAction)?.resolution) {
return getActionableCardFraudAlertResolutionMessage(parentReportAction);
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED)) {
return translateLocal('iou.paidElsewhere');

Check failure on line 5821 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY)) {
return getPolicyChangeMessage(parentReportAction);
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL) || isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.REROUTE)) {
return getChangedApproverActionMessage(parentReportAction);
}

if (parentReportAction?.actionName && isTagModificationAction(parentReportAction?.actionName)) {
return getCleanedTagName(getWorkspaceTagUpdateMessage(parentReportAction) ?? '');
}

if (isMovedAction(parentReportAction)) {
return getMovedActionMessage(parentReportAction, parentReport);
}

if (isMoneyRequestAction(parentReportAction)) {
const originalMessage = getOriginalMessage(parentReportAction);
const reportPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`];
const last4Digits = reportPolicy?.achAccount?.accountNumber?.slice(-4) ?? '';

if (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) {
if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
return translateLocal('iou.paidElsewhere');

Check failure on line 5847 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.VBBA) {
if (originalMessage.automaticAction) {
return translateLocal('iou.automaticallyPaidWithBusinessBankAccount', {last4Digits});

Check failure on line 5851 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
return translateLocal('iou.businessBankAccount', {last4Digits});

Check failure on line 5853 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
if (originalMessage.automaticAction) {
return translateLocal('iou.automaticallyPaidWithExpensify');

Check failure on line 5857 in src/libs/ReportUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

`translateLocal` is deprecated. This function uses imperative Onyx data access patterns, similar to `Onyx.connect`. Use `useLocalize` hook instead for reactive data access in React components
}
return translateLocal('iou.paidWithExpensify');
}
}
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) {
const {automaticAction} = getOriginalMessage(parentReportAction) ?? {};
if (automaticAction) {
return translateLocal('iou.automaticallyApproved');
}
return translateLocal('iou.approvedMessage');
}
if (isUnapprovedAction(parentReportAction)) {
return translateLocal('iou.unapproved');
}

if (isActionableJoinRequest(parentReportAction)) {
return getJoinRequestMessage(parentReportAction);
}

if (isTaskReport(report) && isCanceledTaskReport(report, parentReportAction)) {
return translateLocal('parentReportAction.deletedTask');
}

if (isTaskReport(report)) {
return Parser.htmlToText(report?.reportName ?? '').trim();
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.INTEGRATION_SYNC_FAILED)) {
return getIntegrationSyncFailedMessage(parentReportAction, report?.policyID);
}

if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.TRAVEL_UPDATE)) {
return getTravelUpdateMessage(parentReportAction);
}

if (isChatThread(report)) {
if (!isEmptyObject(parentReportAction) && isTransactionThread(parentReportAction)) {
formattedName = getTransactionReportName({reportAction: parentReportAction, transactions, reports});

if (isArchivedNonExpense) {
formattedName = generateArchivedReportName(formattedName);
}
return formatReportLastMessageText(formattedName);
}

if (!isEmptyObject(parentReportAction) && isOldDotReportAction(parentReportAction)) {
return getMessageOfOldDotReportAction(parentReportAction);
}

if (isRenamedAction(parentReportAction)) {
return getRenamedAction(parentReportAction, isExpenseReport(getReport(report.parentReportID, allReports)));
}

if (parentReportActionMessage?.isDeletedParentAction) {
return translateLocal('parentReportAction.deletedMessage');
}

if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RESOLVED_DUPLICATES) {
return translateLocal('violations.resolvedDuplicates');
}

const isAttachment = isReportActionAttachment(!isEmptyObject(parentReportAction) ? parentReportAction : undefined);
const reportActionMessage = getReportActionMessage({
reportAction: parentReportAction,
reportID: report?.parentReportID,
childReportID: report?.reportID,
reports,
personalDetails,
}).replace(/(\n+|\r\n|\n|\r)/gm, ' ');
if (isAttachment && reportActionMessage) {
return `[${translateLocal('common.attachment')}]`;
}
if (
parentReportActionMessage?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE ||
parentReportActionMessage?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN ||
parentReportActionMessage?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE
) {
return translateLocal('parentReportAction.hiddenMessage');
}
if (isAdminRoom(report) || isUserCreatedPolicyRoom(report)) {
return getAdminRoomInvitedParticipants(parentReportAction, reportActionMessage);
}

if (reportActionMessage && isArchivedNonExpense) {
return generateArchivedReportName(reportActionMessage);
}
if (!isEmptyObject(parentReportAction) && isModifiedExpenseAction(parentReportAction)) {
const policyID = reports?.find((r) => r.reportID === report?.reportID)?.policyID;

const movedFromReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(parentReportAction, CONST.REPORT.MOVE_TYPE.FROM)}`];
const movedToReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(parentReportAction, CONST.REPORT.MOVE_TYPE.TO)}`];
const modifiedMessage = getForReportAction({
reportAction: parentReportAction,
policyID,
movedFromReport,
movedToReport,
});
return formatReportLastMessageText(modifiedMessage);
}
if (isTripRoom(report) && report?.reportName !== CONST.REPORT.DEFAULT_REPORT_NAME) {
return report?.reportName ?? '';
}
if (isCardIssuedAction(parentReportAction)) {
return getCardIssuedMessage({reportAction: parentReportAction});
}
return reportActionMessage;
}

if (isClosedExpenseReportWithNoExpenses(report, transactions)) {
return translateLocal('parentReportAction.deletedReport');
}

if (isGroupChat(report)) {
return getGroupChatName(undefined, true, report) ?? '';
}

if (isChatRoom(report)) {
formattedName = report?.reportName;
}

if (isPolicyExpenseChat(report)) {
formattedName = getPolicyExpenseChatName({report, personalDetailsList: personalDetails});
}

if (isMoneyRequestReport(report)) {
formattedName = getMoneyRequestReportName({report, policy});
}

if (isInvoiceReport(report)) {
formattedName = getInvoiceReportName(report, policy, invoiceReceiverPolicy);
}

if (isInvoiceRoom(report)) {
formattedName = getInvoicesChatName({report, receiverPolicy: invoiceReceiverPolicy, personalDetails, policies});
}

if (isSelfDM(report)) {
formattedName = getDisplayNameForParticipant({accountID: currentUserAccountID, shouldAddCurrentUserPostfix: true, personalDetailsData: personalDetails});
}

if (isConciergeChatReport(report)) {
formattedName = CONST.CONCIERGE_DISPLAY_NAME;
}

if (formattedName) {
return formatReportLastMessageText(isArchivedNonExpense ? generateArchivedReportName(formattedName) : formattedName);
}

// Not a room or PolicyExpenseChat, generate title from first 5 other participants
formattedName = buildReportNameFromParticipantNames({report, personalDetails});

const finalName = formattedName || (report?.reportName ?? '');

return isArchivedNonExpense ? generateArchivedReportName(finalName) : finalName;
}

function newGetReportName(report: OnyxEntry<Report>, reportAttributes?: ReportAttributesDerivedValue['reports']): string {
return (report && reportAttributes?.[report.reportID].reportName) ?? report?.reportName ?? '';
}

function getSearchReportName(props: GetReportNameParams): string {
const {report, policy} = props;
if (isChatThread(report) && policy?.name) {
Expand Down Expand Up @@ -12520,6 +12832,8 @@
getMovedActionMessage,
excludeParticipantsForDisplay,
getReportName,
computeReportName,
newGetReportName,
doesReportContainRequestsFromMultipleUsers,
hasUnresolvedCardFraudAlert,
getUnresolvedCardFraudAlertAction,
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/OnyxDerived/configs/reportAttributes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {OnyxEntry} from 'react-native-onyx';
import {generateIsEmptyReport, generateReportAttributes, getReportName, isArchivedReport, isValidReport} from '@libs/ReportUtils';
import {computeReportName, generateIsEmptyReport, generateReportAttributes, isArchivedReport, isValidReport} from '@libs/ReportUtils';
import SidebarUtils from '@libs/SidebarUtils';
import createOnyxDerivedValueConfig from '@userActions/OnyxDerived/createOnyxDerivedValueConfig';
import {hasKeyTriggeredCompute} from '@userActions/OnyxDerived/utils';
Expand Down Expand Up @@ -200,7 +200,7 @@ export default createOnyxDerivedValueConfig({
}

acc[report.reportID] = {
reportName: report ? getReportName(report, undefined, undefined, undefined, undefined, undefined, undefined, isReportArchived) : '',
reportName: report ? computeReportName(report, undefined, undefined, undefined, undefined, undefined, undefined, isReportArchived) : '',
isEmpty: generateIsEmptyReport(report, isReportArchived),
brickRoadStatus,
requiresAttention,
Expand Down
12 changes: 10 additions & 2 deletions src/pages/RoomMembersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ 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 {
getReportPersonalDetailsParticipants,
isChatThread,
isDefaultRoom,
isPolicyExpenseChat as isPolicyExpenseChatUtils,
isUserCreatedPolicyRoom,
newGetReportName,
} from '@libs/ReportUtils';
import StringUtils from '@libs/StringUtils';
import {clearAddRoomMemberError, openRoomMembersPage, removeFromRoom} from '@userActions/Report';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -64,6 +71,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) {
const isPolicyExpenseChat = useMemo(() => isPolicyExpenseChatUtils(report), [report]);
const backTo = route.params.backTo;
const isReportArchived = useReportIsArchived(report.reportID);
const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true});

const {chatParticipants: participants, personalDetailsParticipants} = useMemo(
() => getReportPersonalDetailsParticipants(report, personalDetails, reportMetadata, true),
Expand Down Expand Up @@ -400,7 +408,7 @@ function RoomMembersPage({report, policy}: RoomMembersPageProps) {
>
<HeaderWithBackButton
title={selectionModeHeader ? translate('common.selectMultiple') : translate('workspace.common.members')}
subtitle={StringUtils.lineBreaksToSpaces(getReportName(report))}
subtitle={StringUtils.lineBreaksToSpaces(newGetReportName(report, reportAttributes?.reports))}
onBackButtonPress={() => {
if (isMobileSelectionModeEnabled) {
setSelectedMembers([]);
Expand Down
Loading