diff --git a/docs/articles/new-expensify/settings/Two-Factor-Authentication.md b/docs/articles/new-expensify/settings/Two-Factor-Authentication.md index 90e1969593769..49545609d4d95 100644 --- a/docs/articles/new-expensify/settings/Two-Factor-Authentication.md +++ b/docs/articles/new-expensify/settings/Two-Factor-Authentication.md @@ -1,35 +1,39 @@ --- title: Two-Factor Authentication (2FA) description: Learn how to set up, use, and recover your Expensify account with two-factor authentication (2FA), including lost device and admin recovery options. -keywords: [Expensify Classic, two-factor authentication, 2FA, login security, authenticator app, recovery codes, locked out, lost phone, account recovery, Domain Admin reset] +keywords: [New Expensify, two-factor authentication, 2FA, login security, authenticator app, recovery codes, locked out, lost phone, account recovery, Domain Admin reset, backup codes. --- -Two-factor authentication (2FA) adds an extra layer of protection to your Expensify account. This guide covers setup, login expectations, recovery steps if you lose access, and admin override options. +Setting up two-factor authentication (2FA) in New Expensify adds an extra layer of protection to your account. This guide explains how to enable 2FA and what to expect if you're ever locked out. --- -# How two-factor authentication works +# Who can use Two-Factor Authentication in Expensify Classic -When logging in: -1. Enter your email and the magic code sent to your inbox. -2. Enter a 6-digit code generated by your authenticator app (such as Google Authenticator, Microsoft Authenticator, or Authy). - -Codes refresh every few seconds. If one expires, simply open the app for a new code. +Anyone can enable Two-Factor Authentication on their own account. Domain admins can also enable Two-Factor Authentication for domains, which forces each domain member to set up Two-Factor Authentication on their account. --- # How to enable two-factor authentication -1. From the left-hand menu, select **Account > Security**. -2. Under **Security options**, select **Two-Factor Authentication**. -3. Follow the prompts to enable 2FA. -4. **Save your backup codes**—these are essential for account recovery. - - Select **Download** to save the codes securely. - - Select **Copy** to paste them into a password manager or secure file. -5. Open your authenticator app and connect it to Expensify by: - - Scanning the QR code, or - - Entering the setup code manually. -6. Enter the 6-digit verification code and select **Verify**. +1. Ensure an authenticator app is installed on your device. +2. From the left-hand menu, select **Account > Security**. +3. Under **Security options**, select **Two-Factor Authentication**. +4. Enable **Two-factor authentication**. +4. Save a copy of your backup codes: + - Click **Download** to save them to your computer. + - Click **Copy** to store them in a secure location. +**Important:** If you lose access to your authenticator app and didn’t save your recovery codes, you may permanently lose access to your account. Consider adding 2FA on multiple devices (e.g., phone and tablet) for backup. +5. Click **Continue**. +6. Open your authenticator app and either: + - Scan the QR code displayed on your screen. + - Enter the 6-digit code from your authenticator app into Expensify and then click **Verify**. + +**Once set up, when logging into Expensify, you will:** +- Receive a Magic Code email to initiate login. +- Be prompted to enter a 6-digit code from your authenticator app. + +If you receive a message that the code is expired, open your authenticator app to get the most recent code. --- @@ -41,46 +45,63 @@ After setup, login requires both: --- -# Recovery options +## For Domain Admins: Reset Two-Factor Authentication for a member + +If a member loses access to their authenticator app or recovery codes, you can reset their 2FA — *but only if*: +- They use a company email on your verified domain, **and** +- You (the Domain Admin) also have 2FA enabled + +To reset a member’s 2FA settings: -Backup recovery codes work like one-time passwords. They are your fastest recovery method if you lose access to your authenticator app. +1. Go to **Settings > Domains > Domain Members**. +2. Click **Edit Settings** for the affected email address. +3. Click **Reset** to disable 2FA. +4. The member can now log in and set up 2FA again. -**Tip:** Store unused recovery codes in a secure, offline location. Each code can only be used once. +If your domain doesn't have 2FA enabled yet: -## If you lost your device and have no recovery codes -- **Individual account**: If you're using a public domain (like gmail.com or outlook.com), you'll need to create a new Expensify account with a different email. Concierge can assist with transferring access to any shared Workspaces. -- **Domain account**: A **Domain Admin** can reset your 2FA. Once reset, you’ll log in normally and set up 2FA again. +1. Go to **Settings > Domains > Domain Members**. +2. Enable **Two-Factor Authentication**. +3. Then follow the steps above to reset 2FA for the member. -# Admin recovery and overrides +**Note** Domain Admin 2FA resets are only available in Expensify Classic. To complete these steps, temporarily [switch to Expensify Classic]([url](https://help.expensify.com/articles/new-expensify/settings/Switch-between-New-Expensify-and-Expensify-Classic.html)). -## If a Domain Admin is available -- Domain Admins can reset a member’s 2FA by going to: - **Settings > Domains > [Domain Name] > Members > Security Settings** -- Select the member, then disable their 2FA. +--- + +## What to do if you're locked out because of Two-Factor Authentication -## If the enforcing Domain Admin has left -1. Verify domain ownership by proving control of the domain’s email DNS or MX records. -2. Assign a new Domain Admin in **Settings > Domains > [Domain Name] > Domain Settings**. -3. Once the new admin is assigned, follow the steps above to reset 2FA for affected members. +If you can’t access your authenticator app and don’t have your recovery codes, contact your Domain Admin to reset your 2FA. -# Best practices +If no Domain Admin is available and you're using a company email, you can follow [this guide](https://help.expensify.com/articles/new-expensify/workspaces/Claim-and-Verify-a-Domain) to claim the domain and reset your 2FA settings yourself. -- Save your recovery codes as soon as you set up 2FA. -- Consider adding 2FA on multiple devices (e.g., phone and tablet) during setup for backup. -- Keep your device’s clock set to the correct time—codes depend on accurate timing. +For more help regaining access, see [Troubleshoot login issues](LINK). --- # FAQ -## Why should I use 2FA? -It prevents unauthorized access, even if someone has your login email or password. +## How does 2FA change how I log into my account? + +Setting up two-factor authentication (2FA) adds an extra layer of security to protect your Expensify Account. When you log in, you must enter a code generated by your preferred authenticator app (such as Google Authenticator or Microsoft Authenticator). + +## How does 2FA work? + +Expensify's 2FA is implemented via a Time-based One-Time Password (TOTP) algorithm. Each time you log in, you must use an authenticator app to generate a unique 6-digit code, adding a second “factor” to your login. + +## What can I do if I can't access my authenticator app? + +When you enable 2FA, you are prompted to either copy or download backup codes which you can use in lieu of the 6-digit authenticator code. If you downloaded the codes they will be saved with the file name `two-factor-auth-codes`. + +If you are unable to access the codes, see [Troubleshoot login issues](LINK) for instructions. + +## What authenticator apps does Expensify recommend? -## What if I lose my phone or uninstall the app? -Use a recovery code to log in, then disable and re-enable 2FA on your new device. +You can use any authenticator app, but here are a few we recommend: -## Can I use 2FA on more than one device? -Yes. Scan the setup QR code with multiple devices when enabling 2FA. +- [1Password](https://support.1password.com/one-time-passwords/) +- [Authy](https://authy.com/) +- [Google Authenticator](https://support.google.com/accounts/answer/1066447) +- [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app) ## What if my verification code isn’t working? -Check your device’s time settings. Authenticator apps rely on accurate system clocks. +Make sure your device’s clock is set to update automatically. Authenticator apps rely on your system clock being accurate, and even a small time difference can cause verification codes to fail. diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index aa90f4a0a721a..5a3014b9b7087 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -377,7 +377,7 @@ function MoneyRequestView({ (isExpenseUnreported && (!policyForMovingExpenses || hasEnabledOptions(policyCategories ?? {}))); // transactionTag can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const shouldShowTag = (isPolicyExpenseChat || isExpenseUnreported) && (transactionTag || hasEnabledTags(policyTagLists)); + const shouldShowTag = (isPolicyExpenseChat || isExpenseUnreported) && (transactionTag || (canEdit && hasEnabledTags(policyTagLists))); const shouldShowBillable = (isPolicyExpenseChat || isExpenseUnreported) && (!!transactionBillable || !(policy?.disabledFields?.defaultBillable ?? true) || !!updatedTransaction?.billable); const isCurrentTransactionReimbursableDifferentFromPolicyDefault = @@ -721,7 +721,7 @@ function MoneyRequestView({ } } } else { - shouldShow = !!tagForDisplay || hasEnabledOptions(tags); + shouldShow = !!tagForDisplay || (canEdit && hasEnabledOptions(tags)); } if (!shouldShow) { diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 6a360a4d0e5fb..3352e3e68bc09 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -4,7 +4,7 @@ import {Str} from 'expensify-common'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import type {LocaleContextProps} from '@components/LocaleContextProvider'; +import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type { @@ -357,7 +357,13 @@ function getMoneyRequestReportName({report, policy, invoiceReceiverPolicy}: {rep return payerPaidAmountMessage; } -function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, report?: Report, reportPolicy?: Policy, parentReport?: Report): string | undefined { +function computeReportNameBasedOnReportAction( + translate: LocalizedTranslate, + parentReportAction?: ReportAction, + report?: Report, + reportPolicy?: Policy, + parentReport?: Report, +): string | undefined { if (!parentReportAction) { return undefined; } @@ -368,32 +374,26 @@ function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, ) { const harvesting = !isMarkAsClosedAction(parentReportAction) ? (getOriginalMessage(parentReportAction)?.harvesting ?? false) : false; if (harvesting) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.automaticallySubmitted'); + return translate('iou.automaticallySubmitted'); } - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.submitted', {memo: getOriginalMessage(parentReportAction)?.message}); + return translate('iou.submitted', {memo: getOriginalMessage(parentReportAction)?.message}); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { const {automaticAction} = getOriginalMessage(parentReportAction) ?? {}; if (automaticAction) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.automaticallyForwarded'); + return translate('iou.automaticallyForwarded'); } - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.forwarded'); + return translate('iou.forwarded'); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { return getRejectedReportMessage(); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RETRACTED) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.retracted'); + return translate('iou.retracted'); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REOPENED) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.reopened'); + return translate('iou.reopened'); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.CORPORATE_UPGRADE) { return getUpgradeWorkspaceMessage(); @@ -402,35 +402,28 @@ function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, return getDowngradeWorkspaceMessage(); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_CURRENCY) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceCurrencyUpdateMessage(translateLocal, parentReportAction); + return getWorkspaceCurrencyUpdateMessage(translate, parentReportAction); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_FIELD) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceUpdateFieldMessage(translateLocal, parentReportAction); + return getWorkspaceUpdateFieldMessage(translate, parentReportAction); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('systemMessage.mergedWithCashTransaction'); + return translate('systemMessage.mergedWithCashTransaction'); } 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) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceFrequencyUpdateMessage(translateLocal, parentReportAction); + return getWorkspaceFrequencyUpdateMessage(translate, parentReportAction); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.ADD_REPORT_FIELD) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceReportFieldAddMessage(translateLocal, parentReportAction); + return getWorkspaceReportFieldAddMessage(translate, parentReportAction); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_REPORT_FIELD) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceReportFieldUpdateMessage(translateLocal, parentReportAction); + return getWorkspaceReportFieldUpdateMessage(translate, parentReportAction); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.DELETE_REPORT_FIELD) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceReportFieldDeleteMessage(translateLocal, parentReportAction); + return getWorkspaceReportFieldDeleteMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION)) { @@ -438,17 +431,14 @@ function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT_NO_RECEIPT)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getPolicyChangeLogMaxExpenseAmountNoReceiptMessage(translateLocal, parentReportAction); + return getPolicyChangeLogMaxExpenseAmountNoReceiptMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_BILLABLE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getPolicyChangeLogDefaultBillableMessage(translateLocal, parentReportAction); + return getPolicyChangeLogDefaultBillableMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_REIMBURSABLE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getPolicyChangeLogDefaultReimbursableMessage(translateLocal, parentReportAction); + return getPolicyChangeLogDefaultReimbursableMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT)) { // eslint-disable-next-line @typescript-eslint/no-deprecated @@ -459,17 +449,14 @@ function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, return getPolicyChangeLogMaxExpenseAgeMessage(translateLocal, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_TITLE_ENFORCED)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getPolicyChangeLogDefaultTitleEnforcedMessage(translateLocal, parentReportAction); + return getPolicyChangeLogDefaultTitleEnforcedMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DEFAULT_TITLE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getPolicyChangeLogDefaultTitleMessage(translateLocal, parentReportAction); + return getPolicyChangeLogDefaultTitleMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT) && getOriginalMessage(parentReportAction)?.resolution) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getActionableCardFraudAlertResolutionMessage(translateLocal, parentReportAction); + return getActionableCardFraudAlertResolutionMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED)) { @@ -500,24 +487,19 @@ function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, if (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.paidElsewhere'); + return translate('iou.paidElsewhere'); } if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { if (originalMessage.automaticAction) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.automaticallyPaidWithBusinessBankAccount', undefined, last4Digits); + return translate('iou.automaticallyPaidWithBusinessBankAccount', undefined, last4Digits); } - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.businessBankAccount', undefined, last4Digits); + return translate('iou.businessBankAccount', undefined, last4Digits); } if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { if (originalMessage.automaticAction) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.automaticallyPaidWithExpensify'); + return translate('iou.automaticallyPaidWithExpensify'); } - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.paidWithExpensify'); + return translate('iou.paidWithExpensify'); } } } @@ -525,60 +507,55 @@ function computeReportNameBasedOnReportAction(parentReportAction?: ReportAction, if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) { const {automaticAction} = getOriginalMessage(parentReportAction) ?? {}; if (automaticAction) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.automaticallyApproved'); + return translate('iou.automaticallyApproved'); } - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.approvedMessage'); + return translate('iou.approvedMessage'); } if (isUnapprovedAction(parentReportAction)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('iou.unapproved'); + return translate('iou.unapproved'); } if (isActionableJoinRequest(parentReportAction)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getJoinRequestMessage(translateLocal, parentReportAction); + return getJoinRequestMessage(translate, parentReportAction); } if (isTaskReport(report) && isCanceledTaskReport(report, parentReportAction)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('parentReportAction.deletedTask'); + return translate('parentReportAction.deletedTask'); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.INTEGRATION_SYNC_FAILED)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getIntegrationSyncFailedMessage(translateLocal, parentReportAction, report?.policyID); + return getIntegrationSyncFailedMessage(translate, parentReportAction, report?.policyID); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.COMPANY_CARD_CONNECTION_BROKEN)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getCompanyCardConnectionBrokenMessage(translateLocal, parentReportAction); + return getCompanyCardConnectionBrokenMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.TRAVEL_UPDATE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getTravelUpdateMessage(translateLocal, parentReportAction); + return getTravelUpdateMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.ADD_CUSTOM_UNIT_RATE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceCustomUnitRateAddedMessage(translateLocal, parentReportAction); + return getWorkspaceCustomUnitRateAddedMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_CUSTOM_UNIT_RATE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceCustomUnitRateUpdatedMessage(translateLocal, parentReportAction); + return getWorkspaceCustomUnitRateUpdatedMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.DELETE_CUSTOM_UNIT_RATE)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getWorkspaceCustomUnitRateDeletedMessage(translateLocal, parentReportAction); + return getWorkspaceCustomUnitRateDeletedMessage(translate, parentReportAction); } return undefined; } -function computeChatThreadReportName(report: Report, reportNameValuePairs: ReportNameValuePairs, reports: OnyxCollection, parentReportAction?: ReportAction): string | undefined { +function computeChatThreadReportName( + translate: LocalizedTranslate, + report: Report, + reportNameValuePairs: ReportNameValuePairs, + reports: OnyxCollection, + parentReportAction?: ReportAction, +): string | undefined { if (!isChatThread(report)) { return undefined; } @@ -599,39 +576,33 @@ function computeChatThreadReportName(report: Report, reportNameValuePairs: Repor } if (!isEmptyObject(parentReportAction) && isOldDotReportAction(parentReportAction)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getMessageOfOldDotReportAction(translateLocal, parentReportAction); + return getMessageOfOldDotReportAction(translate, parentReportAction); } if (isRenamedAction(parentReportAction)) { const parent = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getRenamedAction(translateLocal, parentReportAction, isExpenseReport(parent)); + return getRenamedAction(translate, parentReportAction, isExpenseReport(parent)); } if (parentReportActionMessage?.isDeletedParentAction) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('parentReportAction.deletedMessage'); + return translate('parentReportAction.deletedMessage'); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RESOLVED_DUPLICATES) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('violations.resolvedDuplicates'); + return translate('violations.resolvedDuplicates'); } const isAttachment = isReportActionAttachment(!isEmptyObject(parentReportAction) ? parentReportAction : undefined); const reportActionMessage = getReportActionText(parentReportAction).replaceAll(/(\n+|\r\n|\n|\r)/gm, ' '); if (isAttachment && reportActionMessage) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return `[${translateLocal('common.attachment')}]`; + return `[${translate('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 ) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return translateLocal('parentReportAction.hiddenMessage'); + return translate('parentReportAction.hiddenMessage'); } if (isAdminRoom(report) || isUserCreatedPolicyRoom(report)) { return reportActionMessage; @@ -657,8 +628,7 @@ function computeChatThreadReportName(report: Report, reportNameValuePairs: Repor return report?.reportName ?? ''; } if (isCardIssuedAction(parentReportAction)) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - return getCardIssuedMessage({reportAction: parentReportAction, translate: translateLocal}); + return getCardIssuedMessage({reportAction: parentReportAction, translate}); } return reportActionMessage; } @@ -685,7 +655,8 @@ function computeReportName( const parentReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; const parentReportAction = isThread(report) ? reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.parentReportID}`]?.[report.parentReportActionID] : undefined; - const parentReportActionBasedName = computeReportNameBasedOnReportAction(parentReportAction, report, reportPolicy, parentReport); + // eslint-disable-next-line @typescript-eslint/no-deprecated + const parentReportActionBasedName = computeReportNameBasedOnReportAction(translateLocal, parentReportAction, report, reportPolicy, parentReport); if (parentReportActionBasedName) { return parentReportActionBasedName; @@ -695,7 +666,8 @@ function computeReportName( return Parser.htmlToText(report?.reportName ?? '').trim(); } - const chatThreadReportName = computeChatThreadReportName(report, reportNameValuePairs ?? {}, reports ?? {}, parentReportAction); + // eslint-disable-next-line @typescript-eslint/no-deprecated + const chatThreadReportName = computeChatThreadReportName(translateLocal, report, reportNameValuePairs ?? {}, reports ?? {}, parentReportAction); if (chatThreadReportName) { return chatThreadReportName; } diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 526a3170b9844..953530b3273d4 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -20,7 +20,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; -import {inviteToRoomAction, searchInServer} from '@libs/actions/Report'; +import {inviteToRoom, inviteToRoomAction, searchInServer} from '@libs/actions/Report'; import {clearUserSearchPhrase, updateUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; import {READ_COMMANDS} from '@libs/API/types'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; @@ -38,7 +38,7 @@ import type {MemberEmailsToAccountIDs} from '@libs/PolicyUtils'; import {isPolicyEmployee as isPolicyEmployeeUtil} from '@libs/PolicyUtils'; import {getReportAction} from '@libs/ReportActionsUtils'; import type {OptionData} from '@libs/ReportUtils'; -import {getReportName, isHiddenForCurrentUser} from '@libs/ReportUtils'; +import {getReportName, isHiddenForCurrentUser, isPolicyExpenseChat} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -60,7 +60,7 @@ function RoomInvitePage({ }, }: RoomInvitePageProps) { const styles = useThemeStyles(); - const {translate} = useLocalize(); + const {translate, formatPhoneNumber} = useLocalize(); const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE, {canBeMissing: true}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); @@ -206,7 +206,7 @@ function RoomInvitePage({ const ancestors = useAncestors(report); - const inviteUsers = useCallback(() => { + const inviteUsers = () => { HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); if (!validate()) { @@ -222,7 +222,11 @@ function RoomInvitePage({ invitedEmailsToAccountIDs[login] = Number(accountID); } if (report?.reportID) { - inviteToRoomAction(report, ancestors, invitedEmailsToAccountIDs, currentUserPersonalDetails.timezone ?? CONST.DEFAULT_TIME_ZONE); + if (isPolicyExpenseChat(report)) { + inviteToRoomAction(report, ancestors, invitedEmailsToAccountIDs, currentUserPersonalDetails.timezone ?? CONST.DEFAULT_TIME_ZONE); + } else { + inviteToRoom(reportID, invitedEmailsToAccountIDs, formatPhoneNumber); + } clearUserSearchPhrase(); if (backTo) { Navigation.goBack(backTo); @@ -230,7 +234,7 @@ function RoomInvitePage({ Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(report.reportID)); } } - }, [validate, selectedOptions, ancestors, report, currentUserPersonalDetails.timezone, backTo]); + }; const goBack = useCallback(() => { Navigation.goBack(backRoute);