diff --git a/src/CONST.ts b/src/CONST.ts index abf8382d4771..8d4eaac44a38 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1543,6 +1543,8 @@ const CONST = { PATH_WITHOUT_POLICY_ID: /\/w\/[a-zA-Z0-9]+(\/|$)/, POLICY_ID_FROM_PATH: /\/w\/([a-zA-Z0-9]+)(\/|$)/, + + SHORT_MENTION: new RegExp(`@[\\w\\-\\+\\'#]+(?:\\.[\\w\\-\\'\\+]+)*`, 'gim'), }, PRONOUNS: { diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 9121eebb3367..79e67164a15a 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -260,17 +260,6 @@ Onyx.connect({ }, }); -/** - * Adds expensify SMS domain (@expensify.sms) if login is a phone number and if it's not included yet - */ -function addSMSDomainIfPhoneNumber(login: string): string { - const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(login); - if (parsedPhoneNumber.possible && !Str.isValidEmail(login)) { - return `${parsedPhoneNumber.number?.e164}${CONST.SMS.DOMAIN}`; - } - return login; -} - /** * @param defaultValues {login: accountID} In workspace invite page, when new user is added we pass available data to opt in * @returns Returns avatar data for a list of user accountIDs @@ -779,7 +768,7 @@ function isCurrentUser(userDetails: PersonalDetails): boolean { } // If user login is a mobile number, append sms domain if not appended already. - const userDetailsLogin = addSMSDomainIfPhoneNumber(userDetails.login ?? ''); + const userDetailsLogin = PhoneNumber.addSMSDomainIfPhoneNumber(userDetails.login ?? ''); if (currentUserLogin?.toLowerCase() === userDetailsLogin.toLowerCase()) { return true; @@ -1619,7 +1608,7 @@ function getOptions( const noOptions = recentReportOptions.length + personalDetailsOptions.length === 0 && !currentUserOption; const noOptionsMatchExactly = !personalDetailsOptions .concat(recentReportOptions) - .find((option) => option.login === addSMSDomainIfPhoneNumber(searchValue ?? '').toLowerCase() || option.login === searchValue?.toLowerCase()); + .find((option) => option.login === PhoneNumber.addSMSDomainIfPhoneNumber(searchValue ?? '').toLowerCase() || option.login === searchValue?.toLowerCase()); if ( searchValue && @@ -1628,7 +1617,7 @@ function getOptions( selectedOptions.every((option) => 'login' in option && option.login !== searchValue) && ((Str.isValidEmail(searchValue) && !Str.isDomainEmail(searchValue) && !Str.endsWith(searchValue, CONST.SMS.DOMAIN)) || (parsedPhoneNumber.possible && Str.isValidPhone(LoginUtils.getPhoneNumberWithoutSpecialChars(parsedPhoneNumber.number?.input ?? '')))) && - !optionsToExclude.find((optionToExclude) => 'login' in optionToExclude && optionToExclude.login === addSMSDomainIfPhoneNumber(searchValue).toLowerCase()) && + !optionsToExclude.find((optionToExclude) => 'login' in optionToExclude && optionToExclude.login === PhoneNumber.addSMSDomainIfPhoneNumber(searchValue).toLowerCase()) && (searchValue !== CONST.EMAIL.CHRONOS || Permissions.canUseChronos(betas)) && !excludeUnknownUsers ) { @@ -2009,7 +1998,6 @@ function formatSectionsFromSearchTerm( } export { - addSMSDomainIfPhoneNumber, getAvatarsForAccountIDs, isCurrentUser, isPersonalDetailsReady, diff --git a/src/libs/PhoneNumber.ts b/src/libs/PhoneNumber.ts index f92aade2c892..787b3634030a 100644 --- a/src/libs/PhoneNumber.ts +++ b/src/libs/PhoneNumber.ts @@ -1,6 +1,7 @@ // eslint-disable-next-line no-restricted-imports import {parsePhoneNumber as originalParsePhoneNumber} from 'awesome-phonenumber'; import type {ParsedPhoneNumber, ParsedPhoneNumberInvalid, PhoneNumberParseOptions} from 'awesome-phonenumber'; +import Str from 'expensify-common/lib/str'; import CONST from '@src/CONST'; /** @@ -39,5 +40,16 @@ function parsePhoneNumber(phoneNumber: string, options?: PhoneNumberParseOptions } as ParsedPhoneNumberInvalid; } +/** + * Adds expensify SMS domain (@expensify.sms) if login is a phone number and if it's not included yet + */ +function addSMSDomainIfPhoneNumber(login: string): string { + const parsedPhoneNumber = parsePhoneNumber(login); + if (parsedPhoneNumber.possible && !Str.isValidEmail(login)) { + return `${parsedPhoneNumber.number?.e164}${CONST.SMS.DOMAIN}`; + } + return login; +} + // eslint-disable-next-line import/prefer-default-export -export {parsePhoneNumber}; +export {parsePhoneNumber, addSMSDomainIfPhoneNumber}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index ea0eba523092..a814c91ea8b2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -57,11 +57,13 @@ import isReportMessageAttachment from './isReportMessageAttachment'; import localeCompare from './LocaleCompare'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as Localize from './Localize'; +import {isEmailPublicDomain} from './LoginUtils'; import linkingConfig from './Navigation/linkingConfig'; import Navigation from './Navigation/Navigation'; import * as NumberUtils from './NumberUtils'; import Permissions from './Permissions'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; +import * as PhoneNumber from './PhoneNumber'; import * as PolicyUtils from './PolicyUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; @@ -420,6 +422,7 @@ type AncestorIDs = { }; let currentUserEmail: string | undefined; +let currentUserPrivateDomain: string | undefined; let currentUserAccountID: number | undefined; let isAnonymousUser = false; @@ -436,16 +439,19 @@ Onyx.connect({ currentUserEmail = value.email; currentUserAccountID = value.accountID; isAnonymousUser = value.authTokenType === 'anonymousAccount'; + currentUserPrivateDomain = isEmailPublicDomain(currentUserEmail ?? '') ? '' : Str.extractEmailDomain(currentUserEmail ?? ''); }, }); let allPersonalDetails: OnyxCollection; +let allPersonalDetailLogins: string[]; let currentUserPersonalDetails: OnyxEntry; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (value) => { currentUserPersonalDetails = value?.[currentUserAccountID ?? -1] ?? null; allPersonalDetails = value ?? {}; + allPersonalDetailLogins = Object.values(allPersonalDetails).map((personalDetail) => personalDetail?.login ?? ''); }, }); @@ -2655,7 +2661,26 @@ function hasReportNameError(report: OnyxEntry): boolean { */ function getParsedComment(text: string): string { const parser = new ExpensiMark(); - return text.length <= CONST.MAX_MARKUP_LENGTH ? parser.replace(text, {shouldEscapeText: !shouldAllowRawHTMLMessages()}) : lodashEscape(text); + const textWithMention = text.replace(CONST.REGEX.SHORT_MENTION, (match) => { + const mention = match.substring(1); + + if (!Str.isValidEmail(mention) && currentUserPrivateDomain) { + const mentionWithEmailDomain = `${mention}@${currentUserPrivateDomain}`; + if (allPersonalDetailLogins.includes(mentionWithEmailDomain)) { + return `@${mentionWithEmailDomain}`; + } + } + if (Str.isValidPhone(mention)) { + const mentionWithSmsDomain = PhoneNumber.addSMSDomainIfPhoneNumber(mention); + if (allPersonalDetailLogins.includes(mentionWithSmsDomain)) { + return `@${mentionWithSmsDomain}`; + } + } + + return match; + }); + + return text.length <= CONST.MAX_MARKUP_LENGTH ? parser.replace(textWithMention, {shouldEscapeText: !shouldAllowRawHTMLMessages()}) : lodashEscape(text); } function getReportDescriptionText(report: Report): string { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index dbab05dcfcd1..5f9657755b02 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -35,8 +35,8 @@ import * as Localize from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import * as NextStepUtils from '@libs/NextStepUtils'; import * as NumberUtils from '@libs/NumberUtils'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; import Permissions from '@libs/Permissions'; +import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -801,7 +801,7 @@ function getMoneyRequestInformation( payeeEmail = currentUserEmail, moneyRequestReportID = '', ): MoneyRequestInformation { - const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? ''); + const payerEmail = PhoneNumber.addSMSDomainIfPhoneNumber(participant.login ?? ''); const payerAccountID = Number(participant.accountID); const isPolicyExpenseChat = participant.isPolicyExpenseChat; @@ -1646,7 +1646,7 @@ function createSplitsAndOnyxData( existingSplitChatReportID = '', billable = false, ): SplitsAndOnyxData { - const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); + const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const existingSplitChatReport = existingSplitChatReportID || participants[0].reportID @@ -1814,7 +1814,7 @@ function createSplitsAndOnyxData( // In case the participant is a workspace, email & accountID should remain undefined and won't be used in the rest of this code // participant.login is undefined when the request is initiated from a group DM with an unknown user, so we need to add a default - const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); + const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : PhoneNumber.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase(); const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; @@ -2110,7 +2110,7 @@ function startSplitBill( existingSplitChatReportID = '', billable = false, ) { - const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); + const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const existingSplitChatReport = existingSplitChatReportID || participants[0].reportID @@ -2274,7 +2274,7 @@ function startSplitBill( participants.forEach((participant) => { // Disabling this line since participant.login can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase(); + const email = participant.isOwnPolicyExpenseChat ? '' : PhoneNumber.addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase(); const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID); if (email === currentUserEmailForIOUSplit) { return; @@ -2383,7 +2383,7 @@ function startSplitBill( * @param sessionEmail - email of the current user */ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportAction, updatedTransaction: OnyxTypes.Transaction, sessionAccountID: number, sessionEmail: string) { - const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(sessionEmail); + const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(sessionEmail); const {transactionID} = updatedTransaction; const unmodifiedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -3218,7 +3218,7 @@ function getSendMoneyParams( managerID: number, recipient: Participant, ): SendMoneyParamsData { - const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login ?? ''); + const recipientEmail = PhoneNumber.addSMSDomainIfPhoneNumber(recipient.login ?? ''); const recipientAccountID = Number(recipient.accountID); const newIOUReportDetails = JSON.stringify({ amount, diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 41288ce5eecd..ce222940c7ca 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -32,8 +32,8 @@ import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import Log from '@libs/Log'; import * as NumberUtils from '@libs/NumberUtils'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; +import * as PhoneNumber from '@libs/PhoneNumber'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -650,7 +650,7 @@ function createPolicyExpenseChats(policyID: string, invitedEmailsToAccountIDs: I Object.keys(invitedEmailsToAccountIDs).forEach((email) => { const accountID = invitedEmailsToAccountIDs[email]; const cleanAccountID = Number(accountID); - const login = OptionsListUtils.addSMSDomainIfPhoneNumber(email); + const login = PhoneNumber.addSMSDomainIfPhoneNumber(email); const oldChat = ReportUtils.getChatByParticipantsAndPolicy([sessionAccountID, cleanAccountID], policyID); @@ -731,7 +731,7 @@ function createPolicyExpenseChats(policyID: string, invitedEmailsToAccountIDs: I */ function addMembersToWorkspace(invitedEmailsToAccountIDs: InvitedEmailsToAccountIDs, welcomeNote: string, policyID: string) { const membersListKey = `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}` as const; - const logins = Object.keys(invitedEmailsToAccountIDs).map((memberLogin) => OptionsListUtils.addSMSDomainIfPhoneNumber(memberLogin)); + const logins = Object.keys(invitedEmailsToAccountIDs).map((memberLogin) => PhoneNumber.addSMSDomainIfPhoneNumber(memberLogin)); const accountIDs = Object.values(invitedEmailsToAccountIDs); const newPersonalDetailsOnyxData = PersonalDetailsUtils.getNewPersonalDetailsOnyxData(logins, accountIDs); diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index c363f49e7e3d..7ad12cf3e1ed 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -52,8 +52,8 @@ import getPlatform from '@libs/getPlatform'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import LocalNotification from '@libs/Notification/LocalNotification'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; +import * as PhoneNumber from '@libs/PhoneNumber'; import getPolicyMemberAccountIDs from '@libs/PolicyMembersUtils'; import {extractPolicyIDFromPath} from '@libs/PolicyUtils'; import * as Pusher from '@libs/Pusher/pusher'; @@ -2398,7 +2398,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: Record typeof accountID === 'number', ); - const logins = inviteeEmails.map((memberLogin) => OptionsListUtils.addSMSDomainIfPhoneNumber(memberLogin)); + const logins = inviteeEmails.map((memberLogin) => PhoneNumber.addSMSDomainIfPhoneNumber(memberLogin)); const newPersonalDetailsOnyxData = PersonalDetailsUtils.getNewPersonalDetailsOnyxData(logins, inviteeAccountIDs); const optimisticData: OnyxUpdate[] = [ diff --git a/src/libs/actions/TeachersUnite.ts b/src/libs/actions/TeachersUnite.ts index ab48609e2d53..1f8b32724bd4 100644 --- a/src/libs/actions/TeachersUnite.ts +++ b/src/libs/actions/TeachersUnite.ts @@ -4,7 +4,7 @@ import * as API from '@libs/API'; import type {AddSchoolPrincipalParams, ReferTeachersUniteVolunteerParams} from '@libs/API/parameters'; import {WRITE_COMMANDS} from '@libs/API/types'; import Navigation from '@libs/Navigation/Navigation'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as PhoneNumber from '@libs/PhoneNumber'; import * as ReportUtils from '@libs/ReportUtils'; import type {OptimisticCreatedReportAction} from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -69,7 +69,7 @@ function referTeachersUniteVolunteer(partnerUserID: string, firstName: string, l */ function addSchoolPrincipal(firstName: string, partnerUserID: string, lastName: string, policyID: string) { const policyName = CONST.TEACHERS_UNITE.POLICY_NAME; - const loggedInEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(sessionEmail); + const loggedInEmail = PhoneNumber.addSMSDomainIfPhoneNumber(sessionEmail); const reportCreationData: ReportCreationData = {}; const expenseChatData = ReportUtils.buildOptimisticChatReport([sessionAccountID], '', CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, policyID, sessionAccountID, true, policyName); diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 40a1b009b38d..7bcd64397e20 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -21,7 +21,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import {parsePhoneNumber} from '@libs/PhoneNumber'; +import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as Report from '@userActions/Report'; @@ -56,7 +56,7 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa const excludedUsers = useMemo( () => [...PersonalDetailsUtils.getLoginsByAccountIDs(report?.visibleChatMemberAccountIDs ?? []), ...CONST.EXPENSIFY_EMAILS].map((participant) => - OptionsListUtils.addSMSDomainIfPhoneNumber(participant), + PhoneNumber.addSMSDomainIfPhoneNumber(participant), ), [report], ); @@ -109,7 +109,7 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa filterSelectedOptions = selectedOptions.filter((option) => { const accountID = option?.accountID; const isOptionInPersonalDetails = invitePersonalDetails.some((personalDetail) => accountID && personalDetail?.accountID === accountID); - const parsedPhoneNumber = parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchTerm))); + const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchTerm))); const searchValue = parsedPhoneNumber.possible && parsedPhoneNumber.number ? parsedPhoneNumber.number.e164 : searchTerm.toLowerCase(); const isPartOfSearchTerm = option.text?.toLowerCase().includes(searchValue) ?? option.login?.toLowerCase().includes(searchValue); return isPartOfSearchTerm ?? isOptionInPersonalDetails; @@ -199,7 +199,9 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa if ( !userToInvite && excludedUsers.includes( - parsePhoneNumber(LoginUtils.appendCountryCode(searchValue)).possible ? OptionsListUtils.addSMSDomainIfPhoneNumber(LoginUtils.appendCountryCode(searchValue)) : searchValue, + PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(searchValue)).possible + ? PhoneNumber.addSMSDomainIfPhoneNumber(LoginUtils.appendCountryCode(searchValue)) + : searchValue, ) ) { return translate('messages.userIsAlreadyMember', {login: searchValue, name: reportName}); diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx index ac52c06ee084..5f07dc66ea4d 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx @@ -1,3 +1,4 @@ +import Str from 'expensify-common/lib/str'; import lodashSortBy from 'lodash/sortBy'; import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; @@ -6,8 +7,10 @@ import type {Mention} from '@components/MentionSuggestions'; import MentionSuggestions from '@components/MentionSuggestions'; import {usePersonalDetails} from '@components/OnyxProvider'; import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; +import * as LoginUtils from '@libs/LoginUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as SuggestionsUtils from '@libs/SuggestionUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -44,6 +47,7 @@ function SuggestionMention( const previousValue = usePrevious(value); const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const isMentionSuggestionsMenuVisible = !!suggestionValues.suggestedMentions.length && suggestionValues.shouldShowSuggestionMenu; const [highlightedMentionIndex, setHighlightedMentionIndex] = useArrowKeyFocusManager({ @@ -55,6 +59,22 @@ function SuggestionMention( // Used to decide whether to block the suggestions list from showing to prevent flickering const shouldBlockCalc = useRef(false); + const formatLoginPrivateDomain = useCallback( + (displayText = '', userLogin = '') => { + if (userLogin !== displayText) { + return displayText; + } + // If the emails are not in the same private domain, we also return the displayText + if (!LoginUtils.areEmailsFromSamePrivateDomain(displayText, currentUserPersonalDetails.login ?? '')) { + return Str.removeSMSDomain(displayText); + } + + // Otherwise, the emails must be of the same private domain, so we should remove the domain part + return displayText.split('@')[0]; + }, + [currentUserPersonalDetails.login], + ); + /** * Replace the code of mention and update selection */ @@ -62,7 +82,10 @@ function SuggestionMention( (highlightedMentionIndexInner: number) => { const commentBeforeAtSign = value.slice(0, suggestionValues.atSignIndex); const mentionObject = suggestionValues.suggestedMentions[highlightedMentionIndexInner]; - const mentionCode = mentionObject.text === CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT ? CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT : `@${mentionObject.login}`; + const mentionCode = + mentionObject.text === CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT + ? CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT + : `@${formatLoginPrivateDomain(mentionObject.login, mentionObject.login)}`; const commentAfterMention = value.slice(suggestionValues.atSignIndex + suggestionValues.mentionPrefix.length + 1); updateComment(`${commentBeforeAtSign}${mentionCode} ${SuggestionsUtils.trimLeadingSpace(commentAfterMention)}`, true); @@ -75,7 +98,7 @@ function SuggestionMention( suggestedMentions: [], })); }, - [value, suggestionValues.atSignIndex, suggestionValues.suggestedMentions, suggestionValues.mentionPrefix, updateComment, setSelection], + [value, suggestionValues.atSignIndex, suggestionValues.suggestedMentions, suggestionValues.mentionPrefix, updateComment, setSelection, formatLoginPrivateDomain], ); /** @@ -151,8 +174,8 @@ function SuggestionMention( const sortedPersonalDetails = lodashSortBy(filteredPersonalDetails, (detail) => detail?.displayName || detail?.login); sortedPersonalDetails.slice(0, CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS - suggestions.length).forEach((detail) => { suggestions.push({ - text: PersonalDetailsUtils.getDisplayNameOrDefault(detail), - alternateText: formatPhoneNumber(detail?.login ?? ''), + text: formatLoginPrivateDomain(PersonalDetailsUtils.getDisplayNameOrDefault(detail), detail?.login), + alternateText: `@${formatLoginPrivateDomain(detail?.login, detail?.login)}`, login: detail?.login, icons: [ { @@ -167,7 +190,7 @@ function SuggestionMention( return suggestions; }, - [translate, formatPhoneNumber], + [translate, formatPhoneNumber, formatLoginPrivateDomain], ); const calculateMentionSuggestion = useCallback( diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index ef8629e386d8..03fa78367eda 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -21,7 +21,7 @@ import * as LoginUtils from '@libs/LoginUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import type {MemberForList} from '@libs/OptionsListUtils'; -import {parsePhoneNumber} from '@libs/PhoneNumber'; +import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import type {OptionData} from '@libs/ReportUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; @@ -176,7 +176,7 @@ function WorkspaceInvitePage({ filterSelectedOptions = selectedOptions.filter((option) => { const accountID = option.accountID; const isOptionInPersonalDetails = Object.values(personalDetails).some((personalDetail) => personalDetail.accountID === accountID); - const parsedPhoneNumber = parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchTerm))); + const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchTerm))); const searchValue = parsedPhoneNumber.possible ? parsedPhoneNumber.number?.e164 ?? '' : searchTerm.toLowerCase(); const isPartOfSearchTerm = !!option.text?.toLowerCase().includes(searchValue) || !!option.login?.toLowerCase().includes(searchValue); @@ -274,7 +274,9 @@ function WorkspaceInvitePage({ if ( usersToInvite.length === 0 && excludedUsers.includes( - parsePhoneNumber(LoginUtils.appendCountryCode(searchValue)).possible ? OptionsListUtils.addSMSDomainIfPhoneNumber(LoginUtils.appendCountryCode(searchValue)) : searchValue, + PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(searchValue)).possible + ? PhoneNumber.addSMSDomainIfPhoneNumber(LoginUtils.appendCountryCode(searchValue)) + : searchValue, ) ) { return translate('messages.userIsAlreadyMember', {login: searchValue, name: policyName});