Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EmailDeliveryFailure view #19508

Merged
merged 37 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
bd9e3d4
add copy for email delivery failure
NikkiWines May 24, 2023
3bd5084
add email delivery page to signin logic
NikkiWines May 24, 2023
9a8cc3f
style and consistentcy
NikkiWines May 24, 2023
7c0de29
add emailDeliveryFailurePage
NikkiWines May 24, 2023
387126c
Merge branch 'main' of https://github.com/Expensify/App into nikki-em…
NikkiWines Jun 2, 2023
6815b15
Merge branch 'main' of https://github.com/Expensify/App into nikki-em…
NikkiWines Jun 2, 2023
e4dfed5
update copy
NikkiWines Jun 2, 2023
1cdc46b
update styling for emaildeliveryfailure view
NikkiWines Jun 2, 2023
5c23dfb
ensure we show the correct header
NikkiWines Jun 2, 2023
f84803f
jsx style
NikkiWines Jun 2, 2023
52051ff
prettier style
NikkiWines Jun 2, 2023
fb0b480
remove out of date comment
NikkiWines Jun 2, 2023
1ae9bbe
Merge branch 'main' of https://github.com/Expensify/App into nikki-em…
NikkiWines Jun 2, 2023
9a2a4e3
update english copy
NikkiWines Jun 6, 2023
07ac55d
add spanish copy
NikkiWines Jun 6, 2023
3e0f91b
use presablewithfeedback instead of touchable opacity
NikkiWines Jun 7, 2023
400bc6f
Merge branch 'main' of https://github.com/Expensify/App into nikki-em…
NikkiWines Jun 7, 2023
a66dd2c
fix imports
NikkiWines Jun 7, 2023
5fc8e29
Update emailDeliveryFailure logic to match new function component sty…
NikkiWines Jun 12, 2023
dc7ab26
function docs, prop validation, minor style
NikkiWines Jun 12, 2023
f2c881d
typo
NikkiWines Jun 12, 2023
51615f1
prettier style
NikkiWines Jun 12, 2023
cee46c3
Merge branch 'main' of github.com:Expensify/App into nikki-emaildeliv…
NikkiWines Jul 3, 2023
3e91861
update function declaration
NikkiWines Jul 4, 2023
f1ba8b7
update display name, getRenderOptions(), and welcomeText for email de…
NikkiWines Jul 5, 2023
3e91187
Merge branch 'main' of github.com:Expensify/App into nikki-emaildeliv…
NikkiWines Jul 5, 2023
aba7d1f
prettier style
NikkiWines Jul 5, 2023
a99ab23
Merge branch 'main' of github.com:Expensify/App into nikki-emaildeliv…
NikkiWines Jul 8, 2023
184fced
re-add missing param
NikkiWines Jul 8, 2023
e56a2c6
prettier
NikkiWines Jul 8, 2023
c9495f6
Merge branch 'main' of github.com:Expensify/App into nikki-emaildeliv…
NikkiWines Jul 10, 2023
b172a23
use useLocalize instead of withLocalize
NikkiWines Jul 10, 2023
6239059
don't use compose for single export
NikkiWines Jul 10, 2023
1906916
remove unused import
NikkiWines Jul 10, 2023
952892b
dismiss keyboard on email delivery failure page
NikkiWines Jul 11, 2023
b070b9b
lint errors
NikkiWines Jul 11, 2023
019e919
add clarifying comments
NikkiWines Jul 11, 2023
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
10 changes: 10 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,16 @@ export default {
linkSent: 'Link sent!',
succesfullyUnlinkedLogin: 'Secondary login successfully unlinked!',
},
emailDeliveryFailurePage: {
ourEmailProvider: ({login}) => `Our email provider has temporarily suspended emails to ${login} due to delivery issues. To unblock your login, please follow these steps:`,
confirmThat: ({login}) => `Confirm that ${login} is spelled correctly and is a real, deliverable email address. `,
emailAliases: 'Email aliases such as "[email protected]" must have access to their own email inbox for it to be a valid Expensify login.',
ensureYourEmailClient: 'Ensure your email client allows expensify.com emails. ',
youCanFindDirections: 'You can find directions on how to complete this step ',
helpConfigure: ' but you may need your IT department to help configure your email settings.',
onceTheAbove: 'Once the above steps are completed, please reach out to ',
toUnblock: ' to unblock your login.',
},
detailsPage: {
localTime: 'Local time',
},
Expand Down
12 changes: 12 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,18 @@ export default {
linkSent: '¡Enlace enviado!',
succesfullyUnlinkedLogin: '¡Nombre de usuario secundario desvinculado correctamente!',
},
emailDeliveryFailurePage: {
ourEmailProvider: ({login}) =>
`Nuestro proveedor de correo electrónico ha suspendido temporalmente los correos electrónicos a ${login} debido a problemas de entrega. Para desbloquear el inicio de sesión, sigue estos pasos:`,
confirmThat: ({login}) => `Confirma que ${login} está escrito correctamente y que es una dirección de correo electrónico real que puede recibir correos. `,
emailAliases:
'Los alias de correo electrónico como "[email protected]" deben tener acceso a su propia bandeja de entrada de correo electrónico para que sea un inicio de sesión válido de Expensify.',
ensureYourEmailClient: 'Asegúrese de que su cliente de correo electrónico permita correos electrónicos de expensify.com. ',
youCanFindDirections: 'Puedes encontrar instrucciones sobre cómo completar este paso ',
helpConfigure: ', pero es posible que necesites que el departamento de informática te ayude a configurar los ajustes de correo electrónico.',
onceTheAbove: 'Una vez completados los pasos anteriores, ponte en contacto con ',
toUnblock: ' para desbloquear el inicio de sesión.',
},
detailsPage: {
localTime: 'Hora local',
},
Expand Down
97 changes: 97 additions & 0 deletions src/pages/signin/EmailDeliveryFailurePage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, {useEffect} from 'react';
import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
import styles from '../../styles/styles';
import Text from '../../components/Text';
import TextLink from '../../components/TextLink';
import ONYXKEYS from '../../ONYXKEYS';
import useLocalize from '../../hooks/useLocalize';
import useKeyboardState from '../../hooks/useKeyboardState';
import redirectToSignIn from '../../libs/actions/SignInRedirect';
import CONST from '../../CONST';
import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';

const propTypes = {
/* Onyx Props */

/** The credentials of the logged in person */
credentials: PropTypes.shape({
/** The email/phone the user logged in with */
login: PropTypes.string,
}),
};

const defaultProps = {
credentials: {},
};

function EmailDeliveryFailurePage(props) {
const {isKeyboardShown} = useKeyboardState();
const {translate} = useLocalize();
const login = Str.isSMSLogin(props.credentials.login) ? Str.removeSMSDomain(props.credentials.login) : props.credentials.login;

// This view doesn't have a field for user input, so dismiss the device keyboard if shown
useEffect(() => {
if (!isKeyboardShown) {
return;
}
Keyboard.dismiss();
}, [isKeyboardShown]);
Comment on lines +36 to +41
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's add a comment why this was added, as it look unnecessary here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!


return (
<>
<View style={[styles.mv3, styles.flexRow, styles.justifyContentetween]}>
<View style={[styles.flex1]}>
<Text>{translate('emailDeliveryFailurePage.ourEmailProvider', {login})}</Text>
<Text style={[styles.mt5]}>
<Text style={[styles.textStrong]}>{translate('emailDeliveryFailurePage.confirmThat', {login})}</Text>
{translate('emailDeliveryFailurePage.emailAliases')}
</Text>
<Text style={[styles.mt5]}>
<Text style={[styles.textStrong]}>{translate('emailDeliveryFailurePage.ensureYourEmailClient')}</Text>
{translate('emailDeliveryFailurePage.youCanFindDirections')}
<TextLink
href="https://community.expensify.com/discussion/5651/deep-dive-best-practices-when-youre-running-into-trouble-receiving-emails-from-expensify/p1?new=1"
style={[styles.link]}
>
{translate('common.here')}
</TextLink>
{translate('emailDeliveryFailurePage.helpConfigure')}
</Text>
<Text style={styles.mt5}>
{translate('emailDeliveryFailurePage.onceTheAbove')}
<TextLink
href={`mailto:${CONST.EMAIL.CONCIERGE}`}
style={[styles.link]}
>
{CONST.EMAIL.CONCIERGE}
</TextLink>
{translate('emailDeliveryFailurePage.toUnblock')}
</Text>
</View>
</View>
<View style={[styles.mv4, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter]}>
<PressableWithFeedback
onPress={() => redirectToSignIn()}
accessibilityRole="button"
accessibilityLabel={translate('common.back')}
// disable hover dim for switch
hoverDimmingValue={1}
pressDimmingValue={0.2}
>
<Text style={[styles.link]}>{translate('common.back')}</Text>
</PressableWithFeedback>
</View>
</>
);
}

EmailDeliveryFailurePage.propTypes = propTypes;
EmailDeliveryFailurePage.defaultProps = defaultProps;
EmailDeliveryFailurePage.displayName = 'EmailDeliveryFailurePage';

export default withOnyx({
credentials: {key: ONYXKEYS.CREDENTIALS},
})(EmailDeliveryFailurePage);
33 changes: 25 additions & 8 deletions src/pages/signin/SignInPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import ResendValidationForm from './ResendValidationForm';
import Performance from '../../libs/Performance';
import * as App from '../../libs/actions/App';
import UnlinkLoginForm from './UnlinkLoginForm';
import EmailDeliveryFailurePage from './EmailDeliveryFailurePage';
import * as Localize from '../../libs/Localize';
import * as StyleUtils from '../../styles/StyleUtils';
import useLocalize from '../../hooks/useLocalize';
Expand All @@ -39,6 +40,9 @@ const propTypes = {

/** Does this account require 2FA? */
requiresTwoFactorAuth: PropTypes.bool,

/** Is this account having trouble receiving emails */
hasEmailDeliveryFailure: PropTypes.bool,
}),

/** The credentials of the person signing in */
Expand All @@ -63,18 +67,23 @@ const defaultProps = {
* @param {Boolean} isAccountValidated
* @param {Boolean} didForgetPassword
* @param {Boolean} canUsePasswordlessLogins
* @param {Boolean} hasEmailDeliveryFailure
* @returns {Object}
*/
function getRenderOptions({hasLogin, hasPassword, hasValidateCode, hasAccount, isPrimaryLogin, isAccountValidated, didForgetPassword, canUsePasswordlessLogins}) {
function getRenderOptions({hasLogin, hasPassword, hasValidateCode, hasAccount, isPrimaryLogin, isAccountValidated, didForgetPassword, canUsePasswordlessLogins, hasEmailDeliveryFailure}) {
const shouldShowLoginForm = !hasLogin && !hasValidateCode;
const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !isAccountValidated;
const shouldShowPasswordForm = hasLogin && isAccountValidated && !hasPassword && !didForgetPassword && !isUnvalidatedSecondaryLogin && !canUsePasswordlessLogins;
const shouldShowValidateCodeForm = hasAccount && (hasLogin || hasValidateCode) && !isUnvalidatedSecondaryLogin && canUsePasswordlessLogins;
const shouldShowResendValidationForm = hasLogin && (!isAccountValidated || didForgetPassword) && !isUnvalidatedSecondaryLogin && !canUsePasswordlessLogins;
const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm || isUnvalidatedSecondaryLogin;
const shouldShowEmailDeliveryFailurePage = hasLogin && hasEmailDeliveryFailure;
const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !isAccountValidated && !shouldShowEmailDeliveryFailurePage;
const shouldShowPasswordForm =
hasLogin && isAccountValidated && !hasPassword && !didForgetPassword && !isUnvalidatedSecondaryLogin && !canUsePasswordlessLogins && !shouldShowEmailDeliveryFailurePage;
const shouldShowValidateCodeForm = hasAccount && (hasLogin || hasValidateCode) && !isUnvalidatedSecondaryLogin && canUsePasswordlessLogins && !shouldShowEmailDeliveryFailurePage;
const shouldShowResendValidationForm =
hasLogin && (!isAccountValidated || didForgetPassword) && !isUnvalidatedSecondaryLogin && !canUsePasswordlessLogins && !shouldShowEmailDeliveryFailurePage;
const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm || isUnvalidatedSecondaryLogin || shouldShowEmailDeliveryFailurePage;
const shouldShowWelcomeText = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm;
return {
shouldShowLoginForm,
shouldShowEmailDeliveryFailurePage,
shouldShowUnlinkLoginForm: isUnvalidatedSecondaryLogin,
shouldShowPasswordForm,
shouldShowValidateCodeForm,
Expand All @@ -97,6 +106,7 @@ function SignInPage({credentials, account}) {

const {
shouldShowLoginForm,
shouldShowEmailDeliveryFailurePage,
shouldShowUnlinkLoginForm,
shouldShowPasswordForm,
shouldShowValidateCodeForm,
Expand All @@ -112,11 +122,12 @@ function SignInPage({credentials, account}) {
isAccountValidated: Boolean(account.validated),
didForgetPassword: Boolean(account.forgotPassword),
canUsePasswordlessLogins,
hasEmailDeliveryFailure: Boolean(account.hasEmailDeliveryFailure),
});

let welcomeHeader;
let welcomeText;
if (shouldShowValidateCodeForm) {
if (shouldShowValidateCodeForm || shouldShowResendValidationForm) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We were somehow returning true for shouldShowResendValidationForm (which I think should probably be removed) but never had any logic for setting the welcomeHeader or welcomeText for that view. Now we do 😅

if (account.requiresTwoFactorAuth) {
// We will only know this after a user signs in successfully, without their 2FA code
welcomeHeader = isSmallScreenWidth ? '' : translate('welcomeText.welcomeBack');
Expand All @@ -141,8 +152,13 @@ function SignInPage({credentials, account}) {
} else if (shouldShowPasswordForm) {
welcomeHeader = isSmallScreenWidth ? '' : translate('welcomeText.welcomeBack');
welcomeText = isSmallScreenWidth ? `${translate('welcomeText.welcomeBack')} ${translate('welcomeText.enterPassword')}` : translate('welcomeText.enterPassword');
} else if (shouldShowUnlinkLoginForm) {
} else if (shouldShowUnlinkLoginForm || shouldShowEmailDeliveryFailurePage) {
welcomeHeader = isSmallScreenWidth ? translate('login.hero.header') : translate('welcomeText.welcomeBack');

// Don't show any welcome text if we're showing the user the email delivery failed view
if (shouldShowEmailDeliveryFailurePage) {
welcomeText = '';
}
} else if (!shouldShowResendValidationForm) {
welcomeHeader = isSmallScreenWidth ? translate('login.hero.header') : translate('welcomeText.getStarted');
welcomeText = isSmallScreenWidth ? translate('welcomeText.getStarted') : '';
Expand All @@ -167,6 +183,7 @@ function SignInPage({credentials, account}) {
{shouldShowValidateCodeForm ? <ValidateCodeForm isVisible={shouldShowValidateCodeForm} /> : <PasswordForm isVisible={shouldShowPasswordForm} />}
{shouldShowResendValidationForm && <ResendValidationForm />}
{shouldShowUnlinkLoginForm && <UnlinkLoginForm />}
{shouldShowEmailDeliveryFailurePage && <EmailDeliveryFailurePage />}
</SignInPageLayout>
</View>
);
Expand Down