diff --git a/src/languages/en.ts b/src/languages/en.ts
index 506ecd43cc1c..6328ea0612f3 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1824,6 +1824,9 @@ const translations = {
onceTheAbove: 'Once the above steps are completed, please reach out to ',
toUnblock: ' to unblock your login.',
},
+ smsDeliveryFailurePage: {
+ smsDeliveryFailureMessage: ({login}: OurEmailProviderParams) => `We've been unable to deliver SMS messages to ${login}, so we've suspended it for 24 hours.`,
+ },
welcomeSignUpForm: {
join: 'Join',
},
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 740dac086587..b80100e590e1 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1829,6 +1829,9 @@ const translations = {
onceTheAbove: 'Una vez completados los pasos anteriores, ponte en contacto con ',
toUnblock: ' para desbloquear el inicio de sesiĆ³n.',
},
+ smsDeliveryFailurePage: {
+ smsDeliveryFailureMessage: ({login}: OurEmailProviderParams) => `No hemos podido entregar mensajes SMS a ${login}, por lo que lo hemos suspendido durante 24 horas.`,
+ },
welcomeSignUpForm: {
join: 'Unirse',
},
diff --git a/src/pages/signin/SMSDeliveryFailurePage.tsx b/src/pages/signin/SMSDeliveryFailurePage.tsx
new file mode 100644
index 000000000000..86f4f9959d8b
--- /dev/null
+++ b/src/pages/signin/SMSDeliveryFailurePage.tsx
@@ -0,0 +1,68 @@
+import {Str} from 'expensify-common';
+import React, {useEffect, useMemo} from 'react';
+import {Keyboard, View} from 'react-native';
+import {useOnyx} from 'react-native-onyx';
+import Button from '@components/Button';
+import Text from '@components/Text';
+import useKeyboardState from '@hooks/useKeyboardState';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink';
+import Terms from './Terms';
+
+function SMSDeliveryFailurePage() {
+ const styles = useThemeStyles();
+ const {isKeyboardShown} = useKeyboardState();
+ const {translate} = useLocalize();
+ const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS);
+ const [account] = useOnyx(ONYXKEYS.ACCOUNT);
+
+ const login = useMemo(() => {
+ if (!credentials?.login) {
+ return '';
+ }
+ return Str.isSMSLogin(credentials.login) ? Str.removeSMSDomain(credentials.login) : credentials.login;
+ }, [credentials?.login]);
+
+ const SMSDeliveryFailureMessage = account?.SMSDeliveryFailureStatus?.message;
+
+ useEffect(() => {
+ if (!isKeyboardShown) {
+ return;
+ }
+ Keyboard.dismiss();
+ }, [isKeyboardShown]);
+
+ return (
+ <>
+
+
+
+ {translate('smsDeliveryFailurePage.smsDeliveryFailureMessage', {login})} {SMSDeliveryFailureMessage}
+
+
+
+
+
+
+ Session.clearSignInData()} />
+
+
+
+
+ >
+ );
+}
+
+SMSDeliveryFailurePage.displayName = 'SMSDeliveryFailurePage';
+
+export default SMSDeliveryFailurePage;
diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx
index e257efcce828..ce16bf0cd823 100644
--- a/src/pages/signin/SignInPage.tsx
+++ b/src/pages/signin/SignInPage.tsx
@@ -1,8 +1,8 @@
import {Str} from 'expensify-common';
import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react';
-import type {ForwardedRef, RefAttributes} from 'react';
-import {withOnyx} from 'react-native-onyx';
+import type {ForwardedRef} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
+import {useOnyx} from 'react-native-onyx';
import ColorSchemeWrapper from '@components/ColorSchemeWrapper';
import CustomStatusBarAndBackground from '@components/CustomStatusBarAndBackground';
import ScreenWrapper from '@components/ScreenWrapper';
@@ -24,7 +24,7 @@ import * as Session from '@userActions/Session';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
-import type {Account, Credentials, Locale} from '@src/types/onyx';
+import type {Account, Credentials} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import ChooseSSOOrMagicCode from './ChooseSSOOrMagicCode';
import EmailDeliveryFailurePage from './EmailDeliveryFailurePage';
@@ -33,25 +33,12 @@ import type {InputHandle} from './LoginForm/types';
import SignInPageLayout from './SignInPageLayout';
import type {SignInPageLayoutRef} from './SignInPageLayout/types';
import SignUpWelcomeForm from './SignUpWelcomeForm';
+import SMSDeliveryFailurePage from './SMSDeliveryFailurePage';
import UnlinkLoginForm from './UnlinkLoginForm';
import ValidateCodeForm from './ValidateCodeForm';
import type {BaseValidateCodeFormRef} from './ValidateCodeForm/BaseValidateCodeForm';
-type SignInPageInnerOnyxProps = {
- /** The details about the account that the user is signing in with */
- account: OnyxEntry;
-
- /** The credentials of the person signing in */
- credentials: OnyxEntry;
-
- /** Active Clients connected to ONYX Database */
- activeClients: OnyxEntry;
-
- /** The user's preferred locale */
- preferredLocale: OnyxEntry;
-};
-
-type SignInPageInnerProps = SignInPageInnerOnyxProps & {
+type SignInPageInnerProps = {
shouldEnableMaxHeight?: boolean;
};
@@ -62,6 +49,7 @@ type SignInPageRef = {
type RenderOption = {
shouldShowLoginForm: boolean;
shouldShowEmailDeliveryFailurePage: boolean;
+ shouldShowSMSDeliveryFailurePage: boolean;
shouldShowUnlinkLoginForm: boolean;
shouldShowValidateCodeForm: boolean;
shouldShowChooseSSOOrMagicCode: boolean;
@@ -90,6 +78,7 @@ type GetRenderOptionsParams = {
* @param isUsingMagicCode
* @param hasInitiatedSAMLLogin
* @param hasEmailDeliveryFailure
+ * @param hasSMSDeliveryFailure
*/
function getRenderOptions({
hasLogin,
@@ -105,6 +94,7 @@ function getRenderOptions({
const isSAMLEnabled = !!account?.isSAMLEnabled;
const isSAMLRequired = !!account?.isSAMLRequired;
const hasEmailDeliveryFailure = !!account?.hasEmailDeliveryFailure;
+ const hasSMSDeliveryFailure = !!account?.SMSDeliveryFailureStatus?.hasSMSDeliveryFailure;
// True, if the user has SAML required, and we haven't yet initiated SAML for their account
const shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && !!account.isLoading;
@@ -121,13 +111,15 @@ function getRenderOptions({
const shouldShouldSignUpWelcomeForm = !!credentials?.login && !account?.validated && !account?.accountExists && !account?.domainControlled;
const shouldShowLoginForm = !shouldShowAnotherLoginPageOpenedMessage && !hasLogin && !hasValidateCode;
const shouldShowEmailDeliveryFailurePage = hasLogin && hasEmailDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin;
- const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !account?.validated && !hasEmailDeliveryFailure;
+ const shouldShowSMSDeliveryFailurePage = hasLogin && hasSMSDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin;
+ const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !account?.validated && !hasEmailDeliveryFailure && !hasSMSDeliveryFailure;
const shouldShowValidateCodeForm =
!shouldShouldSignUpWelcomeForm &&
hasAccount &&
(hasLogin || hasValidateCode) &&
!isUnvalidatedSecondaryLogin &&
!hasEmailDeliveryFailure &&
+ !hasSMSDeliveryFailure &&
!shouldShowChooseSSOOrMagicCode &&
!isSAMLRequired;
const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowValidateCodeForm || shouldShowChooseSSOOrMagicCode || isUnvalidatedSecondaryLogin || shouldShouldSignUpWelcomeForm;
@@ -137,6 +129,7 @@ function getRenderOptions({
return {
shouldShowLoginForm,
shouldShowEmailDeliveryFailurePage,
+ shouldShowSMSDeliveryFailurePage,
shouldShowUnlinkLoginForm: !shouldShouldSignUpWelcomeForm && isUnvalidatedSecondaryLogin,
shouldShowValidateCodeForm,
shouldShowChooseSSOOrMagicCode,
@@ -147,7 +140,7 @@ function getRenderOptions({
};
}
-function SignInPage({credentials, account, activeClients = [], preferredLocale, shouldEnableMaxHeight = true}: SignInPageInnerProps, ref: ForwardedRef) {
+function SignInPage({shouldEnableMaxHeight = true}: SignInPageInnerProps, ref: ForwardedRef) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {translate, formatPhoneNumber} = useLocalize();
@@ -157,6 +150,18 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,
const loginFormRef = useRef(null);
const validateCodeFormRef = useRef(null);
+ const [account] = useOnyx(ONYXKEYS.ACCOUNT);
+ const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS);
+ /**
+ This variable is only added to make sure the component is re-rendered
+ whenever the activeClients change, so that we call the
+ ActiveClientManager.isClientTheLeader function
+ everytime the leader client changes.
+ We use that function to prevent repeating code that checks which client is the leader.
+ */
+ const [activeClients = []] = useOnyx(ONYXKEYS.ACTIVE_CLIENTS);
+ const [preferredLocale] = useOnyx(ONYXKEYS.NVP_PREFERRED_LOCALE);
+
/** This state is needed to keep track of if user is using recovery code instead of 2fa code,
* and we need it here since welcome text(`welcomeText`) also depends on it */
const [isUsingRecoveryCode, setIsUsingRecoveryCode] = useState(false);
@@ -200,6 +205,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,
const {
shouldShowLoginForm,
shouldShowEmailDeliveryFailurePage,
+ shouldShowSMSDeliveryFailurePage,
shouldShowUnlinkLoginForm,
shouldShowValidateCodeForm,
shouldShowChooseSSOOrMagicCode,
@@ -249,11 +255,11 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,
? `${translate('welcomeText.welcome')} ${translate('welcomeText.welcomeEnterMagicCode', {login: userLoginToDisplay})}`
: translate('welcomeText.welcomeEnterMagicCode', {login: userLoginToDisplay});
}
- } else if (shouldShowUnlinkLoginForm || shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode) {
+ } else if (shouldShowUnlinkLoginForm || shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode || shouldShowSMSDeliveryFailurePage) {
welcomeHeader = shouldUseNarrowLayout ? headerText : translate('welcomeText.welcome');
// Don't show any welcome text if we're showing the user the email delivery failed view
- if (shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode) {
+ if (shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode || shouldShowSMSDeliveryFailurePage) {
welcomeText = '';
}
} else if (shouldShouldSignUpWelcomeForm) {
@@ -273,7 +279,8 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,
const navigateBack = () => {
if (
shouldShouldSignUpWelcomeForm ||
- (!shouldShowAnotherLoginPageOpenedMessage && (shouldShowEmailDeliveryFailurePage || shouldShowUnlinkLoginForm || shouldShowChooseSSOOrMagicCode))
+ (!shouldShowAnotherLoginPageOpenedMessage &&
+ (shouldShowEmailDeliveryFailurePage || shouldShowUnlinkLoginForm || shouldShowChooseSSOOrMagicCode || shouldShowSMSDeliveryFailurePage))
) {
Session.clearSignInData();
return;
@@ -331,6 +338,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,
{shouldShowUnlinkLoginForm && }
{shouldShowChooseSSOOrMagicCode && }
{shouldShowEmailDeliveryFailurePage && }
+ {shouldShowSMSDeliveryFailurePage && }
>
)}
@@ -339,7 +347,6 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,
}
type SignInPageProps = SignInPageInnerProps;
-type SignInPageOnyxProps = SignInPageInnerOnyxProps;
const SignInPageWithRef = forwardRef(SignInPage);
function SignInPageThemeWrapper(props: SignInPageProps, ref: ForwardedRef) {
@@ -361,20 +368,6 @@ function SignInPageThemeWrapper(props: SignInPageProps, ref: ForwardedRef, SignInPageOnyxProps>({
- account: {key: ONYXKEYS.ACCOUNT},
- credentials: {key: ONYXKEYS.CREDENTIALS},
- /**
- This variable is only added to make sure the component is re-rendered
- whenever the activeClients change, so that we call the
- ActiveClientManager.isClientTheLeader function
- everytime the leader client changes.
- We use that function to prevent repeating code that checks which client is the leader.
- */
- activeClients: {key: ONYXKEYS.ACTIVE_CLIENTS},
- preferredLocale: {
- key: ONYXKEYS.NVP_PREFERRED_LOCALE,
- },
-})(forwardRef(SignInPageThemeWrapper));
+export default forwardRef(SignInPageThemeWrapper);
export type {SignInPageRef};
diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts
index 3902d67882c4..0337359e45b2 100644
--- a/src/types/onyx/Account.ts
+++ b/src/types/onyx/Account.ts
@@ -60,6 +60,15 @@ type DelegatedAccess = {
errorFields?: DelegateErrors;
};
+/** Model of SMS delivery failure status */
+type SMSDeliveryFailureStatus = {
+ /** Whether the account is having trouble receiving SMS */
+ hasSMSDeliveryFailure: boolean;
+
+ /** The message associated with the SMS delivery failure */
+ message: string;
+};
+
/** Model of user account */
type Account = {
/** Whether SAML is enabled for the current account */
@@ -145,6 +154,9 @@ type Account = {
/** The users you can access as delegate and the users who can access your account as a delegate */
delegatedAccess?: DelegatedAccess;
+
+ /** Indicates SMS delivery failure status and associated information */
+ SMSDeliveryFailureStatus?: SMSDeliveryFailureStatus;
};
export default Account;