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

Fix stuck navigation & Re-add Contact Method Details pages #15751

Merged
merged 36 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4237497
No need to call Navigate.navigate
aldo-expensify Mar 8, 2023
99a10ac
Redirect on componentDidUpdate instead of render
aldo-expensify Mar 8, 2023
a2056b5
Add everything back that got reverted
Beamanator Mar 9, 2023
05274b2
Fix lint and missing LoginField
Beamanator Mar 10, 2023
46b9f43
Merge branch 'main' of github.com:Expensify/App into aldo_fix-delete-…
Beamanator Mar 10, 2023
887a57c
Merge branch 'beaman-recreateShowAllExpensifyLogins' into aldo_fix-de…
Beamanator Mar 10, 2023
17fd385
A bit of cleanup
Beamanator Mar 10, 2023
2200f69
Merge branch 'main' of github.com:Expensify/App into aldo_fix-delete-…
aldo-expensify Mar 13, 2023
4952847
Merge with main / resolve conflicts
aldo-expensify Mar 13, 2023
b659e1b
Remove Navigation.isNavigating
aldo-expensify Mar 16, 2023
463f198
Resolve conflicts / merge main
aldo-expensify Mar 17, 2023
109479b
Polish
aldo-expensify Mar 21, 2023
e0354df
Show NOT FOUND when contact method is missing
aldo-expensify Mar 21, 2023
6420459
Update comments
aldo-expensify Mar 21, 2023
6e0de62
Update comment about follow up PR
aldo-expensify Mar 21, 2023
c2931da
Remove unused prop size
aldo-expensify Mar 21, 2023
5b4ed14
Merge branch 'main' of github.com:Expensify/App into aldo_fix-delete-…
aldo-expensify Mar 21, 2023
1d7502b
Update comment
aldo-expensify Mar 21, 2023
5eb315a
Fix margins
aldo-expensify Mar 23, 2023
2d7094c
Use CONST
aldo-expensify Mar 23, 2023
1aed80b
Submit validation code on press enter
aldo-expensify Mar 23, 2023
4f52414
Restrict autocomplete to phones only
aldo-expensify Mar 23, 2023
21f6623
Remove unused css
aldo-expensify Mar 23, 2023
7f66b8f
Merge main / Resolve conflicts
aldo-expensify Mar 23, 2023
634ed14
Remove required from prop types / add defaults
aldo-expensify Mar 23, 2023
012faeb
Pass correct autoComplete value depending on type
aldo-expensify Mar 23, 2023
fc31a8d
Add new validation to magic code input
Beamanator Mar 27, 2023
322e72a
Reuse existing validate code validation
Beamanator Mar 27, 2023
afe51f4
Clear error on successful submit
Beamanator Mar 27, 2023
5749c3b
Only handle touch in resend validate code text
aldo-expensify Mar 27, 2023
eb71724
4px to the left
aldo-expensify Mar 27, 2023
f95dbda
Fix lint issues
Beamanator Mar 27, 2023
6cc7921
Make resend checkmark 4 px from text
Beamanator Mar 27, 2023
7b9c665
Merge branch 'main' of github.com:Expensify/App into aldo_fix-delete-…
Beamanator Mar 27, 2023
6151893
Fix bug requiring double tap to submit
aldo-expensify Mar 28, 2023
82dd1a4
All keypad input to blur on submit
Beamanator Mar 28, 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
2 changes: 2 additions & 0 deletions src/ROUTES.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export default {
SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH: `${SETTINGS_PERSONAL_DETAILS}/date-of-birth`,
SETTINGS_PERSONAL_DETAILS_ADDRESS: `${SETTINGS_PERSONAL_DETAILS}/address`,
SETTINGS_CONTACT_METHODS,
SETTINGS_CONTACT_METHOD_DETAILS: `${SETTINGS_CONTACT_METHODS}/:contactMethod/details`,
getEditContactMethodRoute: contactMethod => `${SETTINGS_CONTACT_METHODS}/${encodeURIComponent(contactMethod)}/details`,
NEW_GROUP: 'new/group',
NEW_CHAT: 'new/chat',
REPORT,
Expand Down
58 changes: 36 additions & 22 deletions src/components/AvatarWithIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ import walletTermsPropTypes from '../pages/EnablePayments/walletTermsPropTypes';
import * as PolicyUtils from '../libs/PolicyUtils';
import * as PaymentMethods from '../libs/actions/PaymentMethods';
import * as ReportUtils from '../libs/ReportUtils';
import * as UserUtils from '../libs/UserUtils';
import themeColors from '../styles/themes/default';

const propTypes = {
/** URL for the avatar */
source: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,

/** Avatar size */
size: PropTypes.string,

/** To show a tooltip on hover */
tooltipText: PropTypes.string,

/* Onyx Props */

/** The employee list of all policies (coming from Onyx) */
policiesMemberList: PropTypes.objectOf(policyMemberPropType),

Expand All @@ -44,56 +45,66 @@ const propTypes = {

/** Information about the user accepting the terms for payments */
walletTerms: walletTermsPropTypes,

/** Login list for the user that is signed in */
loginList: PropTypes.shape({
/** Date login was validated, used to show info indicator status */
validatedDate: PropTypes.string,

/** Field-specific server side errors keyed by microtime */
errorFields: PropTypes.objectOf(PropTypes.objectOf(PropTypes.string)),
}),
};

const defaultProps = {
size: 'default',
tooltipText: '',
policiesMemberList: {},
policies: {},
bankAccountList: {},
cardList: {},
userWallet: {},
walletTerms: {},
loginList: {},
};

const AvatarWithIndicator = (props) => {
const isLarge = props.size === 'large';
const indicatorStyles = [
styles.alignItemsCenter,
styles.justifyContentCenter,
isLarge ? styles.statusIndicatorLarge : styles.statusIndicator,
];

// If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and
// those should be cleaned out before doing any error checking
const cleanPolicies = _.pick(props.policies, policy => policy);
const cleanPolicyMembers = _.pick(props.policiesMemberList, member => member);

// All of the error-checking methods are put into an array. This is so that using _.some() will return
// early as soon as the first error is returned. This makes the error checking very efficient since
// we only care if a single error exists anywhere.
// All of the error & info-checking methods are put into an array. This is so that using _.some() will return
// early as soon as the first error / info condition is returned. This makes the checks very efficient since
// we only care if a single error / info condition exists anywhere.
const errorCheckingMethods = [
() => !_.isEmpty(props.userWallet.errors),
() => PaymentMethods.hasPaymentMethodError(props.bankAccountList, props.cardList),
() => _.some(cleanPolicies, PolicyUtils.hasPolicyError),
() => _.some(cleanPolicies, PolicyUtils.hasCustomUnitsError),
() => _.some(cleanPolicyMembers, PolicyUtils.hasPolicyMemberError),
() => UserUtils.hasLoginListError(props.loginList),

// Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead)
() => !_.isEmpty(props.walletTerms.errors) && !props.walletTerms.chatReportID,
];
const shouldShowIndicator = _.some(errorCheckingMethods, errorCheckingMethod => errorCheckingMethod());
const infoCheckingMethods = [
() => UserUtils.hasLoginListInfo(props.loginList),
];
const shouldShowErrorIndicator = _.some(errorCheckingMethods, errorCheckingMethod => errorCheckingMethod());
const shouldShowInfoIndicator = !shouldShowErrorIndicator && _.some(infoCheckingMethods, infoCheckingMethod => infoCheckingMethod());

const indicatorColor = shouldShowErrorIndicator ? themeColors.danger : themeColors.success;
const indicatorStyles = [
styles.alignItemsCenter,
styles.justifyContentCenter,
styles.statusIndicator(indicatorColor),
];

return (
<View style={[isLarge ? styles.avatarLarge : styles.sidebarAvatar]}>
<View style={[styles.sidebarAvatar]}>
<Tooltip text={props.tooltipText}>
<Avatar
imageStyles={[isLarge ? styles.avatarLarge : null]}
source={ReportUtils.getSmallSizeAvatar(props.source)}
size={props.size}
/>
{shouldShowIndicator && (
<Avatar source={ReportUtils.getSmallSizeAvatar(props.source)} />
{(shouldShowErrorIndicator || shouldShowInfoIndicator) && (
<View style={StyleSheet.flatten(indicatorStyles)} />
)}
</Tooltip>
Expand Down Expand Up @@ -124,4 +135,7 @@ export default withOnyx({
walletTerms: {
key: ONYXKEYS.WALLET_TERMS,
},
loginList: {
key: ONYXKEYS.LOGIN_LIST,
},
})(AvatarWithIndicator);
2 changes: 1 addition & 1 deletion src/components/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const MenuItem = (props) => {
const descriptionTextStyle = StyleUtils.combineStyles([
styles.textLabelSupporting,
(props.icon ? styles.ml3 : undefined),
styles.breakAll,
styles.breakWord,
styles.lineHeightNormal,
], props.style);

Expand Down
9 changes: 0 additions & 9 deletions src/components/ScreenWrapper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,7 @@ class ScreenWrapper extends React.Component {
Navigation.dismissModal();
}, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true);

this.unsubscribeTransitionStart = this.props.navigation.addListener('transitionStart', () => {
Navigation.setIsNavigating(true);
});

this.unsubscribeTransitionEnd = this.props.navigation.addListener('transitionEnd', (event) => {
Navigation.setIsNavigating(false);

// Prevent firing the prop callback when user is exiting the page.
if (lodashGet(event, 'data.closing')) {
return;
Expand Down Expand Up @@ -85,9 +79,6 @@ class ScreenWrapper extends React.Component {
if (this.unsubscribeTransitionEnd) {
this.unsubscribeTransitionEnd();
}
if (this.unsubscribeTransitionStart) {
this.unsubscribeTransitionStart();
}
if (this.beforeRemoveSubscription) {
this.beforeRemoveSubscription();
}
Expand Down
16 changes: 16 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ export default {
youAppearToBeOffline: 'You appear to be offline.',
thisFeatureRequiresInternet: 'This feature requires an active internet connection to be used.',
areYouSure: 'Are you sure?',
verify: 'Verify',
yesContinue: 'Yes, continue',
zipCodeExample: 'e.g. 12345, 12345-1234, 12345 1234',
websiteExample: 'e.g. https://www.expensify.com',
},
Expand Down Expand Up @@ -349,6 +351,20 @@ export default {
contacts: {
contactMethod: 'Contact method',
contactMethods: 'Contact methods',
helpTextBeforeEmail: 'Add more ways for people to find you, and forward receipts to ',
helpTextAfterEmail: ' from multiple email addresses.',
pleaseVerify: 'Please verify this contact method',
getInTouch: "Whenever we need to get in touch with you, we'll use this contact method.",
enterMagicCode: ({contactMethod}) => `Please enter the magic code sent to ${contactMethod}`,
yourDefaultContactMethod: 'This is your current default contact method. You will not be able to delete this contact method until you set an alternative default by selecting another contact method and pressing “Set as default”.',
removeContactMethod: 'Remove contact method',
removeAreYouSure: 'Are you sure you want to remove this contact method? This action cannot be undone.',
resendMagicCode: 'Resend magic code',
genericFailureMessages: {
requestContactMethodValidateCode: 'Failed to send a new magic code. Please wait a bit and try again.',
validateSecondaryLogin: 'Failed to validate contact method with given magic code. Please request a new code and try again.',
deleteContactMethod: 'Failed to delete contact method. Please reach out to Concierge for help.',
},
},
pronouns: {
coCos: 'Co / Cos',
Expand Down
16 changes: 16 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ export default {
youAppearToBeOffline: 'Parece que estás desconectado.',
thisFeatureRequiresInternet: 'Esta función requiere una conexión a Internet activa para ser utilizada.',
areYouSure: '¿Estás seguro?',
verify: 'Verifique',
yesContinue: 'Sí, Continuar',
zipCodeExample: 'p. ej. 12345, 12345-1234, 12345 1234',
websiteExample: 'p. ej. https://www.expensify.com',
},
Expand Down Expand Up @@ -348,6 +350,20 @@ export default {
contacts: {
contactMethod: 'Método de contacto',
contactMethods: 'Métodos de contacto',
helpTextBeforeEmail: 'Añade más formas de que la gente te encuentre y reenvía los recibos a ',
helpTextAfterEmail: ' desde varias direcciones de correo electrónico.',
pleaseVerify: 'Por favor verifica este método de contacto',
getInTouch: 'Utilizaremos este método de contacto cuando necesitemos contactarte.',
enterMagicCode: ({contactMethod}) => `Por favor, introduce el código mágico enviado a ${contactMethod}`,
yourDefaultContactMethod: 'Este es tu método de contacto predeterminado. No podrás eliminarlo hasta que añadas otro método de contacto y lo marques como predeterminado pulsando "Establecer como predeterminado".',
removeContactMethod: 'Eliminar método de contacto',
removeAreYouSure: '¿Estás seguro de que quieres eliminar este método de contacto? Esta acción no se puede deshacer.',
resendMagicCode: 'Reenviar código mágico',
genericFailureMessages: {
requestContactMethodValidateCode: 'No se ha podido enviar un nuevo código mágico. Espera un rato y vuelve a intentarlo.',
validateSecondaryLogin: 'No se ha podido validar el método de contacto con el código mágico provisto. Solicita un nuevo código y vuelve a intentarlo.',
deleteContactMethod: 'No se ha podido eliminar el método de contacto. Por favor contacta con Concierge para obtener ayuda.',
},
},
pronouns: {
coCos: 'Co / Cos',
Expand Down
24 changes: 23 additions & 1 deletion src/libs/ErrorUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import _ from 'underscore';
import lodashGet from 'lodash/get';
import CONST from '../CONST';

/**
Expand Down Expand Up @@ -54,6 +55,27 @@ function getLatestErrorMessage(onyxData) {
.value();
}

/**
* @param {Object} onyxData
* @param {Object} onyxData.errorFields
* @param {String} fieldName
* @returns {Object}
*/
function getLatestErrorField(onyxData, fieldName) {
const errorsForField = lodashGet(onyxData, ['errorFields', fieldName], {});

if (_.isEmpty(errorsForField)) {
return {};
}
return _.chain(errorsForField)
.keys()
.sortBy()
.reverse()
.map(key => ({[key]: errorsForField[key]}))
.first()
.value();
}

/**
* Method used to generate error message for given inputID
* @param {Object} errors - An object containing current errors in the form
Expand All @@ -74,8 +96,8 @@ function addErrorMessage(errors, inputID, message) {
}

export {
// eslint-disable-next-line import/prefer-default-export
getAuthenticateErrorMessage,
getLatestErrorMessage,
getLatestErrorField,
addErrorMessage,
};
7 changes: 7 additions & 0 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([
},
name: 'Settings_ContactMethods',
},
{
getComponent: () => {
const SettingsContactMethodDetailsPage = require('../../../pages/settings/Profile/Contacts/ContactMethodDetailsPage').default;
return SettingsContactMethodDetailsPage;
},
name: 'Settings_ContactMethodDetails',
},
{
getComponent: () => {
const SettingsAddSecondaryLoginPage = require('../../../pages/settings/Profile/Contacts/AddSecondaryLoginPage').default;
Expand Down
19 changes: 1 addition & 18 deletions src/libs/Navigation/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ let reportScreenIsReadyPromise = new Promise((resolve) => {

let isLoggedIn = false;
let pendingRoute = null;
let isNavigating = false;

Onyx.connect({
key: ONYXKEYS.SESSION,
Expand All @@ -56,27 +55,13 @@ function setDidTapNotification() {
* @returns {Boolean}
*/
function canNavigate(methodName, params = {}) {
if (navigationRef.isReady() && !isNavigating) {
if (navigationRef.isReady()) {
return true;
}

if (isNavigating) {
Log.hmmm(`[Navigation] ${methodName} failed because navigation is progress`, params);
return false;
}

Log.hmmm(`[Navigation] ${methodName} failed because navigation ref was not yet ready`, params);
return false;
}

/**
* Sets Navigation State
* @param {Boolean} isNavigatingValue
*/
function setIsNavigating(isNavigatingValue) {
isNavigating = isNavigatingValue;
}

/**
* Opens the LHN drawer.
* @private
Expand Down Expand Up @@ -129,7 +114,6 @@ function goBack(shouldOpenDrawer = true) {
}
return;
}

navigationRef.current.goBack();
}

Expand Down Expand Up @@ -331,7 +315,6 @@ export default {
resetDrawerIsReadyPromise,
resetIsReportScreenReadyPromise,
isDrawerRoute,
setIsNavigating,
isReportScreenReady,
setIsReportScreenIsReady,
};
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/linkingConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ export default {
path: ROUTES.SETTINGS_CONTACT_METHODS,
exact: true,
},
Settings_ContactMethodDetails: {
path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS,
},
Settings_Add_Secondary_Login: {
path: ROUTES.SETTINGS_ADD_LOGIN,
},
Expand Down
Loading
Loading