Skip to content

Add CTA to error messages about "email should be your default contact" #58198

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

Merged
merged 8 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
20 changes: 17 additions & 3 deletions src/components/BookTravelButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Str} from 'expensify-common';
import React, {useCallback, useContext, useState} from 'react';
import type {ReactElement} from 'react';
import {NativeModules} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
Expand All @@ -22,6 +23,8 @@ import ConfirmModal from './ConfirmModal';
import CustomStatusBarAndBackgroundContext from './CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext';
import DotIndicatorMessage from './DotIndicatorMessage';
import {RocketDude} from './Icon/Illustrations';
import Text from './Text';
import TextLink from './TextLink';

type BookTravelButtonProps = {
text: string;
Expand All @@ -39,7 +42,7 @@ function BookTravelButton({text}: BookTravelButtonProps) {
const {translate} = useLocalize();
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
const policy = usePolicy(activePolicyID);
const [errorMessage, setErrorMessage] = useState('');
const [errorMessage, setErrorMessage] = useState<string | ReactElement>('');
const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS);
const [primaryLogin] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => account?.primaryLogin});
const [sessionEmail] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email});
Expand All @@ -64,7 +67,18 @@ function BookTravelButton({text}: BookTravelButtonProps) {

// The primary login of the user is where Spotnana sends the emails with booking confirmations, itinerary etc. It can't be a phone number.
if (!primaryContactMethod || Str.isSMSLogin(primaryContactMethod)) {
setErrorMessage(translate('travel.phoneError'));
setErrorMessage(
<Text style={[styles.flexRow, StyleUtils.getDotIndicatorTextStyles(true)]}>
<Text style={[StyleUtils.getDotIndicatorTextStyles(true)]}>{translate('travel.phoneErrorIntro')}</Text>{' '}
<TextLink
style={[StyleUtils.getDotIndicatorTextStyles(true), styles.link]}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.getRoute())}
>
{translate('travel.phoneErrorLink')}
</TextLink>
.
</Text>,
);
return;
}

Expand Down Expand Up @@ -110,7 +124,7 @@ function BookTravelButton({text}: BookTravelButtonProps) {
Navigation.navigate(ROUTES.TRAVEL_DOMAIN_SELECTOR);
}
}
}, [policy, wasNewDotLaunchedJustForTravel, travelSettings, translate, primaryContactMethod, setRootStatusBarEnabled, isBlockedFromSpotnanaTravel]);
}, [policy, wasNewDotLaunchedJustForTravel, travelSettings, translate, primaryContactMethod, setRootStatusBarEnabled, isBlockedFromSpotnanaTravel, StyleUtils, styles]);

return (
<>
Expand Down
5 changes: 3 additions & 2 deletions src/components/DotIndicatorMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable react/no-array-index-key */
import type {ReactElement} from 'react';
import React from 'react';
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
import {View} from 'react-native';
Expand All @@ -22,7 +23,7 @@ type DotIndicatorMessageProps = {
* timestamp: 'message',
* }
*/
messages: Record<string, string | ReceiptError | null>;
messages: Record<string, string | ReceiptError | ReactElement | null>;

/** The type of message, 'error' shows a red dot, 'success' shows a green dot */
type: 'error' | 'success';
Expand Down Expand Up @@ -53,7 +54,7 @@ function DotIndicatorMessage({messages = {}, style, type, textStyles}: DotIndica

const isErrorMessage = type === 'error';

const renderMessage = (message: string | ReceiptError, index: number) => {
const renderMessage = (message: string | ReceiptError | ReactElement, index: number) => {
if (isReceiptError(message)) {
return (
<Text
Expand Down
9 changes: 7 additions & 2 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2034,7 +2034,11 @@ const translations = {
phrase3: 'or ',
phrase4: 'verify your account here',
},
hasPhoneLoginError: 'To add a verified bank account please ensure your primary login is a valid email and try again. You can add your phone number as a secondary login.',
hasPhoneLoginError: {
phrase1: 'To add a verified bank account please ',
link: 'ensure your primary login is a valid email',
phrase2: ' and try again. You can add your phone number as a secondary login.',
},
hasBeenThrottledError: 'An error occurred while adding your bank account. Please wait a few minutes and try again.',
hasCurrencyError: 'Oops! It appears that your workspace currency is set to a different currency than USD. To proceed, please set it to USD and try again.',
error: {
Expand Down Expand Up @@ -2623,7 +2627,8 @@ const translations = {
tripSummary: 'Trip summary',
departs: 'Departs',
errorMessage: 'Something went wrong. Please try again later.',
phoneError: 'To book travel, your default contact method must be a valid email',
phoneErrorIntro: 'To book travel, please',
phoneErrorLink: 'add a work email address',
domainSelector: {
title: 'Domain',
subtitle: 'Choose a domain for Expensify Travel setup.',
Expand Down
10 changes: 7 additions & 3 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2053,8 +2053,11 @@ const translations = {
phrase3: 'o',
phrase4: 'verifica aquí tu cuenta',
},
hasPhoneLoginError:
'Para añadir una cuenta bancaria verificada, asegúrate de que tu nombre de usuario principal sea un correo electrónico válido y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.',
hasPhoneLoginError: {
phrase1: 'Para añadir una cuenta bancaria verificada, ',
link: 'asegúrate de que tu nombre de usuario principal sea un correo electrónico válido',
phrase2: ' y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.',
},
hasBeenThrottledError: 'Se ha producido un error al intentar añadir tu cuenta bancaria. Por favor, espera unos minutos e inténtalo de nuevo.',
hasCurrencyError: '¡Ups! Parece que la moneda de tu espacio de trabajo no está configurada en USD. Por favor, configúrala en USD e inténtalo nuevamente.',
error: {
Expand Down Expand Up @@ -2647,7 +2650,8 @@ const translations = {
tripSummary: 'Resumen del viaje',
departs: 'Sale',
errorMessage: 'Ha ocurrido un error. Por favor, inténtalo mas tarde.',
phoneError: 'Para reservar viajes, tu método de contacto predeterminado debe ser un correo electrónico válido',
phoneErrorIntro: 'Para reservar viajes,',
phoneErrorLink: 'añada una dirección de correo electrónico del trabajo',
domainSelector: {
title: 'Dominio',
subtitle: 'Elige un dominio para configurar Expensify Travel.',
Expand Down
15 changes: 14 additions & 1 deletion src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {useSession} from '@components/OnyxProvider';
import ReimbursementAccountLoadingIndicator from '@components/ReimbursementAccountLoadingIndicator';
import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
import useBeforeRemove from '@hooks/useBeforeRemove';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -38,6 +39,7 @@ import {
import {clearReimbursementAccountDraft} from '@userActions/ReimbursementAccount';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {InputID} from '@src/types/form/ReimbursementAccountForm';
import type {ACHDataReimbursementAccount} from '@src/types/onyx/ReimbursementAccount';
Expand Down Expand Up @@ -377,7 +379,18 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy}: Reimbursemen
const throttledDate = reimbursementAccount?.throttledDate ?? '';

if (userHasPhonePrimaryEmail) {
errorText = translate('bankAccount.hasPhoneLoginError');
errorText = (
<Text style={styles.flexRow}>
<Text>{translate('bankAccount.hasPhoneLoginError.phrase1')}</Text>{' '}
<TextLink
style={styles.link}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(route.params.backTo))}
>
{translate('bankAccount.hasPhoneLoginError.link')}
</TextLink>
{translate('bankAccount.hasPhoneLoginError.phrase2')}
</Text>
);
} else if (throttledDate) {
errorText = translate('bankAccount.hasBeenThrottledError');
} else if (hasUnsupportedCurrency) {
Expand Down
Loading