From 448f053d65cf680a20d287b6b13096d81e385907 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 22 Aug 2022 12:04:30 +0200 Subject: [PATCH 1/4] create openInitialSettingsPage, openEnablePaymentsPage, rm getAppData --- .../Navigation/AppNavigator/AuthScreens.js | 6 +--- src/libs/actions/App.js | 10 ------- src/libs/actions/BankAccounts.js | 1 - src/libs/actions/Wallet.js | 28 +++++++++++-------- .../EnablePayments/EnablePaymentsPage.js | 10 ++----- src/pages/settings/InitialSettingsPage.js | 1 + 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 79868dbe51e3..9b3136b247e4 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -102,10 +102,7 @@ class AuthScreens extends React.Component { componentDidMount() { NetworkConnection.listenForReconnect(); - NetworkConnection.onReconnect(() => { - App.getAppData(); - App.reconnectApp(); - }); + NetworkConnection.onReconnect(() => App.reconnectApp()); PusherConnectionManager.init(); Pusher.init({ appKey: CONFIG.PUSHER.APP_KEY, @@ -119,7 +116,6 @@ class AuthScreens extends React.Component { // Listen for report changes and fetch some data we need on initialization UnreadIndicatorUpdater.listenForReportChanges(); - App.getAppData(); App.openApp(); App.fixAccountAndReloadData(); diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 86842a882ebd..d4ca04c22989 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -11,7 +11,6 @@ import CONST from '../../CONST'; import Log from '../Log'; import Performance from '../Performance'; import Timing from './Timing'; -import * as BankAccounts from './BankAccounts'; import * as Policy from './Policy'; import Navigation from '../Navigation/Navigation'; import ROUTES from '../../ROUTES'; @@ -98,13 +97,6 @@ AppState.addEventListener('change', (nextAppState) => { appState = nextAppState; }); -/** - * Fetches data needed for app initialization - */ -function getAppData() { - BankAccounts.fetchUserWallet(); -} - /** * Fetches data needed for app initialization */ @@ -162,7 +154,6 @@ function fixAccountAndReloadData() { return; } Log.info('FixAccount found updates for this user, so data will be reinitialized', true, response); - getAppData(); }); } @@ -257,7 +248,6 @@ function openProfile() { export { setLocale, setSidebarLoaded, - getAppData, fixAccountAndReloadData, setUpPoliciesAndNavigate, openProfile, diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 333d0e6b22d8..b3d8d72100d8 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -28,7 +28,6 @@ export { export { fetchOnfidoToken, activateWallet, - fetchUserWallet, verifyIdentity, } from './Wallet'; diff --git a/src/libs/actions/Wallet.js b/src/libs/actions/Wallet.js index 529f95fa90bf..bf1885673349 100644 --- a/src/libs/actions/Wallet.js +++ b/src/libs/actions/Wallet.js @@ -435,7 +435,7 @@ function verifyIdentity(parameters) { } /** - * Fetches information about a user's Expensify Wallet + * Fetches data when the user opens the InitialSettingsPage * * @typedef {Object} UserWallet * @property {Number} availableBalance @@ -443,16 +443,21 @@ function verifyIdentity(parameters) { * @property {String} currentStep - used to track which step of the "activate wallet" flow a user is in * @property {('SILVER'|'GOLD')} tierName - will be GOLD when fully activated. SILVER is able to recieve funds only. */ -function fetchUserWallet() { - DeprecatedAPI.Get({returnValueList: 'userWallet'}) - .then((response) => { - if (response.jsonCode !== 200) { - return; - } +function openInitialSettingsPage() { + API.read('OpenInitialSettingsPage'); +} - // When refreshing the wallet, we should not show the failed KYC page anymore, as we should allow them to retry. - Onyx.merge(ONYXKEYS.USER_WALLET, {...response.userWallet, shouldShowFailedKYC: false}); - }); +/** + * Fetches data when the user opens the EnablePaymentsPage + * + * @typedef {Object} UserWallet + * @property {Number} availableBalance + * @property {Number} currentBalance + * @property {String} currentStep - used to track which step of the "activate wallet" flow a user is in + * @property {('SILVER'|'GOLD')} tierName - will be GOLD when fully activated. SILVER is able to recieve funds only. + */ +function openEnablePaymentsPage() { + API.read('OpenEnablePaymentsPage'); } /** @@ -472,7 +477,8 @@ function updateCurrentStep(currentStep) { export { fetchOnfidoToken, activateWallet, - fetchUserWallet, + openInitialSettingsPage, + openEnablePaymentsPage, setAdditionalDetailsErrors, updateAdditionalDetailsDraft, setAdditionalDetailsErrorMessage, diff --git a/src/pages/EnablePayments/EnablePaymentsPage.js b/src/pages/EnablePayments/EnablePaymentsPage.js index 0e15b668da6c..e744131b8f9e 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.js +++ b/src/pages/EnablePayments/EnablePaymentsPage.js @@ -3,7 +3,7 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import ScreenWrapper from '../../components/ScreenWrapper'; -import * as BankAccounts from '../../libs/actions/BankAccounts'; +import * as Wallet from '../../libs/actions/Wallet'; import ONYXKEYS from '../../ONYXKEYS'; import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; import CONST from '../../CONST'; @@ -39,7 +39,7 @@ const defaultProps = { class EnablePaymentsPage extends React.Component { componentDidMount() { - this.fetchData(); + Wallet.openEnablePaymentsPage(); } componentDidUpdate(prevProps) { @@ -47,11 +47,7 @@ class EnablePaymentsPage extends React.Component { return; } - this.fetchData(); - } - - fetchData() { - BankAccounts.fetchUserWallet(); + Wallet.openEnablePaymentsPage(); } render() { diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 785e00322716..53e60b2a8fea 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -29,6 +29,7 @@ import policyMemberPropType from '../policyMemberPropType'; import * as PaymentMethods from '../../libs/actions/PaymentMethods'; import bankAccountPropTypes from '../../components/bankAccountPropTypes'; import cardPropTypes from '../../components/cardPropTypes'; +import * as Wallet from '../../libs/actions/Wallet'; const propTypes = { /* Onyx Props */ From 5afc3b72e8513dfdd1b67d9c4ebc920298c25902 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 22 Aug 2022 12:10:33 +0200 Subject: [PATCH 2/4] refactor InitialSettingsPage to class component --- src/pages/settings/InitialSettingsPage.js | 246 +++++++++++----------- 1 file changed, 126 insertions(+), 120 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 53e60b2a8fea..c4a229e12e52 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -88,130 +88,136 @@ const defaultProps = { ...withCurrentUserPersonalDetailsDefaultProps, }; -const InitialSettingsPage = (props) => { - // On the very first sign in or after clearing storage these - // details will not be present on the first render so we'll just - // return nothing for now. - if (_.isEmpty(props.currentUserPersonalDetails)) { - return null; +class InitialSettingsPage extends React.Component { + componentDidMount() { + Wallet.openInitialSettingsPage(); } - const walletBalance = props.numberFormat( - props.userWallet.currentBalance / 100, // Divide by 100 because balance is in cents - {style: 'currency', currency: 'USD'}, - ); - - const defaultMenuItems = [ - { - translationKey: 'common.profile', - icon: Expensicons.Profile, - action: () => { App.openProfile(); }, - }, - { - translationKey: 'common.preferences', - icon: Expensicons.Gear, - action: () => { Navigation.navigate(ROUTES.SETTINGS_PREFERENCES); }, - }, - { - translationKey: 'initialSettingsPage.security', - icon: Expensicons.Lock, - action: () => { Navigation.navigate(ROUTES.SETTINGS_SECURITY); }, - }, - { - translationKey: 'common.payments', - icon: Expensicons.Wallet, - action: () => { Navigation.navigate(ROUTES.SETTINGS_PAYMENTS); }, - brickRoadIndicator: PaymentMethods.hasPaymentMethodError(props.bankAccountList, props.cardList) || !_.isEmpty(props.userWallet.errors) ? 'error' : null, - }, - { - translationKey: 'initialSettingsPage.about', - icon: Expensicons.Info, - action: () => { Navigation.navigate(ROUTES.SETTINGS_ABOUT); }, - }, - { - translationKey: 'initialSettingsPage.signOut', - icon: Expensicons.Exit, - action: Session.signOutAndRedirectToSignIn, - }, - ]; - - // Add free policies (workspaces) to the list of menu items - const menuItems = _.chain(props.policies) - .filter(policy => policy && policy.type === CONST.POLICY.TYPE.FREE && policy.role === CONST.POLICY.ROLE.ADMIN) - .map(policy => ({ - title: policy.name, - icon: policy.avatarURL ? policy.avatarURL : Expensicons.Building, - iconType: policy.avatarURL ? CONST.ICON_TYPE_AVATAR : CONST.ICON_TYPE_ICON, - action: () => Navigation.navigate(ROUTES.getWorkspaceInitialRoute(policy.id)), - iconStyles: policy.avatarURL ? [] : [styles.popoverMenuIconEmphasized], - iconFill: themeColors.iconReversed, - fallbackIcon: Expensicons.FallbackWorkspaceAvatar, - brickRoadIndicator: Policy.hasPolicyMemberError(lodashGet(props.policyMembers, `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policy.id}`, {})) ? 'error' : null, - })) - .value(); - menuItems.push(...defaultMenuItems); - - const openProfileSettings = () => Navigation.navigate(ROUTES.SETTINGS_PROFILE); - - return ( - - Navigation.dismissModal(true)} - /> - - - - - - { App.openProfile(); }, + }, + { + translationKey: 'common.preferences', + icon: Expensicons.Gear, + action: () => { Navigation.navigate(ROUTES.SETTINGS_PREFERENCES); }, + }, + { + translationKey: 'initialSettingsPage.security', + icon: Expensicons.Lock, + action: () => { Navigation.navigate(ROUTES.SETTINGS_SECURITY); }, + }, + { + translationKey: 'common.payments', + icon: Expensicons.Wallet, + action: () => { Navigation.navigate(ROUTES.SETTINGS_PAYMENTS); }, + brickRoadIndicator: PaymentMethods.hasPaymentMethodError(this.props.bankAccountList, this.props.cardList) || !_.isEmpty(this.props.userWallet.errors) ? 'error' : null, + }, + { + translationKey: 'initialSettingsPage.about', + icon: Expensicons.Info, + action: () => { Navigation.navigate(ROUTES.SETTINGS_ABOUT); }, + }, + { + translationKey: 'initialSettingsPage.signOut', + icon: Expensicons.Exit, + action: Session.signOutAndRedirectToSignIn, + }, + ]; + + // Add free policies (workspaces) to the list of menu items + const menuItems = _.chain(this.props.policies) + .filter(policy => policy && policy.type === CONST.POLICY.TYPE.FREE && policy.role === CONST.POLICY.ROLE.ADMIN) + .map(policy => ({ + title: policy.name, + icon: policy.avatarURL ? policy.avatarURL : Expensicons.Building, + iconType: policy.avatarURL ? CONST.ICON_TYPE_AVATAR : CONST.ICON_TYPE_ICON, + action: () => Navigation.navigate(ROUTES.getWorkspaceInitialRoute(policy.id)), + iconStyles: policy.avatarURL ? [] : [styles.popoverMenuIconEmphasized], + iconFill: themeColors.iconReversed, + fallbackIcon: Expensicons.FallbackWorkspaceAvatar, + brickRoadIndicator: Policy.hasPolicyMemberError(lodashGet(this.props.policyMembers, `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policy.id}`, {})) ? 'error' : null, + })) + .value(); + menuItems.push(...defaultMenuItems); + + const openProfileSettings = () => Navigation.navigate(ROUTES.SETTINGS_PROFILE); + + return ( + + Navigation.dismissModal(true)} + /> + + + + + + + + + + + + {this.props.currentUserPersonalDetails.displayName + ? this.props.currentUserPersonalDetails.displayName + : Str.removeSMSDomain(this.props.session.email)} + + + {this.props.currentUserPersonalDetails.displayName && ( + + {Str.removeSMSDomain(this.props.session.email)} + + )} + + {_.map(menuItems, (item, index) => { + const keyTitle = item.translationKey ? this.props.translate(item.translationKey) : item.title; + const isPaymentItem = item.translationKey === 'common.payments'; + return ( + - - - - - - {props.currentUserPersonalDetails.displayName - ? props.currentUserPersonalDetails.displayName - : Str.removeSMSDomain(props.session.email)} - - - {props.currentUserPersonalDetails.displayName && ( - - {Str.removeSMSDomain(props.session.email)} - - )} + ); + })} - {_.map(menuItems, (item, index) => { - const keyTitle = item.translationKey ? props.translate(item.translationKey) : item.title; - const isPaymentItem = item.translationKey === 'common.payments'; - return ( - - ); - })} - - - - ); -}; + + + ); + } +} InitialSettingsPage.propTypes = propTypes; InitialSettingsPage.defaultProps = defaultProps; From 512d2a68271b53f6e2d3369a73b20edd048c82f0 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 22 Aug 2022 12:34:54 +0200 Subject: [PATCH 3/4] move openProfileSettings and getWalletBalance to class methods --- src/pages/settings/InitialSettingsPage.js | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index c4a229e12e52..a18d03a5b403 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -89,10 +89,32 @@ const defaultProps = { }; class InitialSettingsPage extends React.Component { + constructor(props) { + super(props); + + this.getWalletBalance = this.getWalletBalance.bind(this); + } + componentDidMount() { Wallet.openInitialSettingsPage(); } + /** + * @param {Boolean} isPaymentItem whether the item being rendered is the payments menu item + * @returns {Number} the user wallet balance + */ + getWalletBalance(isPaymentItem) { + return (isPaymentItem && Permissions.canUseWallet(this.props.betas)) + ? this.props.numberFormat( + this.props.userWallet.currentBalance / 100, // Divide by 100 because balance is in cents + {style: 'currency', currency: 'USD'}, + ) : undefined; + } + + openProfileSettings() { + Navigation.navigate(ROUTES.SETTINGS_PROFILE); + } + render() { // On the very first sign in or after clearing storage these // details will not be present on the first render so we'll just @@ -101,11 +123,6 @@ class InitialSettingsPage extends React.Component { return null; } - const walletBalance = this.props.numberFormat( - this.props.userWallet.currentBalance / 100, // Divide by 100 because balance is in cents - {style: 'currency', currency: 'USD'}, - ); - const defaultMenuItems = [ { translationKey: 'common.profile', @@ -156,8 +173,6 @@ class InitialSettingsPage extends React.Component { .value(); menuItems.push(...defaultMenuItems); - const openProfileSettings = () => Navigation.navigate(ROUTES.SETTINGS_PROFILE); - return ( From 3cef13d5e1012dc99036d7f8c1693686d436ad4f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 22 Aug 2022 12:48:34 +0200 Subject: [PATCH 4/4] move getMenuItems to class methods --- src/pages/settings/InitialSettingsPage.js | 53 +++++++++++++++-------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index a18d03a5b403..672419a5d61c 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -93,6 +93,8 @@ class InitialSettingsPage extends React.Component { super(props); this.getWalletBalance = this.getWalletBalance.bind(this); + this.getDefaultMenuItems = this.getDefaultMenuItems.bind(this); + this.getMenuItems = this.getMenuItems.bind(this); } componentDidMount() { @@ -111,19 +113,12 @@ class InitialSettingsPage extends React.Component { ) : undefined; } - openProfileSettings() { - Navigation.navigate(ROUTES.SETTINGS_PROFILE); - } - - render() { - // On the very first sign in or after clearing storage these - // details will not be present on the first render so we'll just - // return nothing for now. - if (_.isEmpty(this.props.currentUserPersonalDetails)) { - return null; - } - - const defaultMenuItems = [ + /** + * Retuns a list of default menu items + * @returns {Array} the default menu items + */ + getDefaultMenuItems() { + return ([ { translationKey: 'common.profile', icon: Expensicons.Profile, @@ -155,9 +150,14 @@ class InitialSettingsPage extends React.Component { icon: Expensicons.Exit, action: Session.signOutAndRedirectToSignIn, }, - ]; + ]); + } - // Add free policies (workspaces) to the list of menu items + /** + * Add free policies (workspaces) to the list of menu items and returns the list of menu items + * @returns {Array} the menu item list + */ + getMenuItems() { const menuItems = _.chain(this.props.policies) .filter(policy => policy && policy.type === CONST.POLICY.TYPE.FREE && policy.role === CONST.POLICY.ROLE.ADMIN) .map(policy => ({ @@ -171,7 +171,22 @@ class InitialSettingsPage extends React.Component { brickRoadIndicator: Policy.hasPolicyMemberError(lodashGet(this.props.policyMembers, `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policy.id}`, {})) ? 'error' : null, })) .value(); - menuItems.push(...defaultMenuItems); + menuItems.push(...this.getDefaultMenuItems()); + + return menuItems; + } + + openProfileSettings() { + Navigation.navigate(ROUTES.SETTINGS_PROFILE); + } + + render() { + // On the very first sign in or after clearing storage these + // details will not be present on the first render so we'll just + // return nothing for now. + if (_.isEmpty(this.props.currentUserPersonalDetails)) { + return null; + } return ( @@ -182,7 +197,7 @@ class InitialSettingsPage extends React.Component { - + - + {this.props.currentUserPersonalDetails.displayName ? this.props.currentUserPersonalDetails.displayName @@ -208,7 +223,7 @@ class InitialSettingsPage extends React.Component { )} - {_.map(menuItems, (item, index) => { + {_.map(this.getMenuItems(), (item, index) => { const keyTitle = item.translationKey ? this.props.translate(item.translationKey) : item.title; const isPaymentItem = item.translationKey === 'common.payments'; return (