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: 4 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3544,9 +3544,11 @@ function getDisplayNameForParticipant({

// This is to check if account is an invite/optimistically created one
// and prevent from falling back to 'Hidden', so a correct value is shown
// when searching for a new user
// when searching for a new user. Imported device contacts persist a real
// display name on their optimistic record, so prefer that over the login.
if (personalDetails.isOptimisticPersonalDetail === true) {
return formattedLogin;
const optimisticDisplayName = getDisplayNameOrDefault(personalDetails, formattedLogin, false);
return shouldUseShortForm && personalDetails.firstName ? personalDetails.firstName : optimisticDisplayName;
}

// For selfDM, we display the user's displayName followed by '(you)' as a postfix
Expand Down
13 changes: 10 additions & 3 deletions src/libs/actions/IOU/MoneyRequestBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1545,14 +1545,21 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma
}

const shouldCreateOptimisticPersonalDetails = isNewChatReport && !(personalDetails?.[payerAccountID] ?? allPersonalDetails[payerAccountID]);
// For imported device contacts the name is carried on text/firstName/lastName rather than
// displayName, so fall back through those before defaulting to the login/phone number. Otherwise
// the contact's name is lost and the optimistic record falls back to the phone number.
const optimisticPersonalDetailFirstName = participant.firstName ?? '';
const optimisticPersonalDetailLastName = participant.lastName ?? '';
const optimisticPersonalDetailDisplayName =
[participant.displayName, participant.text, `${optimisticPersonalDetailFirstName} ${optimisticPersonalDetailLastName}`.trim()].find((name) => !!name) ?? payerEmail;
// Add optimistic personal details for participant
const optimisticPersonalDetailListAction = shouldCreateOptimisticPersonalDetails
? {
[payerAccountID]: {
accountID: payerAccountID,
// Disabling this line since participant.displayName can be an empty string
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
displayName: formatPhoneNumber(participant.displayName || payerEmail),
displayName: formatPhoneNumber(optimisticPersonalDetailDisplayName),
firstName: optimisticPersonalDetailFirstName,
lastName: optimisticPersonalDetailLastName,
login: participant.login,
isOptimisticPersonalDetail: true,
},
Expand Down
83 changes: 83 additions & 0 deletions tests/unit/ReportUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13832,6 +13832,89 @@ describe('ReportUtils', () => {

await Onyx.clear();
});

it('should prefer the real display name of an optimistic imported device contact over the phone login', async () => {
await Onyx.clear();

const importedContactAccountID = 987001;
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
[importedContactAccountID]: {
accountID: importedContactAccountID,
login: '+15551234567@expensify.sms',
displayName: 'John Doe',
firstName: 'John',
lastName: 'Doe',
isOptimisticPersonalDetail: true,
},
});
await waitForBatchedUpdates();

const displayName = getDisplayNameForParticipant({formatPhoneNumber, accountID: importedContactAccountID});
expect(displayName).toBe('John Doe');

await Onyx.clear();
});

it('should return the first name for an optimistic imported device contact when short form is requested', async () => {
await Onyx.clear();

const importedContactAccountID = 987002;
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
[importedContactAccountID]: {
accountID: importedContactAccountID,
login: '+15551234567@expensify.sms',
displayName: 'John Doe',
firstName: 'John',
lastName: 'Doe',
isOptimisticPersonalDetail: true,
},
});
await waitForBatchedUpdates();

const displayName = getDisplayNameForParticipant({formatPhoneNumber, accountID: importedContactAccountID, shouldUseShortForm: true});
expect(displayName).toBe('John');

await Onyx.clear();
});

it('should fall back to the login for an optimistic invite/new-user stub whose display name equals the login', async () => {
await Onyx.clear();

const newUserAccountID = 987003;
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
[newUserAccountID]: {
accountID: newUserAccountID,
login: 'newuser@example.com',
displayName: 'newuser@example.com',
isOptimisticPersonalDetail: true,
},
});
await waitForBatchedUpdates();

const displayName = getDisplayNameForParticipant({formatPhoneNumber, accountID: newUserAccountID});
expect(displayName).toBe('newuser@example.com');

await Onyx.clear();
});

it('should fall back to the formatted login (not "Hidden") for an optimistic record without a display name', async () => {
await Onyx.clear();

const newUserAccountID = 987004;
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
[newUserAccountID]: {
accountID: newUserAccountID,
login: 'newuser2@example.com',
isOptimisticPersonalDetail: true,
},
});
await waitForBatchedUpdates();

const displayName = getDisplayNameForParticipant({formatPhoneNumber, accountID: newUserAccountID});
expect(displayName).toBe('newuser2@example.com');

await Onyx.clear();
});
});

describe('getViolatingReportIDForRBRInLHN', () => {
Expand Down
Loading