Skip to content
Merged
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
6 changes: 5 additions & 1 deletion src/components/Search/FilterComponents/InSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ function InSelector({value = [], selectionListTextInputStyle, selectionListStyle
const isReportArchived = !!privateIsArchived;
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${reportData?.policyID}`];
const reportPolicyTags = policyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${getNonEmptyStringOnyxID(report?.policyID)}`];
const alternateText = getAlternateText(report, {}, {isReportArchived, policy, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, isTrackIntentUser});
const alternateText = getAlternateText(
report,
{},
{isReportArchived, personalDetails, policy, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, isTrackIntentUser},
);
return {...report, alternateText};
});

Expand Down
2 changes: 1 addition & 1 deletion src/components/Search/SearchFiltersChatsSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
const alternateText = getAlternateText(
report,
{},
{isReportArchived: privateIsArchived, policy, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, isTrackIntentUser},
{isReportArchived: privateIsArchived, personalDetails, policy, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, isTrackIntentUser},
);
return {...report, alternateText};
});
Expand Down
23 changes: 19 additions & 4 deletions src/libs/OptionsListUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {getForReportAction} from '@libs/ModifiedExpenseMessage';
import Navigation from '@libs/Navigation/Navigation';
import Parser from '@libs/Parser';
import type {OptionData as PersonalDetailOptionData} from '@libs/PersonalDetailOptionsListUtils/types';
import {getDisplayNameOrDefault, getPersonalDetailByEmail, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils';
import {getDisplayNameOrDefault, getLoginByAccountID, getPersonalDetailByEmail, getPersonalDetailsByIDs, getPersonalDetailsListByIDs} from '@libs/PersonalDetailsUtils';
import {addSMSDomainIfPhoneNumber, parsePhoneNumber} from '@libs/PhoneNumber';
import {
canSendInvoiceFromWorkspace,
Expand Down Expand Up @@ -430,6 +430,7 @@ function shouldShowLastActorDisplayName(

type GetAlternateTextConfig = {
isReportArchived: boolean | undefined;
personalDetails: OnyxEntry<PersonalDetailsList>;
// We'll make it required in the next PR. Ref: https://github.com/Expensify/App/issues/66415
policy?: OnyxEntry<Policy>;
lastActorDetails?: Partial<PersonalDetails> | null;
Expand All @@ -451,6 +452,7 @@ function getAlternateText(
{showChatPreviewLine = false, forcePolicyNamePreview = false}: PreviewConfig,
{
isReportArchived,
personalDetails,
policy,
lastActorDetails = {},
visibleReportActionsData = {},
Expand All @@ -473,6 +475,7 @@ function getAlternateText(
getLastMessageTextForReport({
translate: translateFn,
report,
personalDetails,
lastActorDetails,
policy,
isReportArchived,
Expand Down Expand Up @@ -653,6 +656,7 @@ function getLastActorDisplayNameFromLastVisibleActions(
function getLastMessageTextForReport({
translate,
report,
personalDetails,
lastActorDetails,
movedFromReport,
movedToReport,
Expand All @@ -670,6 +674,7 @@ function getLastMessageTextForReport({
}: {
translate: LocalizedTranslate;
report: OnyxEntry<Report>;
personalDetails: OnyxEntry<PersonalDetailsList>;
lastActorDetails: Partial<PersonalDetails> | null;
movedFromReport?: OnyxEntry<Report>;
movedToReport?: OnyxEntry<Report>;
Expand Down Expand Up @@ -793,7 +798,13 @@ function getLastMessageTextForReport({
} else if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED)) {
lastMessageTextFromReport = getMarkedReimbursedMessage(translate, lastReportAction);
} else if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSED)) {
lastMessageTextFromReport = getReimbursedMessage(translate, lastReportAction, report?.ownerAccountID);
lastMessageTextFromReport = getReimbursedMessage(
translate,
lastReportAction,
report?.ownerAccountID,
getLoginByAccountID(report?.ownerAccountID, personalDetails),
getLoginByAccountID(lastReportAction.actorAccountID, personalDetails),
);
} else if (isReportMessageAttachment({text: report?.lastMessageText ?? '', html: report?.lastMessageHtml, type: ''})) {
lastMessageTextFromReport = `[${translate('common.attachment')}]`;
} else if (isModifiedExpenseAction(lastReportAction)) {
Expand Down Expand Up @@ -917,7 +928,8 @@ function getLastMessageTextForReport({
} else if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION)) {
lastMessageTextFromReport = Parser.htmlToText(getUnreportedTransactionMessage(translate, lastReportAction, reportAttributesDerived));
} else if (isActionableMentionWhisper(lastReportAction)) {
lastMessageTextFromReport = Parser.htmlToText(getActionableMentionWhisperMessage(translate, lastReportAction));
const targetAccountIDs = getOriginalMessage(lastReportAction)?.inviteeAccountIDs;
lastMessageTextFromReport = Parser.htmlToText(getActionableMentionWhisperMessage(translate, lastReportAction, getPersonalDetailsListByIDs(targetAccountIDs, personalDetails)));
} else if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.DYNAMIC_EXTERNAL_WORKFLOW_ROUTED)) {
lastMessageTextFromReport = getDynamicExternalWorkflowRoutedMessage(lastReportAction, translate);
}
Expand Down Expand Up @@ -1071,7 +1083,7 @@ function getLastMessageTextForReport({

type CreateOptionParams = {
accountIDs: number[];
personalDetails: OnyxInputOrEntry<PersonalDetailsList>;
personalDetails: OnyxEntry<PersonalDetailsList>;
report: OnyxInputOrEntry<Report>;
privateIsArchived: boolean | undefined;
policy?: OnyxEntry<Policy>;
Expand Down Expand Up @@ -1180,6 +1192,7 @@ function createOption({
result.lastMessageText = getLastMessageTextForReport({
translate: translateFn,
report,
personalDetails,
lastActorDetails,
policy,
isReportArchived: result.private_isArchived,
Expand All @@ -1198,6 +1211,7 @@ function createOption({
{showChatPreviewLine, forcePolicyNamePreview},
{
isReportArchived: !!result.private_isArchived,
personalDetails,
policy,
lastActorDetails,
visibleReportActionsData,
Expand Down Expand Up @@ -2345,6 +2359,7 @@ function prepareReportOptionsForDisplay(
{showChatPreviewLine, forcePolicyNamePreview},
{
isReportArchived: !!option.private_isArchived,
personalDetails,
policy,
lastActorDetails: null,
visibleReportActionsData,
Expand Down
30 changes: 18 additions & 12 deletions src/libs/PersonalDetailsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,11 @@ function getPersonalDetailsByIDs({
return result;
}

function newGetPersonalDetailsByIDs(accountIDs: number[], personalDetails: OnyxEntry<PersonalDetailsList>): PersonalDetails[] {
function newGetPersonalDetailsByIDs(accountIDs: number[] | undefined, personalDetails: OnyxEntry<PersonalDetailsList>): PersonalDetails[] {
if (!accountIDs) {
return [];
}

const result: PersonalDetails[] = [];
for (const accountID of accountIDs) {
const detail = getPersonalDetailsByID(accountID, personalDetails);
Expand All @@ -154,18 +158,20 @@ function newGetPersonalDetailsByIDs(accountIDs: number[], personalDetails: OnyxE
return result;
}

function getPersonalDetailsListByIDs(accountIDs: Array<number | undefined>, personalDetails: OnyxEntry<PersonalDetailsList>): PersonalDetailsList {
return accountIDs.reduce((acc, accountID) => {
if (!accountID) {
return acc;
}
const detail = personalDetails?.[accountID];
if (!detail) {
function getPersonalDetailsListByIDs(accountIDs: Array<number | undefined> | undefined, personalDetails: OnyxEntry<PersonalDetailsList>): PersonalDetailsList {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is identical to the one in #91565

return (
accountIDs?.reduce((acc, accountID) => {
if (!accountID) {
return acc;
}
const detail = personalDetails?.[accountID];
if (!detail) {
return acc;
}
acc[accountID] = detail;
return acc;
}
acc[accountID] = detail;
return acc;
}, {} as PersonalDetailsList);
}, {} as PersonalDetailsList) ?? {}
);
}

/**
Expand Down
74 changes: 43 additions & 31 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import createDynamicRoute from './Navigation/helpers/dynamicRoutesUtils/createDy
import getReportURLForCurrentContext from './Navigation/helpers/getReportURLForCurrentContext';
import {getIsOffline, subscribe as subscribeNetworkState} from './NetworkState';
import Parser from './Parser';
import {arePersonalDetailsMissing, createPersonalDetailsLookupByAccountID, getEffectiveDisplayName, getPersonalDetailByEmail, getPersonalDetailsByIDs} from './PersonalDetailsUtils';
import {arePersonalDetailsMissing, getEffectiveDisplayName, getPersonalDetailByEmail} from './PersonalDetailsUtils';
import stripFollowupListFromHtml from './ReportActionFollowupUtils/stripFollowupListFromHtml';
import type {getReportName} from './ReportNameUtils';
import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils';
Expand Down Expand Up @@ -469,8 +469,17 @@ function getMarkedReimbursedMessage(translate: LocalizedTranslate, reportAction:
return translate('iou.paidElsewhere', {comment: originalMessage?.message?.trim()});
}

function getReimbursedMessage(translate: LocalizedTranslate, reportAction: OnyxInputOrEntry<ReportAction>, reportOwnerAccountID: number | undefined, currentUserAccountID?: number): string {
function getReimbursedMessage(
translate: LocalizedTranslate,
reportAction: OnyxInputOrEntry<ReportAction>,
reportOwnerAccountID: number | undefined,
submitterLoginParam: string | undefined,
actorLoginParam: string | undefined,
currentUserAccountID?: number,
): string {
const effectiveCurrentUserAccountID = currentUserAccountID ?? deprecatedCurrentUserAccountID ?? CONST.DEFAULT_NUMBER_ID;
const submitterLogin = submitterLoginParam ?? '';
const actorLogin = actorLoginParam ?? '';
const originalMessage = getOriginalMessage(reportAction) as OriginalMessageReimbursed | undefined;

// Auth stores the payment method as `method`; the openReport path maps it to `paymentMethod` via getDisplayInformation().
Expand Down Expand Up @@ -499,13 +508,8 @@ function getReimbursedMessage(translate: LocalizedTranslate, reportAction: OnyxI

// Resolve submitter from report owner
const submitterAccountID = reportOwnerAccountID ?? CONST.DEFAULT_NUMBER_ID;
const submitterLogin = getPersonalDetailsByIDs({accountIDs: [submitterAccountID], currentUserAccountID: effectiveCurrentUserAccountID}).at(0)?.login ?? '';
const isCurrentUser = submitterAccountID === effectiveCurrentUserAccountID;

// Resolve actor from action
const actorAccountID = reportAction?.actorAccountID ?? CONST.DEFAULT_NUMBER_ID;
const actorLogin = getPersonalDetailsByIDs({accountIDs: [actorAccountID], currentUserAccountID: effectiveCurrentUserAccountID}).at(0)?.login ?? '';

const isAutomation = !!reportAction?.delegateAccountID;

let paymentSuffix = '';
Expand Down Expand Up @@ -1979,6 +1983,8 @@ function isReportActionAttachment(reportAction: OnyxInputOrEntry<ReportAction>):
function getMemberChangeMessageElements(
translate: LocalizedTranslate,
reportAction: OnyxEntry<ReportAction>,
actorDetails: OnyxEntry<PersonalDetails>,
targetAccountDetailsList: OnyxEntry<PersonalDetailsList>,
getReportNameCallback: typeof getReportName,
reportAttributes?: ReportAttributesDerivedValue['reports'],
): readonly MemberChangeMessageElement[] {
Expand All @@ -1996,17 +2002,15 @@ function getMemberChangeMessageElements(
}

if (isLeaveAction) {
verb = getPolicyChangeLogEmployeeLeftMessage(translate, reportAction);
verb = getPolicyChangeLogEmployeeLeftMessage(translate, reportAction, actorDetails);
}

const originalMessage = getOriginalMessage(reportAction);
const targetAccountIDs: number[] = originalMessage?.targetAccountIDs ?? [];
const personalDetails = getPersonalDetailsByIDs({accountIDs: targetAccountIDs, currentUserAccountID: 0});
const personalDetailsMap = createPersonalDetailsLookupByAccountID(personalDetails);

const mentionElements = targetAccountIDs.map((accountID): MemberChangeMessageUserMentionElement => {
const personalDetail = personalDetailsMap[accountID];
const handleText = getEffectiveDisplayName(formatPhoneNumber, personalDetail) ?? translate('common.hidden');
const personalDetail = targetAccountDetailsList?.[accountID];
const handleText = personalDetail ? getEffectiveDisplayName(formatPhoneNumber, personalDetail) : translate('common.hidden');

return {
kind: 'userMention',
Expand Down Expand Up @@ -2324,10 +2328,19 @@ function getDynamicExternalWorkflowApproveFailedActionMessage(translate: Localiz
function getMemberChangeMessageFragment(
translate: LocalizedTranslate,
reportAction: OnyxEntry<ReportAction>,
actorDetails: OnyxEntry<PersonalDetails>,
targetAccountDetailsList: OnyxEntry<PersonalDetailsList>,
getReportNameCallback: typeof getReportName,
reportAttributes?: ReportAttributesDerivedValue['reports'],
): Message {
const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(translate, reportAction, getReportNameCallback, reportAttributes);
const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(
translate,
reportAction,
actorDetails,
targetAccountDetailsList,
getReportNameCallback,
reportAttributes,
);
const html = messageElements
.map((messageElement) => {
switch (messageElement.kind) {
Expand Down Expand Up @@ -2449,18 +2462,20 @@ function hasRequestFromCurrentAccount(report: OnyxEntry<Report>, currentAccountI
* @param reportAction
* @returns the actionable mention whisper message.
*/
function getActionableMentionWhisperMessage(translate: LocalizedTranslate, reportAction: OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER>>): string {
function getActionableMentionWhisperMessage(
translate: LocalizedTranslate,
reportAction: OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER>>,
targetAccountDetails: OnyxEntry<PersonalDetailsList>,
): string {
if (!reportAction) {
return '';
}
const originalMessage = getOriginalMessage(reportAction);
const targetAccountIDs: number[] = originalMessage?.inviteeAccountIDs ?? [];
const personalDetails = getPersonalDetailsByIDs({accountIDs: targetAccountIDs, currentUserAccountID: 0});
const personalDetailsMap = createPersonalDetailsLookupByAccountID(personalDetails);

const mentionElements = targetAccountIDs.map((accountID): string => {
const personalDetail = personalDetailsMap[accountID];
const displayName = getEffectiveDisplayName(formatPhoneNumber, personalDetail);
const personalDetail = targetAccountDetails?.[accountID];
const displayName = personalDetail ? getEffectiveDisplayName(formatPhoneNumber, personalDetail) : undefined;
const handleText = isEmpty(displayName) ? translate('common.hidden') : displayName;
return `<mention-user accountID=${accountID}>@${handleText}</mention-user>`;
});
Expand Down Expand Up @@ -2865,16 +2880,17 @@ function getPolicyChangeLogUpdateEmployee(translate: LocalizedTranslate, reportA
return buildPolicyChangeLogUpdateEmployeeSingleFieldMessage(translate, originalMessage?.field, originalMessage?.oldValue, originalMessage?.newValue, email);
}

function getPolicyChangeLogEmployeeLeftMessage(translate: LocalizedTranslate, reportAction: ReportAction, useName = false): string {
if (!isLeavePolicyAction(reportAction)) {
return '';
}
function getPolicyChangeLogEmployeeLeftMessage(
translate: LocalizedTranslate,
reportAction: ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY>,
actorDetails: OnyxEntry<PersonalDetails>,
useName = false,
): string {
const originalMessage = getOriginalMessage(reportAction);
const personalDetails = getPersonalDetailsByIDs({accountIDs: reportAction.actorAccountID ? [reportAction.actorAccountID] : [], currentUserAccountID: 0})?.at(0);
if (!!originalMessage && !originalMessage.email) {
originalMessage.email = personalDetails?.login;
originalMessage.email = actorDetails?.login;
}
const nameOrEmail = useName && !!personalDetails?.firstName ? `${personalDetails?.firstName}:` : (originalMessage?.email ?? '');
const nameOrEmail = useName && !!actorDetails?.firstName ? `${actorDetails?.firstName}:` : (originalMessage?.email ?? '');
const formattedNameOrEmail = formatPhoneNumber(nameOrEmail);
return translate('report.actions.type.leftWorkspace', formattedNameOrEmail);
}
Expand Down Expand Up @@ -4005,12 +4021,7 @@ function getUpdatedApprovalRuleMessage(translate: LocalizedTranslate, reportActi
return getReportActionText(reportAction);
}

function getRemovedFromApprovalChainMessage(translate: LocalizedTranslate, reportAction: OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.REMOVED_FROM_APPROVAL_CHAIN>>) {
const originalMessage = getOriginalMessage(reportAction);
const submittersNames = getPersonalDetailsByIDs({
accountIDs: originalMessage?.submittersAccountIDs ?? [],
currentUserAccountID: deprecatedCurrentUserAccountID ?? CONST.DEFAULT_NUMBER_ID,
}).map(({displayName, login}) => displayName ?? login ?? 'Unknown Submitter');
function getRemovedFromApprovalChainMessage(translate: LocalizedTranslate, submittersNames: string[]) {
return translate('workspaceActions.removedFromApprovalWorkflow', {submittersNames, count: submittersNames.length});
}

Expand Down Expand Up @@ -4732,6 +4743,7 @@ export {
isDeletedAction,
isDeletedParentAction,
isMemberChangeAction,
isLeavePolicyAction,
isExportIntegrationAction,
isIntegrationMessageAction,
isMessageDeleted,
Expand Down
7 changes: 5 additions & 2 deletions src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
shouldShowLastActorDisplayName,
} from './OptionsListUtils';
import Parser from './Parser';
import {getPersonalDetailsByID} from './PersonalDetailsUtils';
import {getCleanedTagName} from './PolicyUtils';
import {
getActionableCard3DSTransactionApprovalMessage,
Expand Down Expand Up @@ -136,6 +137,7 @@ import {
isActionOfType,
isCardIssuedAction,
isInviteOrRemovedAction,
isLeavePolicyAction,
isOldDotReportAction,
isRenamedAction,
isTagModificationAction,
Expand Down Expand Up @@ -976,6 +978,7 @@ function getOptionData({
lastMessageTextFromReport = getLastMessageTextForReport({
translate,
report,
personalDetails,
lastActorDetails,
movedFromReport,
movedToReport,
Expand Down Expand Up @@ -1167,8 +1170,8 @@ function getOptionData({
result.alternateText = getPolicyChangeLogDefaultReimbursableMessage(translate, lastAction);
} else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_TITLE_ENFORCED) {
result.alternateText = getPolicyChangeLogDefaultTitleEnforcedMessage(translate, lastAction);
} else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY) {
result.alternateText = getPolicyChangeLogEmployeeLeftMessage(translate, lastAction, true);
} else if (isLeavePolicyAction(lastAction)) {
result.alternateText = getPolicyChangeLogEmployeeLeftMessage(translate, lastAction, getPersonalDetailsByID(lastAction.actorAccountID, personalDetails), true);
} else if (isCardIssuedAction(lastAction)) {
result.alternateText = getCardIssuedMessage({reportAction: lastAction, expensifyCard: card, translate});
} else if (lastAction && isOldDotReportAction(lastAction)) {
Expand Down
Loading
Loading