From 376824753546427070280e2d55dbea874aa9274b Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 4 Nov 2021 15:56:01 -0700 Subject: [PATCH 01/67] Initial testing --- src/components/PlaidLink/index.native.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/PlaidLink/index.native.js b/src/components/PlaidLink/index.native.js index da6fdf8dcb93..dab545d633f0 100644 --- a/src/components/PlaidLink/index.native.js +++ b/src/components/PlaidLink/index.native.js @@ -13,6 +13,7 @@ class PlaidLink extends React.Component { } componentDidMount() { + console.log("here"); const emitter = new NativeEventEmitter(nativeModule); this.listener = emitter.addListener('onEvent', this.onEvent.bind(this)); @@ -21,6 +22,7 @@ class PlaidLink extends React.Component { token: this.props.token, }, onSuccess: ({publicToken, metadata}) => { + console.log("here in onSuccess", metadata); this.props.onSuccess({publicToken, metadata}); }, }); From ecabb8abf952670fc23de3477a3c4fa94c0c712d Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 4 Nov 2021 16:32:15 -0700 Subject: [PATCH 02/67] Add new redirectURI param for plaidLinkToken call --- src/components/PlaidLink/index.js | 1 + src/libs/API.js | 6 ++++-- src/libs/actions/BankAccounts.js | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index 472e1f373872..8fdd725a3c9a 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -4,6 +4,7 @@ import {plaidLinkPropTypes, plaidLinkDefaultProps} from './plaidLinkPropTypes'; import Log from '../../libs/Log'; const PlaidLink = (props) => { + console.log("here in index PlaidLink"); const onSuccess = useCallback((publicToken, metadata) => { props.onSuccess({publicToken, metadata}); }, []); diff --git a/src/libs/API.js b/src/libs/API.js index 19f70c63879a..5a12cd154fa5 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -868,8 +868,10 @@ function Wallet_GetOnfidoSDKToken() { /** * @returns {Promise} */ -function Plaid_GetLinkToken() { - return Network.post('Plaid_GetLinkToken', {}, CONST.NETWORK.METHOD.POST, true); +function Plaid_GetLinkToken(parameters) { + const commandName = 'Plaid_GetLinkToken'; + requireParameters(['redirectURI'], parameters, commandName); + return Network.post('Plaid_GetLinkToken', parameters, CONST.NETWORK.METHOD.POST, true); } /** diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 91988e7cdd1f..63bcbcc85ab5 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -46,9 +46,11 @@ Onyx.connect({ /** * Gets the Plaid Link token used to initialize the Plaid SDK + * + * @param {String} redirectURI */ -function fetchPlaidLinkToken() { - API.Plaid_GetLinkToken() +function fetchPlaidLinkToken(redirectURI) { + API.Plaid_GetLinkToken(redirectURI) .then((response) => { if (response.jsonCode !== 200) { return; From 6a7fac8a5d2ba1c9b41b268700fe7127f7d53020 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 4 Nov 2021 16:38:50 -0700 Subject: [PATCH 03/67] Update redirectURI param --- src/libs/API.js | 2 +- src/libs/actions/BankAccounts.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/API.js b/src/libs/API.js index 5a12cd154fa5..d290e9c09b33 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -870,7 +870,7 @@ function Wallet_GetOnfidoSDKToken() { */ function Plaid_GetLinkToken(parameters) { const commandName = 'Plaid_GetLinkToken'; - requireParameters(['redirectURI'], parameters, commandName); + requireParameters(['redirect_uri'], parameters, commandName); return Network.post('Plaid_GetLinkToken', parameters, CONST.NETWORK.METHOD.POST, true); } diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 63bcbcc85ab5..ec99756dd13a 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -50,7 +50,7 @@ Onyx.connect({ * @param {String} redirectURI */ function fetchPlaidLinkToken(redirectURI) { - API.Plaid_GetLinkToken(redirectURI) + API.Plaid_GetLinkToken({redirect_uri: redirectURI}) .then((response) => { if (response.jsonCode !== 200) { return; From 74866236154ea4d5660a9001164b2ec8b46c8a9e Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 4 Nov 2021 17:11:19 -0700 Subject: [PATCH 04/67] Add redirect new.e page --- src/components/AddPlaidBankAccount.js | 9 ++++++++- src/components/PlaidOAuth/oauth.js | 28 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/components/PlaidOAuth/oauth.js diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 8ce5a6cc4a1d..8535f90f4509 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -27,6 +27,7 @@ import * as ReimbursementAccountUtils from '../libs/ReimbursementAccountUtils'; import ReimbursementAccountForm from '../pages/ReimbursementAccount/ReimbursementAccountForm'; import getBankIcon from './Icon/BankIcons'; import Icon from './Icon'; +import getPlatform from '../libs/getPlatform'; const propTypes = { ...withLocalizePropTypes, @@ -106,8 +107,14 @@ class AddPlaidBankAccount extends React.Component { } componentDidMount() { + let redirectURI = ''; + if (getPlatform() === 'web') { + console.log("in web"); + // redirectURI = 'https://new.expensify.com/partners/plaid/oauth_web'; + redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + } clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(); + fetchPlaidLinkToken(redirectURI); } /** diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js new file mode 100644 index 000000000000..2f30d9756752 --- /dev/null +++ b/src/components/PlaidOAuth/oauth.js @@ -0,0 +1,28 @@ +import React, { useEffect } from 'react'; +import { usePlaidLink } from 'react-plaid-link'; +const OAuthLink = (callback, deps) => { + // The Link token from the first Link initialization + const linkToken = localStorage.getItem('link_token'); + const onSuccess = React.useCallback((public_token) => { + // send public_token to server, retrieve access_token and item_id + // return to "https://example.com" upon completion + }, deps); + const onExit = (err, metatdata) => { + // handle error... + }; + const config = { + token: linkToken, + receivedRedirectUri: window.location.href, //the redirect URI with an OAuth state ID parameter + onSuccess, + onExit, +}; + const { open, ready, error } = usePlaidLink(config); + // automatically reinitialize Link + useEffect(() => { + if (ready) { + open(); + } + }, [ready, open]); + return <>; +}; +export default OAuthLink; From b9df3006334485809e08c55ff3717abf869c5c8d Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 4 Nov 2021 17:16:58 -0700 Subject: [PATCH 05/67] Hook up OAuth redirect with onyx plaidLinkToken --- src/components/PlaidOAuth/oauth.js | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index 2f30d9756752..f31bbb490b59 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -1,8 +1,16 @@ import React, { useEffect } from 'react'; import { usePlaidLink } from 'react-plaid-link'; -const OAuthLink = (callback, deps) => { +import compose from "../../libs/compose"; +import withLocalize from "../withLocalize"; +import {withOnyx} from "react-native-onyx"; +import ONYXKEYS from "../../ONYXKEYS"; +import {plaidLinkDefaultProps, plaidLinkPropTypes} from "../PlaidLink/plaidLinkPropTypes"; +import PlaidLink from "../PlaidLink"; + +const OAuthLink = (props, callback, deps) => { // The Link token from the first Link initialization - const linkToken = localStorage.getItem('link_token'); + // const linkToken = localStorage.getItem('link_token'); + const linkToken = props.plaidLinkToken; const onSuccess = React.useCallback((public_token) => { // send public_token to server, retrieve access_token and item_id // return to "https://example.com" upon completion @@ -25,4 +33,20 @@ const OAuthLink = (callback, deps) => { }, [ready, open]); return <>; }; -export default OAuthLink; +OAuthLink.propTypes = plaidLinkPropTypes; +OAuthLink.defaultProps = plaidLinkDefaultProps; +OAuthLink.displayName = 'OAuthLink'; + +export default compose( + withOnyx({ + plaidLinkToken: { + key: ONYXKEYS.PLAID_LINK_TOKEN, + + // We always fetch a new token to call Plaid. If we don't then it's possible to open multiple Plaid Link instances. In particular, this can cause issues for Android e.g. + // inability to hand off to React Native once the bank connection is made. This is because an old stashed token will mount the PlaidLink component then it gets set again + // which will mount another PlaidLink component. + initWithStoredValues: false, + } + }) +)(OAuthLink); + From 80c3ae0598374605390af621d07c28c5e29f79e8 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Sun, 7 Nov 2021 16:33:09 -0500 Subject: [PATCH 06/67] Testing redirect_uri --- src/components/AddPlaidBankAccount.js | 3 ++- src/components/PlaidOAuth/oauth.js | 2 +- src/libs/API.js | 1 + src/libs/actions/BankAccounts.js | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 8535f90f4509..aaf0910d285f 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -111,7 +111,8 @@ class AddPlaidBankAccount extends React.Component { if (getPlatform() === 'web') { console.log("in web"); // redirectURI = 'https://new.expensify.com/partners/plaid/oauth_web'; - redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + redirectURI = 'https://www.expensify.com.dev/partners/plaid/oauth_callback.php'; } clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index f31bbb490b59..787db82152da 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -23,7 +23,7 @@ const OAuthLink = (props, callback, deps) => { receivedRedirectUri: window.location.href, //the redirect URI with an OAuth state ID parameter onSuccess, onExit, -}; + }; const { open, ready, error } = usePlaidLink(config); // automatically reinitialize Link useEffect(() => { diff --git a/src/libs/API.js b/src/libs/API.js index d290e9c09b33..2f126e3910cd 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -871,6 +871,7 @@ function Wallet_GetOnfidoSDKToken() { function Plaid_GetLinkToken(parameters) { const commandName = 'Plaid_GetLinkToken'; requireParameters(['redirect_uri'], parameters, commandName); + console.log(parameters); return Network.post('Plaid_GetLinkToken', parameters, CONST.NETWORK.METHOD.POST, true); } diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index ec99756dd13a..d0db866fb52b 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -50,6 +50,7 @@ Onyx.connect({ * @param {String} redirectURI */ function fetchPlaidLinkToken(redirectURI) { + console.log(redirectURI); API.Plaid_GetLinkToken({redirect_uri: redirectURI}) .then((response) => { if (response.jsonCode !== 200) { From 319cd0025a29274436f4eb4580428f17d5c22597 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Sun, 7 Nov 2021 17:17:44 -0500 Subject: [PATCH 07/67] Add redirect PLAID route --- src/ROUTES.js | 1 + src/components/AddPlaidBankAccount.js | 5 +++-- src/components/PlaidLink/index.native.js | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 9facdbd64a1b..1e8fd6970339 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -18,6 +18,7 @@ export default { BANK_ACCOUNT: 'bank-account/:stepToOpen?', BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, + OAUTH_PLAID: '/partners/plaid/oauth_web', HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index aaf0910d285f..ff52a850b3a2 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -111,8 +111,9 @@ class AddPlaidBankAccount extends React.Component { if (getPlatform() === 'web') { console.log("in web"); // redirectURI = 'https://new.expensify.com/partners/plaid/oauth_web'; - // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; - redirectURI = 'https://www.expensify.com.dev/partners/plaid/oauth_callback.php'; + redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + // redirectURI = 'https://expensify.com.dev/partners/plaid/oauth_callback.php'; + // https://expensify.com.dev/partners/plaid/oauth_callback.php } clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); diff --git a/src/components/PlaidLink/index.native.js b/src/components/PlaidLink/index.native.js index dab545d633f0..c677647396f6 100644 --- a/src/components/PlaidLink/index.native.js +++ b/src/components/PlaidLink/index.native.js @@ -13,7 +13,6 @@ class PlaidLink extends React.Component { } componentDidMount() { - console.log("here"); const emitter = new NativeEventEmitter(nativeModule); this.listener = emitter.addListener('onEvent', this.onEvent.bind(this)); From a545977f86c8ed66d4665e52fffc720d686dab4b Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Sun, 7 Nov 2021 17:23:18 -0500 Subject: [PATCH 08/67] Hook up OAuth to modalStack --- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 5 +++++ src/libs/Navigation/linkingConfig.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 2d1c236e896b..f87a4f03f1c6 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -37,6 +37,7 @@ import WorkspaceBillsPage from '../../../pages/workspace/bills/WorkspaceBillsPag import WorkspaceTravelPage from '../../../pages/workspace/travel/WorkspaceTravelPage'; import WorkspaceMembersPage from '../../../pages/workspace/WorkspaceMembersPage'; import WorkspaceBankAccountPage from '../../../pages/workspace/WorkspaceBankAccountPage'; +import OAuthLink from "../../../components/PlaidOAuth/oauth"; import CONST from '../../../CONST'; const defaultSubRouteOptions = { @@ -225,6 +226,10 @@ const SettingsModalStackNavigator = createModalStackNavigator([ name: 'ReimbursementAccount', initialParams: {stepToOpen: CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT}, }, + { + Component: OAuthLink, + name: 'OAuth_Plaid', + }, ]); const EnablePaymentsStackNavigator = createModalStackNavigator([{ diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index e206ae4edfcd..75c3e02b948c 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -103,6 +103,10 @@ export default { path: ROUTES.BANK_ACCOUNT, exact: true, }, + OAuth_PLaid: { + path: ROUTES.OAUTH_PLAID, + exact: true, + }, }, }, Report_Details: { From a6ca4fb7650e513011bc742ed6f5a03c2149b415 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Sun, 7 Nov 2021 17:30:47 -0500 Subject: [PATCH 09/67] Switch out PlaidLink with OAuthLink --- src/ROUTES.js | 2 +- src/components/AddPlaidBankAccount.js | 33 +++++++++++++++------------ src/components/PlaidOAuth/oauth.js | 2 ++ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 1e8fd6970339..7c469cc1d2d0 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -18,7 +18,7 @@ export default { BANK_ACCOUNT: 'bank-account/:stepToOpen?', BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, - OAUTH_PLAID: '/partners/plaid/oauth_web', + OAUTH_PLAID: 'partners/plaid/oauth_web', HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index ff52a850b3a2..e0ae3400a367 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -9,6 +9,7 @@ import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import Log from '../libs/Log'; import PlaidLink from './PlaidLink'; +import OAuthLink from "./PlaidOAuth/oauth"; import { clearPlaidBankAccountsAndToken, fetchPlaidLinkToken, @@ -170,20 +171,24 @@ class AddPlaidBankAccount extends React.Component { )} {!_.isEmpty(this.props.plaidLinkToken) && ( - { - Log.info('[PlaidLink] Success!'); - getPlaidBankAccounts(publicToken, metadata.institution.name); - this.setState({institution: metadata.institution}); - }} - onError={(error) => { - Log.hmmm('[PlaidLink] Error: ', error.message); - }} - - // User prematurely exited the Plaid flow - // eslint-disable-next-line react/jsx-props-no-multi-spaces - onExit={this.props.onExitPlaid} + // { + // Log.info('[PlaidLink] Success!'); + // getPlaidBankAccounts(publicToken, metadata.institution.name); + // this.setState({institution: metadata.institution}); + // }} + // onError={(error) => { + // Log.hmmm('[PlaidLink] Error: ', error.message); + // }} + // + // // User prematurely exited the Plaid flow + // // eslint-disable-next-line react/jsx-props-no-multi-spaces + // onExit={this.props.onExitPlaid} + // /> + )} {accounts.length > 0 && ( diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index 787db82152da..323df9be8e72 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -8,6 +8,7 @@ import {plaidLinkDefaultProps, plaidLinkPropTypes} from "../PlaidLink/plaidLinkP import PlaidLink from "../PlaidLink"; const OAuthLink = (props, callback, deps) => { + console.log("in OAuthLink"); // The Link token from the first Link initialization // const linkToken = localStorage.getItem('link_token'); const linkToken = props.plaidLinkToken; @@ -16,6 +17,7 @@ const OAuthLink = (props, callback, deps) => { // return to "https://example.com" upon completion }, deps); const onExit = (err, metatdata) => { + console.log(err); // handle error... }; const config = { From c64322176a14e8b9ade880b0907febf26c3fec0e Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 8 Nov 2021 12:10:55 -0500 Subject: [PATCH 10/67] Add redirect screen separate from settings --- src/components/AddPlaidBankAccount.js | 37 ++++++++++---------- src/components/PlaidLink/index.js | 2 ++ src/components/PlaidOAuth/oauth.js | 49 +++++++++++++++++++++++++-- src/libs/API.js | 1 - src/libs/Navigation/linkingConfig.js | 9 ++--- src/libs/actions/BankAccounts.js | 4 +-- 6 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index e0ae3400a367..164dd12cb67c 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -112,9 +112,10 @@ class AddPlaidBankAccount extends React.Component { if (getPlatform() === 'web') { console.log("in web"); // redirectURI = 'https://new.expensify.com/partners/plaid/oauth_web'; - redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; // redirectURI = 'https://expensify.com.dev/partners/plaid/oauth_callback.php'; // https://expensify.com.dev/partners/plaid/oauth_callback.php + redirectURI = 'http://localhost:8080/partners/plaid/oauth_web/'; } clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); @@ -171,25 +172,25 @@ class AddPlaidBankAccount extends React.Component { )} {!_.isEmpty(this.props.plaidLinkToken) && ( - // { - // Log.info('[PlaidLink] Success!'); - // getPlaidBankAccounts(publicToken, metadata.institution.name); - // this.setState({institution: metadata.institution}); - // }} - // onError={(error) => { - // Log.hmmm('[PlaidLink] Error: ', error.message); - // }} + { + Log.info('[PlaidLink] Success!'); + getPlaidBankAccounts(publicToken, metadata.institution.name); + this.setState({institution: metadata.institution}); + }} + onError={(error) => { + Log.hmmm('[PlaidLink] Error: ', error.message); + }} + + // User prematurely exited the Plaid flow + // eslint-disable-next-line react/jsx-props-no-multi-spaces + onExit={this.props.onExitPlaid} + /> + // - )} {accounts.length > 0 && ( { const {open, ready, error} = usePlaidLink({ token: props.token, onSuccess, + receivedRedirectUri: null, //the redirect URI with an OAuth state ID parameter onExit: (exitError, metadata) => { Log.info('[PlaidLink] Exit: ', false, {exitError, metadata}); + console.log(exitError); props.onExit(); }, onEvent: (event, metadata) => { diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index 323df9be8e72..81a70451d1f5 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -6,6 +6,16 @@ import {withOnyx} from "react-native-onyx"; import ONYXKEYS from "../../ONYXKEYS"; import {plaidLinkDefaultProps, plaidLinkPropTypes} from "../PlaidLink/plaidLinkPropTypes"; import PlaidLink from "../PlaidLink"; +import ScreenWrapper from "../ScreenWrapper"; +import HeaderWithCloseButton from "../HeaderWithCloseButton"; +import Navigation from "../../libs/Navigation/Navigation"; +import ROUTES from "../../ROUTES"; +import WorkspaceSection from "../../pages/workspace/WorkspaceSection"; +import {BankArrowPink} from "../Icon/Illustrations"; +import {Bank, RotateLeft} from "../Icon/Expensicons"; +import {requestResetFreePlanBankAccount} from "../../libs/actions/BankAccounts"; +import Text from "../Text"; +import WorkspaceResetBankAccountModal from "../../pages/workspace/WorkspaceResetBankAccountModal"; const OAuthLink = (props, callback, deps) => { console.log("in OAuthLink"); @@ -20,9 +30,10 @@ const OAuthLink = (props, callback, deps) => { console.log(err); // handle error... }; + const newRedirecUri = ''; const config = { token: linkToken, - receivedRedirectUri: window.location.href, //the redirect URI with an OAuth state ID parameter + receivedRedirectUri: encodeURI(window.location.href), //the redirect URI with an OAuth state ID parameter onSuccess, onExit, }; @@ -33,7 +44,41 @@ const OAuthLink = (props, callback, deps) => { open(); } }, [ready, open]); - return <>; + // return <>; + return ( + + Navigation.navigate(ROUTES.getWorkspaceInitialRoute(this.props.route.params.policyID))} + shouldShowBackButton + /> + + + {'Test text'} + + + + + ); + }; OAuthLink.propTypes = plaidLinkPropTypes; OAuthLink.defaultProps = plaidLinkDefaultProps; diff --git a/src/libs/API.js b/src/libs/API.js index 2f126e3910cd..d290e9c09b33 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -871,7 +871,6 @@ function Wallet_GetOnfidoSDKToken() { function Plaid_GetLinkToken(parameters) { const commandName = 'Plaid_GetLinkToken'; requireParameters(['redirect_uri'], parameters, commandName); - console.log(parameters); return Network.post('Plaid_GetLinkToken', parameters, CONST.NETWORK.METHOD.POST, true); } diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 75c3e02b948c..f8ba57bfd4c0 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -103,10 +103,6 @@ export default { path: ROUTES.BANK_ACCOUNT, exact: true, }, - OAuth_PLaid: { - path: ROUTES.OAUTH_PLAID, - exact: true, - }, }, }, Report_Details: { @@ -184,6 +180,11 @@ export default { RequestCall_Root: ROUTES.REQUEST_CALL, }, }, + OAUTH_PLAID_REDIRECT: { + screens: { + OAuth_PLaid: ROUTES.OAUTH_PLAID, + }, + }, }, }, }; diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index d0db866fb52b..412371ee19b7 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -50,13 +50,12 @@ Onyx.connect({ * @param {String} redirectURI */ function fetchPlaidLinkToken(redirectURI) { - console.log(redirectURI); API.Plaid_GetLinkToken({redirect_uri: redirectURI}) .then((response) => { if (response.jsonCode !== 200) { return; } - + console.log(response); Onyx.merge(ONYXKEYS.PLAID_LINK_TOKEN, response.linkToken); }); } @@ -105,6 +104,7 @@ function getPlaidBankAccounts(publicToken, bank) { if (response.jsonCode === 666 && response.title === CONST.BANK_ACCOUNT.PLAID.ERROR.TOO_MANY_ATTEMPTS) { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {isPlaidDisabled: true}); } + console.log("getPlaidBank", response); plaidAccessToken = response.plaidAccessToken; From 727a1caf2780c692d550523e21534eb812198ce2 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 8 Nov 2021 12:24:34 -0500 Subject: [PATCH 11/67] Add OAuth to AuthScreens --- src/components/PlaidOAuth/oauth.js | 3 +-- src/libs/Navigation/AppNavigator/AuthScreens.js | 7 +++++++ .../Navigation/AppNavigator/ModalStackNavigators.js | 10 ++++++---- src/libs/Navigation/linkingConfig.js | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index 81a70451d1f5..391a765ed869 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -12,8 +12,6 @@ import Navigation from "../../libs/Navigation/Navigation"; import ROUTES from "../../ROUTES"; import WorkspaceSection from "../../pages/workspace/WorkspaceSection"; import {BankArrowPink} from "../Icon/Illustrations"; -import {Bank, RotateLeft} from "../Icon/Expensicons"; -import {requestResetFreePlanBankAccount} from "../../libs/actions/BankAccounts"; import Text from "../Text"; import WorkspaceResetBankAccountModal from "../../pages/workspace/WorkspaceResetBankAccountModal"; @@ -25,6 +23,7 @@ const OAuthLink = (props, callback, deps) => { const onSuccess = React.useCallback((public_token) => { // send public_token to server, retrieve access_token and item_id // return to "https://example.com" upon completion + console.log("in success for OAuthLink"); }, deps); const onExit = (err, metatdata) => { console.log(err); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 4f6ec4c3c1c1..5f9c9f2fba39 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -55,6 +55,7 @@ import { WorkspaceInviteModalStackNavigator, RequestCallModalStackNavigator, ReportDetailsModalStackNavigator, + PlaidOAuthModalStackNavigator, } from './ModalStackNavigators'; import SCREENS from '../../../SCREENS'; import Timers from '../../Timers'; @@ -394,6 +395,12 @@ class AuthScreens extends React.Component { component={IOUSendModalStackNavigator} listeners={modalScreenListeners} /> + ); } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index f87a4f03f1c6..df0cee10398a 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -226,10 +226,6 @@ const SettingsModalStackNavigator = createModalStackNavigator([ name: 'ReimbursementAccount', initialParams: {stepToOpen: CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT}, }, - { - Component: OAuthLink, - name: 'OAuth_Plaid', - }, ]); const EnablePaymentsStackNavigator = createModalStackNavigator([{ @@ -257,6 +253,11 @@ const RequestCallModalStackNavigator = createModalStackNavigator([{ name: 'RequestCall_Root', }]); +const PlaidOAuthModalStackNavigator = createModalStackNavigator([{ + Component: OAuthLink, + name: 'OAuth_Plaid_Root', +}]); + export { IOUBillStackNavigator, IOURequestModalStackNavigator, @@ -274,4 +275,5 @@ export { ReimbursementAccountModalStackNavigator, WorkspaceInviteModalStackNavigator, RequestCallModalStackNavigator, + PlaidOAuthModalStackNavigator, }; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index f8ba57bfd4c0..ab5bd1f8a0d2 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -182,7 +182,7 @@ export default { }, OAUTH_PLAID_REDIRECT: { screens: { - OAuth_PLaid: ROUTES.OAUTH_PLAID, + OAuth_Plaid_Root: ROUTES.OAUTH_PLAID, }, }, }, From d072bc53360cd4c79d027f1cb22dc472ca46aff0 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 8 Nov 2021 13:02:08 -0500 Subject: [PATCH 12/67] OAuth works using platypus oauth account --- src/components/AddPlaidBankAccount.js | 11 +---------- src/components/PlaidOAuth/oauth.js | 3 ++- src/libs/actions/BankAccounts.js | 1 - 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 164dd12cb67c..8f99d37f68c0 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -110,12 +110,7 @@ class AddPlaidBankAccount extends React.Component { componentDidMount() { let redirectURI = ''; if (getPlatform() === 'web') { - console.log("in web"); - // redirectURI = 'https://new.expensify.com/partners/plaid/oauth_web'; - // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; - // redirectURI = 'https://expensify.com.dev/partners/plaid/oauth_callback.php'; - // https://expensify.com.dev/partners/plaid/oauth_callback.php - redirectURI = 'http://localhost:8080/partners/plaid/oauth_web/'; + redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; } clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); @@ -187,10 +182,6 @@ class AddPlaidBankAccount extends React.Component { // eslint-disable-next-line react/jsx-props-no-multi-spaces onExit={this.props.onExitPlaid} /> - // )} {accounts.length > 0 && ( { +const OAuthLink = ({plaidLinkToken, props, callback, deps}) => { console.log("in OAuthLink"); + console.log(plaidLinkToken); // The Link token from the first Link initialization // const linkToken = localStorage.getItem('link_token'); const linkToken = props.plaidLinkToken; diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 412371ee19b7..837b6a9e0193 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -104,7 +104,6 @@ function getPlaidBankAccounts(publicToken, bank) { if (response.jsonCode === 666 && response.title === CONST.BANK_ACCOUNT.PLAID.ERROR.TOO_MANY_ATTEMPTS) { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {isPlaidDisabled: true}); } - console.log("getPlaidBank", response); plaidAccessToken = response.plaidAccessToken; From 9709dbf91dfadc832beb92274142cc4fbf067a94 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 8 Nov 2021 14:53:56 -0500 Subject: [PATCH 13/67] Make statedID work within addplaidbankaccount --- src/components/AddPlaidBankAccount.js | 15 ++++++++++++++- src/components/PlaidLink/index.js | 3 ++- src/components/PlaidOAuth/oauth.js | 6 ++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 8f99d37f68c0..fe25e1949177 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -103,14 +103,26 @@ class AddPlaidBankAccount extends React.Component { institution: {}, }; + this.receivedRedirectUri = null; this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); } componentDidMount() { + console.log('in componentDidMount', window.location.href); + const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; + const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); + console.log(oauth_state_id); + // If we're reinitializing the PlaidLink after OAuth, then don't grab the token again + if (oauth_state_id) { + this.receivedRedirectUri = window.location.href; + return; + } + let redirectURI = ''; if (getPlatform() === 'web') { - redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + redirectURI = 'http://localhost:8080/bank-account'; } clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); @@ -181,6 +193,7 @@ class AddPlaidBankAccount extends React.Component { // User prematurely exited the Plaid flow // eslint-disable-next-line react/jsx-props-no-multi-spaces onExit={this.props.onExitPlaid} + receivedRedirectUri={this.receivedRedirectUri} /> )} {accounts.length > 0 && ( diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index f22cf9bbeecb..478e2da17a00 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -5,6 +5,7 @@ import Log from '../../libs/Log'; const PlaidLink = (props) => { console.log("here in index PlaidLink"); + console.log(props.receivedRedirectUri); const onSuccess = useCallback((publicToken, metadata) => { props.onSuccess({publicToken, metadata}); }, []); @@ -12,7 +13,7 @@ const PlaidLink = (props) => { const {open, ready, error} = usePlaidLink({ token: props.token, onSuccess, - receivedRedirectUri: null, //the redirect URI with an OAuth state ID parameter + receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter onExit: (exitError, metadata) => { Log.info('[PlaidLink] Exit: ', false, {exitError, metadata}); console.log(exitError); diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index 96e7ba069a8c..b4d2e2956eba 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -15,9 +15,12 @@ import {BankArrowPink} from "../Icon/Illustrations"; import Text from "../Text"; import WorkspaceResetBankAccountModal from "../../pages/workspace/WorkspaceResetBankAccountModal"; -const OAuthLink = ({plaidLinkToken, props, callback, deps}) => { +// const OAuthLink = ({plaidLinkToken, props, callback, deps}) => { +const OAuthLink = ({plaidLinkToken}) => { console.log("in OAuthLink"); console.log(plaidLinkToken); + console.log(props); + // The Link token from the first Link initialization // const linkToken = localStorage.getItem('link_token'); const linkToken = props.plaidLinkToken; @@ -30,7 +33,6 @@ const OAuthLink = ({plaidLinkToken, props, callback, deps}) => { console.log(err); // handle error... }; - const newRedirecUri = ''; const config = { token: linkToken, receivedRedirectUri: encodeURI(window.location.href), //the redirect URI with an OAuth state ID parameter From 3d758fc380a9f5051f64434d7746a3ad10e65d27 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 8 Nov 2021 14:58:37 -0500 Subject: [PATCH 14/67] Work with current plaidLink page --- src/components/AddPlaidBankAccount.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index fe25e1949177..15cc8474fc7a 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -178,7 +178,7 @@ class AddPlaidBankAccount extends React.Component { )} - {!_.isEmpty(this.props.plaidLinkToken) && ( + {(!_.isEmpty(this.props.plaidLinkToken) || this.receivedRedirectUri) && ( { From e9894d28a87513c73c8fdfc8c8ac20b5670bf3af Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 13:05:16 -0500 Subject: [PATCH 15/67] Setup new page with OAuthLink --- src/components/AddPlaidBankAccount.js | 39 +++++++++++---- src/components/PlaidLink/index.js | 2 + src/components/PlaidOAuth/oauth.js | 47 +++---------------- .../ReimbursementAccount/PlaidOAuthPage.js | 16 +++++++ 4 files changed, 53 insertions(+), 51 deletions(-) create mode 100644 src/pages/ReimbursementAccount/PlaidOAuthPage.js diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 15cc8474fc7a..e47d55c13320 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -116,16 +116,15 @@ class AddPlaidBankAccount extends React.Component { // If we're reinitializing the PlaidLink after OAuth, then don't grab the token again if (oauth_state_id) { this.receivedRedirectUri = window.location.href; - return; - } - - let redirectURI = ''; - if (getPlatform() === 'web') { - // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; - redirectURI = 'http://localhost:8080/bank-account'; + } else { + let redirectURI = ''; + if (getPlatform() === 'web') { + // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + redirectURI = 'http://localhost:8080/bank-account'; + } + clearPlaidBankAccountsAndToken(); + fetchPlaidLinkToken(redirectURI); } - clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(redirectURI); } /** @@ -178,11 +177,31 @@ class AddPlaidBankAccount extends React.Component { )} - {(!_.isEmpty(this.props.plaidLinkToken) || this.receivedRedirectUri) && ( + {/*{!_.isEmpty(this.props.plaidLinkToken) && this.receivedRedirectUri && (*/} + {/* {*/} + {/* Log.info('[PlaidLink] Success!');*/} + {/* console.log('[PlaidLink] Success!');*/} + {/* getPlaidBankAccounts(publicToken, metadata.institution.name);*/} + {/* this.setState({institution: metadata.institution});*/} + {/* }}*/} + {/* onError={(error) => {*/} + {/* Log.hmmm('[PlaidLink] Error: ', error.message);*/} + {/* }}*/} + + {/* // User prematurely exited the Plaid flow*/} + {/* // eslint-disable-next-line react/jsx-props-no-multi-spaces*/} + {/* onExit={this.props.onExitPlaid}*/} + {/* receivedRedirectUri={this.receivedRedirectUri}*/} + {/* />*/} + {/*)}*/} + {!_.isEmpty(this.props.plaidLinkToken) && ( { Log.info('[PlaidLink] Success!'); + console.log('[PlaidLink] Success!'); getPlaidBankAccounts(publicToken, metadata.institution.name); this.setState({institution: metadata.institution}); }} diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index 478e2da17a00..c1b8c6d610de 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -20,6 +20,7 @@ const PlaidLink = (props) => { props.onExit(); }, onEvent: (event, metadata) => { + console.log({event, metadata}, '[PlaidLink] onEvent'); Log.info('[PlaidLink] Event: ', false, {event, metadata}); }, }); @@ -33,6 +34,7 @@ const PlaidLink = (props) => { if (!ready) { return; } + console.log("gonna hit open"); open(); }, [ready, error]); diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js index b4d2e2956eba..f5bf45ab4855 100644 --- a/src/components/PlaidOAuth/oauth.js +++ b/src/components/PlaidOAuth/oauth.js @@ -15,27 +15,26 @@ import {BankArrowPink} from "../Icon/Illustrations"; import Text from "../Text"; import WorkspaceResetBankAccountModal from "../../pages/workspace/WorkspaceResetBankAccountModal"; -// const OAuthLink = ({plaidLinkToken, props, callback, deps}) => { -const OAuthLink = ({plaidLinkToken}) => { +const OAuthLink = (props) => { console.log("in OAuthLink"); - console.log(plaidLinkToken); console.log(props); // The Link token from the first Link initialization // const linkToken = localStorage.getItem('link_token'); const linkToken = props.plaidLinkToken; - const onSuccess = React.useCallback((public_token) => { + const onSuccess = React.useCallback((publicToken, metadata) => { // send public_token to server, retrieve access_token and item_id // return to "https://example.com" upon completion console.log("in success for OAuthLink"); - }, deps); + props.onSuccess({publicToken, metadata}) + }, []); const onExit = (err, metatdata) => { console.log(err); // handle error... }; const config = { token: linkToken, - receivedRedirectUri: encodeURI(window.location.href), //the redirect URI with an OAuth state ID parameter + receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter onSuccess, onExit, }; @@ -46,41 +45,7 @@ const OAuthLink = ({plaidLinkToken}) => { open(); } }, [ready, open]); - // return <>; - return ( - - Navigation.navigate(ROUTES.getWorkspaceInitialRoute(this.props.route.params.policyID))} - shouldShowBackButton - /> - - - {'Test text'} - - - - - ); - + return <>; }; OAuthLink.propTypes = plaidLinkPropTypes; OAuthLink.defaultProps = plaidLinkDefaultProps; diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js new file mode 100644 index 000000000000..fef88e489202 --- /dev/null +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -0,0 +1,16 @@ +import React from "react"; +import {View} from 'react-native'; +import OAuthLink from "../../components/PlaidOAuth/oauth"; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; + + +const PlaidOAuthPage = (props) => { + return ( + + + + ); +} + +PlaidOAuthPage.displayName = 'PlaidOAuthPage'; +export default withLocalize(PlaidOAuthPage); From 1dd666f28856bfaf6ab958fcc935454bebe8e84e Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 13:29:56 -0500 Subject: [PATCH 16/67] Fill out PlaidOAuthPage --- .../ReimbursementAccount/PlaidOAuthPage.js | 76 ++++++++++++++++++- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index fef88e489202..e0146787981e 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -2,15 +2,85 @@ import React from "react"; import {View} from 'react-native'; import OAuthLink from "../../components/PlaidOAuth/oauth"; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; - +import ONYXKEYS from "../../ONYXKEYS"; +import {withOnyx} from "react-native-onyx"; +import ReimbursementAccountForm from "./ReimbursementAccountForm"; +import _ from "underscore"; +import Text from "../../components/Text"; +import styles from "../../styles/styles"; +import Icon from "../../components/Icon"; +import ExpensiPicker from "../../components/ExpensiPicker"; +import lodashGet from "lodash/get"; +import getBankIcon from "../../components/Icon/BankIcons"; +import GenericBank from '../../../assets/images/bankicons/generic-bank-account.svg'; +import variables from "../../styles/variables"; const PlaidOAuthPage = (props) => { + const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; + const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); + console.log("in PlaidOAuthPage", oauth_state_id); + const bankAccounts = lodashGet(this.props.plaidBankAccounts, 'accounts', []); + const linkToken = props.plaidLinkToken; + const icon = GenericBank; + const iconSize = variables.iconSizeExtraLarge; + // const {icon, iconSize} = getBankIcon(this.state.institution.name); + return ( - + + {bankAccounts.length > 0 && ( + + {!_.isEmpty(this.props.text) && ( + {this.props.text} + )} + + + {this.state.institution.name} + + + { + this.setState({selectedIndex: Number(index)}); + this.clearError('selectedBank'); + }} + items={options} + placeholder={_.isUndefined(this.state.selectedIndex) ? { + value: '', + label: this.props.translate('bankAccount.chooseAnAccount'), + } : {}} + value={this.state.selectedIndex} + hasError={this.getErrors().selectedBank} + /> + + + )} ); } PlaidOAuthPage.displayName = 'PlaidOAuthPage'; -export default withLocalize(PlaidOAuthPage); +export default compose( + withLocalize, + withOnyx({ + plaidLinkToken: { + // If we hit here we've been redirected to reinitialize the PlaidLink + key: ONYXKEYS.PLAID_LINK_TOKEN, + }, + plaidBankAccounts: { + key: ONYXKEYS.PLAID_BANK_ACCOUNTS, + }, + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + }), +)(PlaidOAuthPage); From c50afb84dd9e565df9a03e1118f3677fb57d4e89 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 13:41:10 -0500 Subject: [PATCH 17/67] Finish attaching props to new PlaidRedirect page --- src/components/PlaidLink/index.native.js | 1 - .../Navigation/AppNavigator/ModalStackNavigators.js | 4 ++-- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 11 ++++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/PlaidLink/index.native.js b/src/components/PlaidLink/index.native.js index c677647396f6..da6fdf8dcb93 100644 --- a/src/components/PlaidLink/index.native.js +++ b/src/components/PlaidLink/index.native.js @@ -21,7 +21,6 @@ class PlaidLink extends React.Component { token: this.props.token, }, onSuccess: ({publicToken, metadata}) => { - console.log("here in onSuccess", metadata); this.props.onSuccess({publicToken, metadata}); }, }); diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index df0cee10398a..abc46ea5a72a 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -37,7 +37,7 @@ import WorkspaceBillsPage from '../../../pages/workspace/bills/WorkspaceBillsPag import WorkspaceTravelPage from '../../../pages/workspace/travel/WorkspaceTravelPage'; import WorkspaceMembersPage from '../../../pages/workspace/WorkspaceMembersPage'; import WorkspaceBankAccountPage from '../../../pages/workspace/WorkspaceBankAccountPage'; -import OAuthLink from "../../../components/PlaidOAuth/oauth"; +import PlaidOAuthPage from '../../../pages/ReimbursementAccount/PlaidOAuthPage'; import CONST from '../../../CONST'; const defaultSubRouteOptions = { @@ -254,7 +254,7 @@ const RequestCallModalStackNavigator = createModalStackNavigator([{ }]); const PlaidOAuthModalStackNavigator = createModalStackNavigator([{ - Component: OAuthLink, + Component: PlaidOAuthPage, name: 'OAuth_Plaid_Root', }]); diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index e0146787981e..c341e398ace7 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -11,16 +11,21 @@ import styles from "../../styles/styles"; import Icon from "../../components/Icon"; import ExpensiPicker from "../../components/ExpensiPicker"; import lodashGet from "lodash/get"; +import compose from '../../libs/compose'; import getBankIcon from "../../components/Icon/BankIcons"; import GenericBank from '../../../assets/images/bankicons/generic-bank-account.svg'; import variables from "../../styles/variables"; -const PlaidOAuthPage = (props) => { +const PlaidOAuthPage = ({ + plaidLinkToken, + plaidBankAccounts, + reimbursementAccount, +}) => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); console.log("in PlaidOAuthPage", oauth_state_id); - const bankAccounts = lodashGet(this.props.plaidBankAccounts, 'accounts', []); - const linkToken = props.plaidLinkToken; + const bankAccounts = lodashGet(plaidBankAccounts, 'accounts', []); + const linkToken = plaidLinkToken; const icon = GenericBank; const iconSize = variables.iconSizeExtraLarge; // const {icon, iconSize} = getBankIcon(this.state.institution.name); From 1413ad4a5010f6509bcc4a614a0227617ee42a9b Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 14:18:49 -0500 Subject: [PATCH 18/67] Setup to reuse AddPlaidBankAccount --- src/components/AddPlaidBankAccount.js | 44 ++---- src/components/PlaidLink/index.js | 3 +- .../ReimbursementAccount/PlaidOAuthPage.js | 136 ++++++++++++------ 3 files changed, 102 insertions(+), 81 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index e47d55c13320..d62ec7def33f 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -80,6 +80,9 @@ const propTypes = { /** Additional text to display */ text: PropTypes.string, + + /** If coming from the Plaid OAuth flow, contains stateID */ + receivedRedirectURI: PropTypes.string, }; const defaultProps = { @@ -109,22 +112,12 @@ class AddPlaidBankAccount extends React.Component { } componentDidMount() { - console.log('in componentDidMount', window.location.href); - const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; - const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); - console.log(oauth_state_id); - // If we're reinitializing the PlaidLink after OAuth, then don't grab the token again - if (oauth_state_id) { - this.receivedRedirectUri = window.location.href; - } else { - let redirectURI = ''; - if (getPlatform() === 'web') { - // redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; - redirectURI = 'http://localhost:8080/bank-account'; - } - clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(redirectURI); + let redirectURI = ''; + if (getPlatform() === 'web') { + redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; } + clearPlaidBankAccountsAndToken(); + fetchPlaidLinkToken(redirectURI); } /** @@ -177,25 +170,6 @@ class AddPlaidBankAccount extends React.Component { )} - {/*{!_.isEmpty(this.props.plaidLinkToken) && this.receivedRedirectUri && (*/} - {/* {*/} - {/* Log.info('[PlaidLink] Success!');*/} - {/* console.log('[PlaidLink] Success!');*/} - {/* getPlaidBankAccounts(publicToken, metadata.institution.name);*/} - {/* this.setState({institution: metadata.institution});*/} - {/* }}*/} - {/* onError={(error) => {*/} - {/* Log.hmmm('[PlaidLink] Error: ', error.message);*/} - {/* }}*/} - - {/* // User prematurely exited the Plaid flow*/} - {/* // eslint-disable-next-line react/jsx-props-no-multi-spaces*/} - {/* onExit={this.props.onExitPlaid}*/} - {/* receivedRedirectUri={this.receivedRedirectUri}*/} - {/* />*/} - {/*)}*/} {!_.isEmpty(this.props.plaidLinkToken) && ( )} {accounts.length > 0 && ( diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index c1b8c6d610de..bd5df22ef636 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -5,7 +5,6 @@ import Log from '../../libs/Log'; const PlaidLink = (props) => { console.log("here in index PlaidLink"); - console.log(props.receivedRedirectUri); const onSuccess = useCallback((publicToken, metadata) => { props.onSuccess({publicToken, metadata}); }, []); @@ -13,7 +12,6 @@ const PlaidLink = (props) => { const {open, ready, error} = usePlaidLink({ token: props.token, onSuccess, - receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter onExit: (exitError, metadata) => { Log.info('[PlaidLink] Exit: ', false, {exitError, metadata}); console.log(exitError); @@ -23,6 +21,7 @@ const PlaidLink = (props) => { console.log({event, metadata}, '[PlaidLink] onEvent'); Log.info('[PlaidLink] Event: ', false, {event, metadata}); }, + receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter }); useEffect(() => { diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index c341e398ace7..9d9060f3feed 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -15,6 +15,19 @@ import compose from '../../libs/compose'; import getBankIcon from "../../components/Icon/BankIcons"; import GenericBank from '../../../assets/images/bankicons/generic-bank-account.svg'; import variables from "../../styles/variables"; +import Log from "../../libs/Log"; +import {getPlaidBankAccounts} from "../../libs/actions/BankAccounts"; +import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import Navigation from '../../libs/Navigation/Navigation'; +import { + addPersonalBankAccount, +} from '../../libs/actions/BankAccounts'; +import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; + +const propTypes = { + ...withLocalizePropTypes, +}; const PlaidOAuthPage = ({ plaidLinkToken, @@ -24,55 +37,90 @@ const PlaidOAuthPage = ({ const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); console.log("in PlaidOAuthPage", oauth_state_id); - const bankAccounts = lodashGet(plaidBankAccounts, 'accounts', []); - const linkToken = plaidLinkToken; - const icon = GenericBank; - const iconSize = variables.iconSizeExtraLarge; - // const {icon, iconSize} = getBankIcon(this.state.institution.name); + + // Need to differentiate between personal and business bank account return ( - - + + { + addPersonalBankAccount(account, password, plaidLinkToken); + }} + receivedRedirectURI={(new URL(window.location.href))} + onExitPlaid={Navigation.dismissModal} + plaidLinkToken={plaidLinkToken} /> - {bankAccounts.length > 0 && ( - - {!_.isEmpty(this.props.text) && ( - {this.props.text} - )} - - - {this.state.institution.name} - - - { - this.setState({selectedIndex: Number(index)}); - this.clearError('selectedBank'); - }} - items={options} - placeholder={_.isUndefined(this.state.selectedIndex) ? { - value: '', - label: this.props.translate('bankAccount.chooseAnAccount'), - } : {}} - value={this.state.selectedIndex} - hasError={this.getErrors().selectedBank} - /> - - - )} - + ); -} +}; +// const PlaidOAuthPage = ({ +// plaidLinkToken, +// plaidBankAccounts, +// reimbursementAccount, +// }) => { +// const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; +// const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); +// console.log("in PlaidOAuthPage", oauth_state_id); +// const bankAccounts = lodashGet(plaidBankAccounts, 'accounts', []); +// const linkToken = plaidLinkToken; +// const icon = GenericBank; +// const iconSize = variables.iconSizeExtraLarge; +// // const {icon, iconSize} = getBankIcon(this.state.institution.name); +// +// return ( +// +// { +// Log.info('[PlaidLink] Success!'); +// console.log('[PlaidLink] Success!'); +// getPlaidBankAccounts(publicToken, metadata.institution.name); +// // this.setState({institution: metadata.institution}); +// }} +// /> +// {bankAccounts.length > 0 && ( +// +// {!_.isEmpty(this.props.text) && ( +// {this.props.text} +// )} +// +// +// {this.state.institution.name} +// +// +// { +// this.setState({selectedIndex: Number(index)}); +// this.clearError('selectedBank'); +// }} +// items={options} +// placeholder={_.isUndefined(this.state.selectedIndex) ? { +// value: '', +// label: this.props.translate('bankAccount.chooseAnAccount'), +// } : {}} +// value={this.state.selectedIndex} +// hasError={this.getErrors().selectedBank} +// /> +// +// +// )} +// +// ); +// } +// PlaidOAuthPage.displayName = 'PlaidOAuthPage'; export default compose( withLocalize, From 6587c1158bb4e43bde90a881caaa991f5fe9f178 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 14:36:54 -0500 Subject: [PATCH 19/67] Things work now --- src/components/AddPlaidBankAccount.js | 15 ++-- src/components/PlaidLink/index.js | 2 +- .../ReimbursementAccount/PlaidOAuthPage.js | 68 +------------------ 3 files changed, 15 insertions(+), 70 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index d62ec7def33f..c3cf6377eb30 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -93,6 +93,7 @@ const defaultProps = { onExitPlaid: () => {}, onSubmit: () => {}, text: '', + receivedRedirectURI: '', }; class AddPlaidBankAccount extends React.Component { @@ -106,7 +107,6 @@ class AddPlaidBankAccount extends React.Component { institution: {}, }; - this.receivedRedirectUri = null; this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); } @@ -116,8 +116,15 @@ class AddPlaidBankAccount extends React.Component { if (getPlatform() === 'web') { redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; } - clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(redirectURI); + + console.log('AddPlaidBank redirectURI', this.props.receivedRedirectURI); + console.log('AddPlaidBank linkToken', this.props.plaidLinkToken); + + // If we're coming from re-initialization then we need to reuse the existing plaidLinkToken + if (!this.props.receivedRedirectURI && !this.props.plaidLinkToken) { + clearPlaidBankAccountsAndToken(); + fetchPlaidLinkToken(redirectURI); + } } /** @@ -186,7 +193,7 @@ class AddPlaidBankAccount extends React.Component { // User prematurely exited the Plaid flow // eslint-disable-next-line react/jsx-props-no-multi-spaces onExit={this.props.onExitPlaid} - receivedRedirectUri={this.props.receivedRedirectUri} + receivedRedirectUri={this.props.receivedRedirectURI} /> )} {accounts.length > 0 && ( diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index bd5df22ef636..cfcc17da4aa4 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -4,7 +4,7 @@ import {plaidLinkPropTypes, plaidLinkDefaultProps} from './plaidLinkPropTypes'; import Log from '../../libs/Log'; const PlaidLink = (props) => { - console.log("here in index PlaidLink"); + console.log("here in index PlaidLink", props.receivedRedirectUri); const onSuccess = useCallback((publicToken, metadata) => { props.onSuccess({publicToken, metadata}); }, []); diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 9d9060f3feed..b805a86dcef7 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -31,6 +31,7 @@ const propTypes = { const PlaidOAuthPage = ({ plaidLinkToken, + translate, plaidBankAccounts, reimbursementAccount, }) => { @@ -43,14 +44,14 @@ const PlaidOAuthPage = ({ return ( { addPersonalBankAccount(account, password, plaidLinkToken); }} - receivedRedirectURI={(new URL(window.location.href))} + receivedRedirectURI={window.location.href} onExitPlaid={Navigation.dismissModal} plaidLinkToken={plaidLinkToken} /> @@ -58,69 +59,6 @@ const PlaidOAuthPage = ({ ); }; -// const PlaidOAuthPage = ({ -// plaidLinkToken, -// plaidBankAccounts, -// reimbursementAccount, -// }) => { -// const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; -// const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); -// console.log("in PlaidOAuthPage", oauth_state_id); -// const bankAccounts = lodashGet(plaidBankAccounts, 'accounts', []); -// const linkToken = plaidLinkToken; -// const icon = GenericBank; -// const iconSize = variables.iconSizeExtraLarge; -// // const {icon, iconSize} = getBankIcon(this.state.institution.name); -// -// return ( -// -// { -// Log.info('[PlaidLink] Success!'); -// console.log('[PlaidLink] Success!'); -// getPlaidBankAccounts(publicToken, metadata.institution.name); -// // this.setState({institution: metadata.institution}); -// }} -// /> -// {bankAccounts.length > 0 && ( -// -// {!_.isEmpty(this.props.text) && ( -// {this.props.text} -// )} -// -// -// {this.state.institution.name} -// -// -// { -// this.setState({selectedIndex: Number(index)}); -// this.clearError('selectedBank'); -// }} -// items={options} -// placeholder={_.isUndefined(this.state.selectedIndex) ? { -// value: '', -// label: this.props.translate('bankAccount.chooseAnAccount'), -// } : {}} -// value={this.state.selectedIndex} -// hasError={this.getErrors().selectedBank} -// /> -// -// -// )} -// -// ); -// } -// PlaidOAuthPage.displayName = 'PlaidOAuthPage'; export default compose( withLocalize, From 03437e67a7e4959beec3a93856936e69a4869367 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 14:38:53 -0500 Subject: [PATCH 20/67] Clean up logs --- src/components/AddPlaidBankAccount.js | 7 +------ src/pages/ReimbursementAccount/PlaidOAuthPage.js | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index c3cf6377eb30..22262036d4bd 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -9,7 +9,6 @@ import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import Log from '../libs/Log'; import PlaidLink from './PlaidLink'; -import OAuthLink from "./PlaidOAuth/oauth"; import { clearPlaidBankAccountsAndToken, fetchPlaidLinkToken, @@ -117,10 +116,7 @@ class AddPlaidBankAccount extends React.Component { redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; } - console.log('AddPlaidBank redirectURI', this.props.receivedRedirectURI); - console.log('AddPlaidBank linkToken', this.props.plaidLinkToken); - - // If we're coming from re-initialization then we need to reuse the existing plaidLinkToken + // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken if (!this.props.receivedRedirectURI && !this.props.plaidLinkToken) { clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); @@ -182,7 +178,6 @@ class AddPlaidBankAccount extends React.Component { token={this.props.plaidLinkToken} onSuccess={({publicToken, metadata}) => { Log.info('[PlaidLink] Success!'); - console.log('[PlaidLink] Success!'); getPlaidBankAccounts(publicToken, metadata.institution.name); this.setState({institution: metadata.institution}); }} diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index b805a86dcef7..0d9db3dfb619 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -41,6 +41,7 @@ const PlaidOAuthPage = ({ // Need to differentiate between personal and business bank account + return ( Date: Tue, 9 Nov 2021 14:54:01 -0500 Subject: [PATCH 21/67] Mass cleanup --- src/components/AddPlaidBankAccount.js | 2 +- src/components/PlaidLink/index.js | 4 ---- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 3 ++- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 22262036d4bd..6e541f630b96 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -92,7 +92,7 @@ const defaultProps = { onExitPlaid: () => {}, onSubmit: () => {}, text: '', - receivedRedirectURI: '', + receivedRedirectURI: null, }; class AddPlaidBankAccount extends React.Component { diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index cfcc17da4aa4..0f256de5597e 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -4,7 +4,6 @@ import {plaidLinkPropTypes, plaidLinkDefaultProps} from './plaidLinkPropTypes'; import Log from '../../libs/Log'; const PlaidLink = (props) => { - console.log("here in index PlaidLink", props.receivedRedirectUri); const onSuccess = useCallback((publicToken, metadata) => { props.onSuccess({publicToken, metadata}); }, []); @@ -14,11 +13,9 @@ const PlaidLink = (props) => { onSuccess, onExit: (exitError, metadata) => { Log.info('[PlaidLink] Exit: ', false, {exitError, metadata}); - console.log(exitError); props.onExit(); }, onEvent: (event, metadata) => { - console.log({event, metadata}, '[PlaidLink] onEvent'); Log.info('[PlaidLink] Event: ', false, {event, metadata}); }, receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter @@ -33,7 +30,6 @@ const PlaidLink = (props) => { if (!ready) { return; } - console.log("gonna hit open"); open(); }, [ready, error]); diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 0d9db3dfb619..842422485a99 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -39,8 +39,9 @@ const PlaidOAuthPage = ({ const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); console.log("in PlaidOAuthPage", oauth_state_id); - // Need to differentiate between personal and business bank account + // Add validation check for stateID or errors + // Need to differentiate between personal and business bank account return ( From e474ff1838181093c5ecf4ef28b41c835b3c6e61 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 14:59:20 -0500 Subject: [PATCH 22/67] Delete unneeded files --- src/components/PlaidLink/index.js | 4 +- src/components/PlaidOAuth/oauth.js | 66 ------------------- src/libs/actions/BankAccounts.js | 1 - .../ReimbursementAccount/PlaidOAuthPage.js | 1 - 4 files changed, 3 insertions(+), 69 deletions(-) delete mode 100644 src/components/PlaidOAuth/oauth.js diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index 0f256de5597e..d2f50b0394d9 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -18,7 +18,9 @@ const PlaidLink = (props) => { onEvent: (event, metadata) => { Log.info('[PlaidLink] Event: ', false, {event, metadata}); }, - receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter + // The redirect URI with an OAuth state ID. Needed to re-initialize the PlaidLink after directing the + // user to their respective bank platform + receivedRedirectUri: props.receivedRedirectUri, }); useEffect(() => { diff --git a/src/components/PlaidOAuth/oauth.js b/src/components/PlaidOAuth/oauth.js deleted file mode 100644 index f5bf45ab4855..000000000000 --- a/src/components/PlaidOAuth/oauth.js +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useEffect } from 'react'; -import { usePlaidLink } from 'react-plaid-link'; -import compose from "../../libs/compose"; -import withLocalize from "../withLocalize"; -import {withOnyx} from "react-native-onyx"; -import ONYXKEYS from "../../ONYXKEYS"; -import {plaidLinkDefaultProps, plaidLinkPropTypes} from "../PlaidLink/plaidLinkPropTypes"; -import PlaidLink from "../PlaidLink"; -import ScreenWrapper from "../ScreenWrapper"; -import HeaderWithCloseButton from "../HeaderWithCloseButton"; -import Navigation from "../../libs/Navigation/Navigation"; -import ROUTES from "../../ROUTES"; -import WorkspaceSection from "../../pages/workspace/WorkspaceSection"; -import {BankArrowPink} from "../Icon/Illustrations"; -import Text from "../Text"; -import WorkspaceResetBankAccountModal from "../../pages/workspace/WorkspaceResetBankAccountModal"; - -const OAuthLink = (props) => { - console.log("in OAuthLink"); - console.log(props); - - // The Link token from the first Link initialization - // const linkToken = localStorage.getItem('link_token'); - const linkToken = props.plaidLinkToken; - const onSuccess = React.useCallback((publicToken, metadata) => { - // send public_token to server, retrieve access_token and item_id - // return to "https://example.com" upon completion - console.log("in success for OAuthLink"); - props.onSuccess({publicToken, metadata}) - }, []); - const onExit = (err, metatdata) => { - console.log(err); - // handle error... - }; - const config = { - token: linkToken, - receivedRedirectUri: props.receivedRedirectUri, //the redirect URI with an OAuth state ID parameter - onSuccess, - onExit, - }; - const { open, ready, error } = usePlaidLink(config); - // automatically reinitialize Link - useEffect(() => { - if (ready) { - open(); - } - }, [ready, open]); - return <>; -}; -OAuthLink.propTypes = plaidLinkPropTypes; -OAuthLink.defaultProps = plaidLinkDefaultProps; -OAuthLink.displayName = 'OAuthLink'; - -export default compose( - withOnyx({ - plaidLinkToken: { - key: ONYXKEYS.PLAID_LINK_TOKEN, - - // We always fetch a new token to call Plaid. If we don't then it's possible to open multiple Plaid Link instances. In particular, this can cause issues for Android e.g. - // inability to hand off to React Native once the bank connection is made. This is because an old stashed token will mount the PlaidLink component then it gets set again - // which will mount another PlaidLink component. - initWithStoredValues: false, - } - }) -)(OAuthLink); - diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 837b6a9e0193..e4041a4000b6 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -55,7 +55,6 @@ function fetchPlaidLinkToken(redirectURI) { if (response.jsonCode !== 200) { return; } - console.log(response); Onyx.merge(ONYXKEYS.PLAID_LINK_TOKEN, response.linkToken); }); } diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 842422485a99..89e252118df9 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,6 +1,5 @@ import React from "react"; import {View} from 'react-native'; -import OAuthLink from "../../components/PlaidOAuth/oauth"; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ONYXKEYS from "../../ONYXKEYS"; import {withOnyx} from "react-native-onyx"; From cf3e88aed5dd5783cd0e6cbcdf631f47cb6fbb52 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 15:06:44 -0500 Subject: [PATCH 23/67] Fix comment --- src/components/PlaidLink/index.js | 1 + .../ReimbursementAccount/PlaidOAuthPage.js | 22 +++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index d2f50b0394d9..db1ca8ad124b 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -18,6 +18,7 @@ const PlaidLink = (props) => { onEvent: (event, metadata) => { Log.info('[PlaidLink] Event: ', false, {event, metadata}); }, + // The redirect URI with an OAuth state ID. Needed to re-initialize the PlaidLink after directing the // user to their respective bank platform receivedRedirectUri: props.receivedRedirectUri, diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 89e252118df9..6cda2886aa9d 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,21 +1,8 @@ -import React from "react"; -import {View} from 'react-native'; +import React from 'react'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import ONYXKEYS from "../../ONYXKEYS"; -import {withOnyx} from "react-native-onyx"; -import ReimbursementAccountForm from "./ReimbursementAccountForm"; -import _ from "underscore"; -import Text from "../../components/Text"; -import styles from "../../styles/styles"; -import Icon from "../../components/Icon"; -import ExpensiPicker from "../../components/ExpensiPicker"; -import lodashGet from "lodash/get"; +import ONYXKEYS from '../../ONYXKEYS'; +import {withOnyx} from 'react-native-onyx'; import compose from '../../libs/compose'; -import getBankIcon from "../../components/Icon/BankIcons"; -import GenericBank from '../../../assets/images/bankicons/generic-bank-account.svg'; -import variables from "../../styles/variables"; -import Log from "../../libs/Log"; -import {getPlaidBankAccounts} from "../../libs/actions/BankAccounts"; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import ScreenWrapper from '../../components/ScreenWrapper'; import Navigation from '../../libs/Navigation/Navigation'; @@ -41,6 +28,8 @@ const PlaidOAuthPage = ({ // Add validation check for stateID or errors // Need to differentiate between personal and business bank account + // if personal then addPersonalBankAccount(account, password, plaidLinkToken); + // if business then bankAccountStep -> addPlaidAccount return ( @@ -60,6 +49,7 @@ const PlaidOAuthPage = ({ ); }; +PlaidOAuthPage.propTypes = propTypes; PlaidOAuthPage.displayName = 'PlaidOAuthPage'; export default compose( withLocalize, From 5f1f635a4597017044b2d66cbf36807e619b8b15 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 15:16:03 -0500 Subject: [PATCH 24/67] Figure out variables for getting bank account --- src/libs/API.js | 2 ++ src/pages/ReimbursementAccount/PlaidOAuthPage.js | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libs/API.js b/src/libs/API.js index d290e9c09b33..8aaf6bb2e968 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -866,6 +866,8 @@ function Wallet_GetOnfidoSDKToken() { } /** + * @param {Object} parameters + * @param {String} parameters.redirect_uri * @returns {Promise} */ function Plaid_GetLinkToken(parameters) { diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 6cda2886aa9d..5a229d64c71d 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,7 +1,7 @@ import React from 'react'; +import {withOnyx} from 'react-native-onyx'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ONYXKEYS from '../../ONYXKEYS'; -import {withOnyx} from 'react-native-onyx'; import compose from '../../libs/compose'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import ScreenWrapper from '../../components/ScreenWrapper'; @@ -23,7 +23,6 @@ const PlaidOAuthPage = ({ }) => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); - console.log("in PlaidOAuthPage", oauth_state_id); // Add validation check for stateID or errors @@ -38,9 +37,9 @@ const PlaidOAuthPage = ({ onCloseButtonPress={Navigation.dismissModal} /> { - addPersonalBankAccount(account, password, plaidLinkToken); - }} + // onSubmit={({account, password, plaidLinkToken}) => { + // addPersonalBankAccount(account, password, plaidLinkToken); + // }} receivedRedirectURI={window.location.href} onExitPlaid={Navigation.dismissModal} plaidLinkToken={plaidLinkToken} From 1578e1750cb16a1da99061fa85a5483e5918e8ca Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 16:44:39 -0500 Subject: [PATCH 25/67] Add no stateID error handling --- src/components/AddPlaidBankAccount.js | 3 ++- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 15 ++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 6e541f630b96..15ba9a567b19 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -117,7 +117,8 @@ class AddPlaidBankAccount extends React.Component { } // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken - if (!this.props.receivedRedirectURI && !this.props.plaidLinkToken) { + // Otherwise, clear the existing token and fetch a new one + if (!this.props.receivedRedirectURI || !this.props.plaidLinkToken) { clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); } diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 5a229d64c71d..c8a87405939c 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -7,9 +7,10 @@ import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import ScreenWrapper from '../../components/ScreenWrapper'; import Navigation from '../../libs/Navigation/Navigation'; import { - addPersonalBankAccount, + addPersonalBankAccount, showBankAccountErrorModal, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; +import ROUTES from "../../ROUTES"; const propTypes = { ...withLocalizePropTypes, @@ -22,9 +23,14 @@ const PlaidOAuthPage = ({ reimbursementAccount, }) => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; - const oauth_state_id = receivedRedirectSearchParams.get('oauth_state_id'); + const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); + let receivedRedirectURI = window.location.href; - // Add validation check for stateID or errors + // If there's no stateID passed, then setting the redirectURI to null + // will return the user to the start of the PLaid flow + if (!oauthStateID) { + receivedRedirectURI = null; + } // Need to differentiate between personal and business bank account // if personal then addPersonalBankAccount(account, password, plaidLinkToken); @@ -40,7 +46,7 @@ const PlaidOAuthPage = ({ // onSubmit={({account, password, plaidLinkToken}) => { // addPersonalBankAccount(account, password, plaidLinkToken); // }} - receivedRedirectURI={window.location.href} + receivedRedirectURI={receivedRedirectURI} onExitPlaid={Navigation.dismissModal} plaidLinkToken={plaidLinkToken} /> @@ -54,7 +60,6 @@ export default compose( withLocalize, withOnyx({ plaidLinkToken: { - // If we hit here we've been redirected to reinitialize the PlaidLink key: ONYXKEYS.PLAID_LINK_TOKEN, }, plaidBankAccounts: { From 66db02b38508804c9e0b43beed6fbf38664089bb Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 16:57:29 -0500 Subject: [PATCH 26/67] Fill out propType doc --- src/components/AddPlaidBankAccount.js | 2 +- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 15ba9a567b19..4b2149599f87 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -80,7 +80,7 @@ const propTypes = { /** Additional text to display */ text: PropTypes.string, - /** If coming from the Plaid OAuth flow, contains stateID */ + /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ receivedRedirectURI: PropTypes.string, }; diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index c8a87405939c..156c08668c27 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -10,9 +10,12 @@ import { addPersonalBankAccount, showBankAccountErrorModal, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; -import ROUTES from "../../ROUTES"; +import PropTypes from "prop-types"; const propTypes = { + /** Plaid SDK token to use to initialize the widget */ + plaidLinkToken: PropTypes.string, + ...withLocalizePropTypes, }; From c160146f542f24bc8171322cf23251bdc4f777c2 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 18:58:38 -0500 Subject: [PATCH 27/67] Lint --- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 156c08668c27..cb52d42ceb87 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,5 +1,6 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; +import PropTypes from "prop-types"; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ONYXKEYS from '../../ONYXKEYS'; import compose from '../../libs/compose'; @@ -7,10 +8,9 @@ import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import ScreenWrapper from '../../components/ScreenWrapper'; import Navigation from '../../libs/Navigation/Navigation'; import { - addPersonalBankAccount, showBankAccountErrorModal, + addPersonalBankAccount, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; -import PropTypes from "prop-types"; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -22,8 +22,6 @@ const propTypes = { const PlaidOAuthPage = ({ plaidLinkToken, translate, - plaidBankAccounts, - reimbursementAccount, }) => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); @@ -46,9 +44,9 @@ const PlaidOAuthPage = ({ onCloseButtonPress={Navigation.dismissModal} /> { - // addPersonalBankAccount(account, password, plaidLinkToken); - // }} + onSubmit={({account, password, plaidLinkToken}) => { + addPersonalBankAccount(account, password, plaidLinkToken); + }} receivedRedirectURI={receivedRedirectURI} onExitPlaid={Navigation.dismissModal} plaidLinkToken={plaidLinkToken} From 87e5b2bf989129f1eb67b229f9e13bdcdb512068 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 19:32:13 -0500 Subject: [PATCH 28/67] Test setting up new withdrawal bank account --- src/components/AddPlaidBankAccount.js | 2 ++ .../ReimbursementAccount/BankAccountStep.js | 1 + .../ReimbursementAccount/PlaidOAuthPage.js | 31 +++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 4b2149599f87..04c5e2dc6596 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -115,6 +115,8 @@ class AddPlaidBankAccount extends React.Component { if (getPlatform() === 'web') { redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; } + console.log(this.props.receivedRedirectURI); + console.log(this.props.plaidLinkToken); // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 01acd421f9d3..72ce4302c396 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -141,6 +141,7 @@ class BankAccountStep extends React.Component { * @param {String} params.account.plaidAccountID */ addPlaidAccount(params) { + console.log(params); setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index cb52d42ceb87..324b642c41cb 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -11,6 +11,7 @@ import { addPersonalBankAccount, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; +import CONST from "../../CONST"; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -19,6 +20,29 @@ const propTypes = { ...withLocalizePropTypes, }; +function addPlaidAccount(params) { + console.log(params); + setupWithdrawalAccount({ + acceptTerms: true, + setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, + + // Params passed via the Plaid callback when an account is selected + plaidAccessToken: params.plaidLinkToken, + accountNumber: params.account.accountNumber, + routingNumber: params.account.routingNumber, + plaidAccountID: params.account.plaidAccountID, + ownershipType: params.account.ownershipType, + isSavings: params.account.isSavings, + bankName: params.bankName, + addressName: params.account.addressName, + + // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan + country: CONST.COUNTRY.US, + currency: CONST.CURRENCY.USD, + fieldsType: CONST.BANK_ACCOUNT.FIELDS_TYPE.LOCAL, + }); +} + const PlaidOAuthPage = ({ plaidLinkToken, translate, @@ -44,9 +68,10 @@ const PlaidOAuthPage = ({ onCloseButtonPress={Navigation.dismissModal} /> { - addPersonalBankAccount(account, password, plaidLinkToken); - }} + // onSubmit={({account, password, plaidLinkToken}) => { + // addPersonalBankAccount(account, password, plaidLinkToken); + // }} + onSubmit={addPlaidAccount} receivedRedirectURI={receivedRedirectURI} onExitPlaid={Navigation.dismissModal} plaidLinkToken={plaidLinkToken} From 3ec279035cd9a609fbea019d2905d38e93c57128 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 19:41:22 -0500 Subject: [PATCH 29/67] Cleanup comments --- src/components/AddPlaidBankAccount.js | 2 - .../ReimbursementAccount/PlaidOAuthPage.js | 37 +------------------ 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 04c5e2dc6596..4b2149599f87 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -115,8 +115,6 @@ class AddPlaidBankAccount extends React.Component { if (getPlatform() === 'web') { redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; } - console.log(this.props.receivedRedirectURI); - console.log(this.props.plaidLinkToken); // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 324b642c41cb..59de3a911e28 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -11,7 +11,6 @@ import { addPersonalBankAccount, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; -import CONST from "../../CONST"; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -20,29 +19,6 @@ const propTypes = { ...withLocalizePropTypes, }; -function addPlaidAccount(params) { - console.log(params); - setupWithdrawalAccount({ - acceptTerms: true, - setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, - - // Params passed via the Plaid callback when an account is selected - plaidAccessToken: params.plaidLinkToken, - accountNumber: params.account.accountNumber, - routingNumber: params.account.routingNumber, - plaidAccountID: params.account.plaidAccountID, - ownershipType: params.account.ownershipType, - isSavings: params.account.isSavings, - bankName: params.bankName, - addressName: params.account.addressName, - - // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan - country: CONST.COUNTRY.US, - currency: CONST.CURRENCY.USD, - fieldsType: CONST.BANK_ACCOUNT.FIELDS_TYPE.LOCAL, - }); -} - const PlaidOAuthPage = ({ plaidLinkToken, translate, @@ -57,7 +33,7 @@ const PlaidOAuthPage = ({ receivedRedirectURI = null; } - // Need to differentiate between personal and business bank account + // TODO: Need to differentiate between personal and business bank account // if personal then addPersonalBankAccount(account, password, plaidLinkToken); // if business then bankAccountStep -> addPlaidAccount @@ -68,10 +44,7 @@ const PlaidOAuthPage = ({ onCloseButtonPress={Navigation.dismissModal} /> { - // addPersonalBankAccount(account, password, plaidLinkToken); - // }} - onSubmit={addPlaidAccount} + // onSubmit={addPlaidAccount} receivedRedirectURI={receivedRedirectURI} onExitPlaid={Navigation.dismissModal} plaidLinkToken={plaidLinkToken} @@ -88,11 +61,5 @@ export default compose( plaidLinkToken: { key: ONYXKEYS.PLAID_LINK_TOKEN, }, - plaidBankAccounts: { - key: ONYXKEYS.PLAID_BANK_ACCOUNTS, - }, - reimbursementAccount: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, - }, }), )(PlaidOAuthPage); From 7142e44097644f42dead607d5b1f73ff53b912b3 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 9 Nov 2021 19:43:14 -0500 Subject: [PATCH 30/67] Lint --- src/pages/ReimbursementAccount/BankAccountStep.js | 1 - src/pages/ReimbursementAccount/PlaidOAuthPage.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 72ce4302c396..01acd421f9d3 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -141,7 +141,6 @@ class BankAccountStep extends React.Component { * @param {String} params.account.plaidAccountID */ addPlaidAccount(params) { - console.log(params); setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 59de3a911e28..e4818926a07a 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,6 +1,6 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; -import PropTypes from "prop-types"; +import PropTypes from 'prop-types'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ONYXKEYS from '../../ONYXKEYS'; import compose from '../../libs/compose'; From 84e2a4fa129ad73746ee804d152e489192b094fd Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 11:23:15 -0500 Subject: [PATCH 31/67] Minor PR comments --- src/ONYXKEYS.js | 3 +++ src/libs/API.js | 2 +- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 947d0aaf0c31..7170c6ad6de7 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -147,4 +147,7 @@ export default { // Are report actions loading? IS_LOADING_REPORT_ACTIONS: 'isLoadingReportActions', + + // Stores which bank account flow, personal or business + IS_ADDING_BBA: 'isAddingBBA', }; diff --git a/src/libs/API.js b/src/libs/API.js index 73908c2c6b9f..ff870d385100 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -887,7 +887,7 @@ function Wallet_GetOnfidoSDKToken() { function Plaid_GetLinkToken(parameters) { const commandName = 'Plaid_GetLinkToken'; requireParameters(['redirect_uri'], parameters, commandName); - return Network.post('Plaid_GetLinkToken', parameters, CONST.NETWORK.METHOD.POST, true); + return Network.post(commandName, parameters, CONST.NETWORK.METHOD.POST, true); } /** diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index e4818926a07a..969732e258bb 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -28,7 +28,7 @@ const PlaidOAuthPage = ({ let receivedRedirectURI = window.location.href; // If there's no stateID passed, then setting the redirectURI to null - // will return the user to the start of the PLaid flow + // will return the user to the start of the Plaid flow if (!oauthStateID) { receivedRedirectURI = null; } From aebd05c5a720bb8a4b37323f3e628058fa74ed40 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 11:48:12 -0500 Subject: [PATCH 32/67] Separate file extension specific platform --- .../index.js} | 30 +-- .../AddPlaidBankAccount/index.native.js | 245 ++++++++++++++++++ src/libs/actions/BankAccounts.js | 2 +- .../ReimbursementAccount/PlaidOAuthPage.js | 9 +- 4 files changed, 264 insertions(+), 22 deletions(-) rename src/components/{AddPlaidBankAccount.js => AddPlaidBankAccount/index.js} (91%) create mode 100644 src/components/AddPlaidBankAccount/index.native.js diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount/index.js similarity index 91% rename from src/components/AddPlaidBankAccount.js rename to src/components/AddPlaidBankAccount/index.js index 4b2149599f87..88310b664b66 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -7,27 +7,27 @@ import { import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import Log from '../libs/Log'; -import PlaidLink from './PlaidLink'; +import Log from '../../libs/Log'; +import PlaidLink from '../PlaidLink/index'; import { clearPlaidBankAccountsAndToken, fetchPlaidLinkToken, getPlaidBankAccounts, setBankAccountFormValidationErrors, showBankAccountErrorModal, -} from '../libs/actions/BankAccounts'; -import ONYXKEYS from '../ONYXKEYS'; -import styles from '../styles/styles'; -import themeColors from '../styles/themes/default'; -import compose from '../libs/compose'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; -import ExpensiPicker from './ExpensiPicker'; -import Text from './Text'; -import * as ReimbursementAccountUtils from '../libs/ReimbursementAccountUtils'; -import ReimbursementAccountForm from '../pages/ReimbursementAccount/ReimbursementAccountForm'; -import getBankIcon from './Icon/BankIcons'; -import Icon from './Icon'; -import getPlatform from '../libs/getPlatform'; +} from '../../libs/actions/BankAccounts'; +import ONYXKEYS from '../../ONYXKEYS'; +import styles from '../../styles/styles'; +import themeColors from '../../styles/themes/default'; +import compose from '../../libs/compose'; +import withLocalize, {withLocalizePropTypes} from '../withLocalize'; +import ExpensiPicker from '../ExpensiPicker'; +import Text from '../Text'; +import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; +import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; +import getBankIcon from '../Icon/BankIcons'; +import Icon from '../Icon'; +import getPlatform from '../../libs/getPlatform/index'; const propTypes = { ...withLocalizePropTypes, diff --git a/src/components/AddPlaidBankAccount/index.native.js b/src/components/AddPlaidBankAccount/index.native.js new file mode 100644 index 000000000000..8f5e5fe19a2b --- /dev/null +++ b/src/components/AddPlaidBankAccount/index.native.js @@ -0,0 +1,245 @@ +import _ from 'underscore'; +import React from 'react'; +import { + ActivityIndicator, + View, +} from 'react-native'; +import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; +import Log from '../../libs/Log'; +import PlaidLink from '../PlaidLink/index'; +import { + clearPlaidBankAccountsAndToken, + fetchPlaidLinkToken, + getPlaidBankAccounts, + setBankAccountFormValidationErrors, + showBankAccountErrorModal, +} from '../../libs/actions/BankAccounts'; +import ONYXKEYS from '../../ONYXKEYS'; +import styles from '../../styles/styles'; +import themeColors from '../../styles/themes/default'; +import compose from '../../libs/compose'; +import withLocalize, {withLocalizePropTypes} from '../withLocalize'; +import ExpensiPicker from '../ExpensiPicker'; +import Text from '../Text'; +import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; +import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; +import getBankIcon from '../Icon/BankIcons'; +import Icon from '../Icon'; +import getPlatform from '../../libs/getPlatform/index'; + +const propTypes = { + ...withLocalizePropTypes, + + /** Plaid SDK token to use to initialize the widget */ + plaidLinkToken: PropTypes.string, + + /** Contains list of accounts and loading state while fetching them */ + plaidBankAccounts: PropTypes.shape({ + /** Whether we are fetching the bank accounts from the API */ + loading: PropTypes.bool, + + /** Error object */ + error: PropTypes.shape({ + /** Error message */ + message: PropTypes.string, + + /** Error title */ + title: PropTypes.string, + }), + + /** List of accounts */ + accounts: PropTypes.arrayOf(PropTypes.shape({ + /** Masked account number */ + accountNumber: PropTypes.string, + + /** Name of account */ + addressName: PropTypes.string, + + /** Has this account has already been added? */ + alreadyExists: PropTypes.bool, + + /** Is the account a savings account? */ + isSavings: PropTypes.bool, + + /** Unique identifier for this account in Plaid */ + plaidAccountID: PropTypes.string, + + /** Routing number for the account */ + routingNumber: PropTypes.string, + })), + }), + + /** Fired when the user exits the Plaid flow */ + onExitPlaid: PropTypes.func, + + /** Fired when the user selects an account and submits the form */ + onSubmit: PropTypes.func, + + /** Additional text to display */ + text: PropTypes.string, + + /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ + receivedRedirectURI: PropTypes.string, +}; + +const defaultProps = { + plaidLinkToken: '', + plaidBankAccounts: { + loading: false, + }, + onExitPlaid: () => {}, + onSubmit: () => {}, + text: '', + receivedRedirectURI: null, +}; + +class AddPlaidBankAccount extends React.Component { + constructor(props) { + super(props); + + this.selectAccount = this.selectAccount.bind(this); + + this.state = { + selectedIndex: undefined, + institution: {}, + }; + + this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); + this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); + } + + componentDidMount() { + clearPlaidBankAccountsAndToken(); + fetchPlaidLinkToken(); + } + + /** + * Get list of bank accounts + * + * @returns {Object[]} + */ + getAccounts() { + return lodashGet(this.props.plaidBankAccounts, 'accounts', []); + } + + /** + * @returns {Boolean} + */ + validate() { + const errors = {}; + if (_.isUndefined(this.state.selectedIndex)) { + errors.selectedBank = true; + } + setBankAccountFormValidationErrors(errors); + return _.size(errors) === 0; + } + + selectAccount() { + if (!this.validate()) { + showBankAccountErrorModal(); + return; + } + + const account = this.getAccounts()[this.state.selectedIndex]; + const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); + this.props.onSubmit({ + bankName, + account, + plaidLinkToken: this.props.plaidLinkToken, + }); + } + + render() { + const accounts = this.getAccounts(); + const options = _.map(accounts, (account, index) => ({ + value: index, label: `${account.addressName} ${account.accountNumber}`, + })); + const {icon, iconSize} = getBankIcon(this.state.institution.name); + return ( + <> + {(!this.props.plaidLinkToken || this.props.plaidBankAccounts.loading) + && ( + + + + )} + {!_.isEmpty(this.props.plaidLinkToken) && ( + { + Log.info('[PlaidLink] Success!'); + getPlaidBankAccounts(publicToken, metadata.institution.name); + this.setState({institution: metadata.institution}); + }} + onError={(error) => { + Log.hmmm('[PlaidLink] Error: ', error.message); + }} + + // User prematurely exited the Plaid flow + // eslint-disable-next-line react/jsx-props-no-multi-spaces + onExit={this.props.onExitPlaid} + receivedRedirectUri={this.props.receivedRedirectURI} + /> + )} + {accounts.length > 0 && ( + + {!_.isEmpty(this.props.text) && ( + {this.props.text} + )} + + + {this.state.institution.name} + + + { + this.setState({selectedIndex: Number(index)}); + this.clearError('selectedBank'); + }} + items={options} + placeholder={_.isUndefined(this.state.selectedIndex) ? { + value: '', + label: this.props.translate('bankAccount.chooseAnAccount'), + } : {}} + value={this.state.selectedIndex} + hasError={this.getErrors().selectedBank} + /> + + + )} + + ); + } +} + +AddPlaidBankAccount.propTypes = propTypes; +AddPlaidBankAccount.defaultProps = defaultProps; + +export default compose( + withLocalize, + withOnyx({ + plaidLinkToken: { + key: ONYXKEYS.PLAID_LINK_TOKEN, + + // We always fetch a new token to call Plaid. If we don't then it's possible to open multiple Plaid Link instances. In particular, this can cause issues for Android e.g. + // inability to hand off to React Native once the bank connection is made. This is because an old stashed token will mount the PlaidLink component then it gets set again + // which will mount another PlaidLink component. + initWithStoredValues: false, + }, + plaidBankAccounts: { + key: ONYXKEYS.PLAID_BANK_ACCOUNTS, + }, + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + }), +)(AddPlaidBankAccount); diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 1c551bcc3d97..5bd3fe931c38 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -49,7 +49,7 @@ Onyx.connect({ * * @param {String} redirectURI */ -function fetchPlaidLinkToken(redirectURI) { +function fetchPlaidLinkToken(redirectURI= null) { API.Plaid_GetLinkToken({redirect_uri: redirectURI}) .then((response) => { if (response.jsonCode !== 200) { diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 969732e258bb..2710b2dca828 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -19,10 +19,7 @@ const propTypes = { ...withLocalizePropTypes, }; -const PlaidOAuthPage = ({ - plaidLinkToken, - translate, -}) => { +const PlaidOAuthPage = props => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); let receivedRedirectURI = window.location.href; @@ -40,14 +37,14 @@ const PlaidOAuthPage = ({ return ( ); From 63e110a62e1fdb0027e4904b9135dd63b3082174 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 12:58:35 -0500 Subject: [PATCH 33/67] Add propTypes file --- src/components/AddPlaidBankAccount/index.js | 71 +------------------ .../AddPlaidBankAccount/plaidBankPropTypes.js | 31 ++++++++ 2 files changed, 34 insertions(+), 68 deletions(-) create mode 100644 src/components/AddPlaidBankAccount/plaidBankPropTypes.js diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 88310b664b66..ed8ebbfca5f2 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -27,72 +27,11 @@ import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; import getBankIcon from '../Icon/BankIcons'; import Icon from '../Icon'; -import getPlatform from '../../libs/getPlatform/index'; +import plaidBankPropTypes from "./plaidBankPropTypes"; const propTypes = { ...withLocalizePropTypes, - - /** Plaid SDK token to use to initialize the widget */ - plaidLinkToken: PropTypes.string, - - /** Contains list of accounts and loading state while fetching them */ - plaidBankAccounts: PropTypes.shape({ - /** Whether we are fetching the bank accounts from the API */ - loading: PropTypes.bool, - - /** Error object */ - error: PropTypes.shape({ - /** Error message */ - message: PropTypes.string, - - /** Error title */ - title: PropTypes.string, - }), - - /** List of accounts */ - accounts: PropTypes.arrayOf(PropTypes.shape({ - /** Masked account number */ - accountNumber: PropTypes.string, - - /** Name of account */ - addressName: PropTypes.string, - - /** Has this account has already been added? */ - alreadyExists: PropTypes.bool, - - /** Is the account a savings account? */ - isSavings: PropTypes.bool, - - /** Unique identifier for this account in Plaid */ - plaidAccountID: PropTypes.string, - - /** Routing number for the account */ - routingNumber: PropTypes.string, - })), - }), - - /** Fired when the user exits the Plaid flow */ - onExitPlaid: PropTypes.func, - - /** Fired when the user selects an account and submits the form */ - onSubmit: PropTypes.func, - - /** Additional text to display */ - text: PropTypes.string, - - /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ - receivedRedirectURI: PropTypes.string, -}; - -const defaultProps = { - plaidLinkToken: '', - plaidBankAccounts: { - loading: false, - }, - onExitPlaid: () => {}, - onSubmit: () => {}, - text: '', - receivedRedirectURI: null, + ...plaidBankPropTypes, }; class AddPlaidBankAccount extends React.Component { @@ -111,14 +50,10 @@ class AddPlaidBankAccount extends React.Component { } componentDidMount() { - let redirectURI = ''; - if (getPlatform() === 'web') { - redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; - } - // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one if (!this.props.receivedRedirectURI || !this.props.plaidLinkToken) { + const redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); } diff --git a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js new file mode 100644 index 000000000000..78b5cbcfc9d2 --- /dev/null +++ b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js @@ -0,0 +1,31 @@ +import PropTypes from "prop-types"; + +const propTypes = { + /** Fired when the user exits the Plaid flow */ + onExitPlaid: PropTypes.func, + + /** Fired when the user selects an account and submits the form */ + onSubmit: PropTypes.func, + + /** Additional text to display */ + text: PropTypes.string, + + /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ + receivedRedirectURI: PropTypes.string, +}; + +const defaultProps = { + plaidLinkToken: '', + plaidBankAccounts: { + loading: false, + }, + onExitPlaid: () => {}, + onSubmit: () => {}, + text: '', + receivedRedirectURI: null, +}; + +export { + propTypes, + defaultProps, +}; From 673e3ceaa0506f75675afa5986bd66b27ac8860d Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 13:08:23 -0500 Subject: [PATCH 34/67] Fill out native addPlaidBank --- src/components/AddPlaidBankAccount/index.js | 9 ++- .../AddPlaidBankAccount/index.native.js | 70 ++----------------- .../AddPlaidBankAccount/plaidBankPropTypes.js | 2 +- 3 files changed, 9 insertions(+), 72 deletions(-) diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index ed8ebbfca5f2..0fb535869c15 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -4,7 +4,6 @@ import { ActivityIndicator, View, } from 'react-native'; -import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import Log from '../../libs/Log'; @@ -27,11 +26,11 @@ import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; import getBankIcon from '../Icon/BankIcons'; import Icon from '../Icon'; -import plaidBankPropTypes from "./plaidBankPropTypes"; +import {propTypes, defaultProps} from './plaidBankPropTypes'; -const propTypes = { +const plaidBankPropTypes = { ...withLocalizePropTypes, - ...plaidBankPropTypes, + ...propTypes, }; class AddPlaidBankAccount extends React.Component { @@ -165,7 +164,7 @@ class AddPlaidBankAccount extends React.Component { } } -AddPlaidBankAccount.propTypes = propTypes; +AddPlaidBankAccount.propTypes = plaidBankPropTypes; AddPlaidBankAccount.defaultProps = defaultProps; export default compose( diff --git a/src/components/AddPlaidBankAccount/index.native.js b/src/components/AddPlaidBankAccount/index.native.js index 8f5e5fe19a2b..fa54bc6d5bc7 100644 --- a/src/components/AddPlaidBankAccount/index.native.js +++ b/src/components/AddPlaidBankAccount/index.native.js @@ -4,7 +4,6 @@ import { ActivityIndicator, View, } from 'react-native'; -import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import Log from '../../libs/Log'; @@ -27,72 +26,11 @@ import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; import getBankIcon from '../Icon/BankIcons'; import Icon from '../Icon'; -import getPlatform from '../../libs/getPlatform/index'; +import {propTypes, defaultProps} from './plaidBankPropTypes'; -const propTypes = { +const plaidBankPropTypes = { ...withLocalizePropTypes, - - /** Plaid SDK token to use to initialize the widget */ - plaidLinkToken: PropTypes.string, - - /** Contains list of accounts and loading state while fetching them */ - plaidBankAccounts: PropTypes.shape({ - /** Whether we are fetching the bank accounts from the API */ - loading: PropTypes.bool, - - /** Error object */ - error: PropTypes.shape({ - /** Error message */ - message: PropTypes.string, - - /** Error title */ - title: PropTypes.string, - }), - - /** List of accounts */ - accounts: PropTypes.arrayOf(PropTypes.shape({ - /** Masked account number */ - accountNumber: PropTypes.string, - - /** Name of account */ - addressName: PropTypes.string, - - /** Has this account has already been added? */ - alreadyExists: PropTypes.bool, - - /** Is the account a savings account? */ - isSavings: PropTypes.bool, - - /** Unique identifier for this account in Plaid */ - plaidAccountID: PropTypes.string, - - /** Routing number for the account */ - routingNumber: PropTypes.string, - })), - }), - - /** Fired when the user exits the Plaid flow */ - onExitPlaid: PropTypes.func, - - /** Fired when the user selects an account and submits the form */ - onSubmit: PropTypes.func, - - /** Additional text to display */ - text: PropTypes.string, - - /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ - receivedRedirectURI: PropTypes.string, -}; - -const defaultProps = { - plaidLinkToken: '', - plaidBankAccounts: { - loading: false, - }, - onExitPlaid: () => {}, - onSubmit: () => {}, - text: '', - receivedRedirectURI: null, + ...propTypes, }; class AddPlaidBankAccount extends React.Component { @@ -221,7 +159,7 @@ class AddPlaidBankAccount extends React.Component { } } -AddPlaidBankAccount.propTypes = propTypes; +AddPlaidBankAccount.propTypes = plaidBankPropTypes; AddPlaidBankAccount.defaultProps = defaultProps; export default compose( diff --git a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js index 78b5cbcfc9d2..85b131508619 100644 --- a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js +++ b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js @@ -1,4 +1,4 @@ -import PropTypes from "prop-types"; +import PropTypes from 'prop-types'; const propTypes = { /** Fired when the user exits the Plaid flow */ From 0b9522bfeaa9bc158cb8d51ff9daeb878068ba35 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 13:23:08 -0500 Subject: [PATCH 35/67] Setup using two different endpoints --- src/ROUTES.js | 2 +- src/components/AddPlaidBankAccount/index.js | 4 +++- src/components/AddPlaidBankAccount/plaidBankPropTypes.js | 3 +++ src/pages/AddPersonalBankAccountPage.js | 1 + src/pages/ReimbursementAccount/BankAccountStep.js | 2 +- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 4 ++++ 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 7c469cc1d2d0..20a9291f1ade 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -18,7 +18,7 @@ export default { BANK_ACCOUNT: 'bank-account/:stepToOpen?', BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, - OAUTH_PLAID: 'partners/plaid/oauth_web', + OAUTH_PLAID: 'partners/plaid/oauth_web/:bankAccountType', HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 0fb535869c15..70d9ee384960 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -52,7 +52,9 @@ class AddPlaidBankAccount extends React.Component { // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one if (!this.props.receivedRedirectURI || !this.props.plaidLinkToken) { - const redirectURI = 'http://localhost:8080/partners/plaid/oauth_web'; + const redirectURI = this.props.isBusinessBankAccount ? + 'http://localhost:8080/partners/plaid/oauth_web/business' : + 'http://localhost:8080/partners/plaid/oauth_web/personal'; clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); } diff --git a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js index 85b131508619..4b6d72e7c409 100644 --- a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js +++ b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js @@ -12,6 +12,9 @@ const propTypes = { /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ receivedRedirectURI: PropTypes.string, + + /** If the bank account being added is a business bank account */ + isBusinessBankAccount: PropTypes.bool, }; const defaultProps = { diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js index 6ce8651c3306..35f7b0996fb5 100644 --- a/src/pages/AddPersonalBankAccountPage.js +++ b/src/pages/AddPersonalBankAccountPage.js @@ -23,6 +23,7 @@ const AddPersonalBankAccountPage = props => ( addPersonalBankAccount(account, password, plaidLinkToken); }} onExitPlaid={Navigation.dismissModal} + isBusinessBankAccount={false} /> ); diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 01acd421f9d3..5c9876906900 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -246,7 +246,7 @@ class BankAccountStep extends React.Component { text={this.props.translate('bankAccount.plaidBodyCopy')} onSubmit={this.addPlaidAccount} onExitPlaid={() => setBankAccountSubStep(null)} - + isBusinessBankAccount /> )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 2710b2dca828..c7c090819953 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -11,6 +11,7 @@ import { addPersonalBankAccount, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; +import lodashGet from "lodash/get"; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -30,6 +31,9 @@ const PlaidOAuthPage = props => { receivedRedirectURI = null; } + const bankAccountType = lodashGet(this.props.route, ['params', 'bankAccountType']); + console.log(bankAccountType); + // TODO: Need to differentiate between personal and business bank account // if personal then addPersonalBankAccount(account, password, plaidLinkToken); // if business then bankAccountStep -> addPlaidAccount From 750c1598c97b4436abf662f5d313f9ef383fea4e Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 13:41:19 -0500 Subject: [PATCH 36/67] Works with two different endpoints --- src/CONST.js | 2 ++ src/components/AddPlaidBankAccount/index.js | 4 ++-- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 9a0fe6e80263..0741eccd04af 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -17,6 +17,8 @@ const CONST = { DOMAIN: '@expensify.sms', }, BANK_ACCOUNT: { + BUSINESS: 'business', + PERSONAL: 'personal', PLAID: { ALLOWED_THROTTLED_COUNT: 2, ERROR: { diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 70d9ee384960..9e1ea802939a 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -53,8 +53,8 @@ class AddPlaidBankAccount extends React.Component { // Otherwise, clear the existing token and fetch a new one if (!this.props.receivedRedirectURI || !this.props.plaidLinkToken) { const redirectURI = this.props.isBusinessBankAccount ? - 'http://localhost:8080/partners/plaid/oauth_web/business' : - 'http://localhost:8080/partners/plaid/oauth_web/personal'; + `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.BUSINESS}` : + `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.PERSONAL}`; clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); } diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index c7c090819953..790f24686c8c 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -31,8 +31,8 @@ const PlaidOAuthPage = props => { receivedRedirectURI = null; } - const bankAccountType = lodashGet(this.props.route, ['params', 'bankAccountType']); - console.log(bankAccountType); + const bankAccountType = lodashGet(props.route, ['params', 'bankAccountType']); + // TODO: Need to differentiate between personal and business bank account // if personal then addPersonalBankAccount(account, password, plaidLinkToken); From a6f5c94a3c3752ad868089a21d906535b42567bb Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 14:41:14 -0500 Subject: [PATCH 37/67] Lint and get adding bank account working --- src/components/AddPlaidBankAccount/index.js | 15 +++++--- src/libs/actions/BankAccounts.js | 36 +++++++++++++++++- .../ReimbursementAccount/BankAccountStep.js | 37 +------------------ .../ReimbursementAccount/PlaidOAuthPage.js | 23 ++++++------ 4 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 9e1ea802939a..ba5ef101f237 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -8,6 +8,7 @@ import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import Log from '../../libs/Log'; import PlaidLink from '../PlaidLink/index'; +import CONST from '../../CONST'; import { clearPlaidBankAccountsAndToken, fetchPlaidLinkToken, @@ -51,13 +52,15 @@ class AddPlaidBankAccount extends React.Component { componentDidMount() { // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one - if (!this.props.receivedRedirectURI || !this.props.plaidLinkToken) { - const redirectURI = this.props.isBusinessBankAccount ? - `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.BUSINESS}` : - `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.PERSONAL}`; - clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(redirectURI); + if (this.props.receivedRedirectURI || this.props.plaidLinkToken) { + return; } + + const redirectURI = this.props.isBusinessBankAccount + ? `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.BUSINESS}` + : `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.PERSONAL}`; + clearPlaidBankAccountsAndToken(); + fetchPlaidLinkToken(redirectURI); } /** diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 5bd3fe931c38..40d3ab414b4a 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -49,7 +49,7 @@ Onyx.connect({ * * @param {String} redirectURI */ -function fetchPlaidLinkToken(redirectURI= null) { +function fetchPlaidLinkToken(redirectURI = null) { API.Plaid_GetLinkToken({redirect_uri: redirectURI}) .then((response) => { if (response.jsonCode !== 200) { @@ -814,6 +814,39 @@ function setupWithdrawalAccount(data) { }); } +/** + * @param {Object} params + * @param {Object} params.account + * @param {String} params.account.bankName + * @param {Boolean} params.account.isSavings + * @param {String} params.account.addressName + * @param {String} params.account.ownershipType + * @param {String} params.account.accountNumber + * @param {String} params.account.routingNumber + * @param {String} params.account.plaidAccountID + */ +function addPlaidBusinessBankAccount(params) { + setupWithdrawalAccount({ + acceptTerms: true, + setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, + + // Params passed via the Plaid callback when an account is selected + plaidAccessToken: params.plaidLinkToken, + accountNumber: params.account.accountNumber, + routingNumber: params.account.routingNumber, + plaidAccountID: params.account.plaidAccountID, + ownershipType: params.account.ownershipType, + isSavings: params.account.isSavings, + bankName: params.bankName, + addressName: params.account.addressName, + + // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan + country: CONST.COUNTRY.US, + currency: CONST.CURRENCY.USD, + fieldsType: CONST.BANK_ACCOUNT.FIELDS_TYPE.LOCAL, + }); +} + function hideBankAccountErrors() { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error: '', errors: null}); } @@ -910,6 +943,7 @@ function validateRoutingNumber(number) { export { activateWallet, addPersonalBankAccount, + addPlaidBusinessBankAccount, clearPlaidBankAccountsAndToken, fetchFreePlanVerifiedBankAccount, fetchOnfidoToken, diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 5c9876906900..9b0c4e3a76ca 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -20,6 +20,7 @@ import exampleCheckImage from './exampleCheckImage'; import Text from '../../components/Text'; import ExpensiTextInput from '../../components/ExpensiTextInput'; import { + addPlaidBusinessBankAccount, setBankAccountFormValidationErrors, setBankAccountSubStep, setupWithdrawalAccount, @@ -49,7 +50,6 @@ class BankAccountStep extends React.Component { this.toggleTerms = this.toggleTerms.bind(this); this.addManualAccount = this.addManualAccount.bind(this); - this.addPlaidAccount = this.addPlaidAccount.bind(this); this.state = { // One of CONST.BANK_ACCOUNT.SETUP_TYPE hasAcceptedTerms: ReimbursementAccountUtils.getDefaultStateForField(props, 'acceptTerms', true), @@ -129,39 +129,6 @@ class BankAccountStep extends React.Component { }); } - /** - * @param {Object} params - * @param {Object} params.account - * @param {String} params.account.bankName - * @param {Boolean} params.account.isSavings - * @param {String} params.account.addressName - * @param {String} params.account.ownershipType - * @param {String} params.account.accountNumber - * @param {String} params.account.routingNumber - * @param {String} params.account.plaidAccountID - */ - addPlaidAccount(params) { - setupWithdrawalAccount({ - acceptTerms: true, - setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, - - // Params passed via the Plaid callback when an account is selected - plaidAccessToken: params.plaidLinkToken, - accountNumber: params.account.accountNumber, - routingNumber: params.account.routingNumber, - plaidAccountID: params.account.plaidAccountID, - ownershipType: params.account.ownershipType, - isSavings: params.account.isSavings, - bankName: params.bankName, - addressName: params.account.addressName, - - // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan - country: CONST.COUNTRY.US, - currency: CONST.CURRENCY.USD, - fieldsType: CONST.BANK_ACCOUNT.FIELDS_TYPE.LOCAL, - }); - } - render() { // Disable bank account fields once they've been added in db so they can't be changed const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; @@ -244,7 +211,7 @@ class BankAccountStep extends React.Component { {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( setBankAccountSubStep(null)} isBusinessBankAccount /> diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 790f24686c8c..2f31433ab4f3 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,6 +1,8 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; +import CONST from '../../CONST'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ONYXKEYS from '../../ONYXKEYS'; import compose from '../../libs/compose'; @@ -8,21 +10,22 @@ import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import ScreenWrapper from '../../components/ScreenWrapper'; import Navigation from '../../libs/Navigation/Navigation'; import { - addPersonalBankAccount, setupWithdrawalAccount, + addPlaidBusinessBankAccount, + addPersonalBankAccount, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; -import lodashGet from "lodash/get"; const propTypes = { /** Plaid SDK token to use to initialize the widget */ - plaidLinkToken: PropTypes.string, + plaidLinkToken: PropTypes.string.isRequired, ...withLocalizePropTypes, }; -const PlaidOAuthPage = props => { +const PlaidOAuthPage = (props) => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); + const bankAccountType = lodashGet(props.route, ['params', 'bankAccountType']); let receivedRedirectURI = window.location.href; // If there's no stateID passed, then setting the redirectURI to null @@ -31,13 +34,6 @@ const PlaidOAuthPage = props => { receivedRedirectURI = null; } - const bankAccountType = lodashGet(props.route, ['params', 'bankAccountType']); - - - // TODO: Need to differentiate between personal and business bank account - // if personal then addPersonalBankAccount(account, password, plaidLinkToken); - // if business then bankAccountStep -> addPlaidAccount - return ( { onCloseButtonPress={Navigation.dismissModal} /> { + addPersonalBankAccount(account, password, plaidLinkToken); + }} receivedRedirectURI={receivedRedirectURI} onExitPlaid={Navigation.dismissModal} plaidLinkToken={props.plaidLinkToken} From 37024573d6a566df15c353b3ff0c807f5f89ae72 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 10 Nov 2021 14:43:44 -0500 Subject: [PATCH 38/67] Delete onyx key --- src/ONYXKEYS.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 7170c6ad6de7..947d0aaf0c31 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -147,7 +147,4 @@ export default { // Are report actions loading? IS_LOADING_REPORT_ACTIONS: 'isLoadingReportActions', - - // Stores which bank account flow, personal or business - IS_ADDING_BBA: 'isAddingBBA', }; From 326b948eb9d6e6c02f76f2a6bf24e170e2593839 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Fri, 12 Nov 2021 20:26:28 -0500 Subject: [PATCH 39/67] Testing navigation bug --- src/libs/actions/BankAccounts.js | 2 ++ .../ReimbursementAccount/BankAccountStep.js | 1 + .../ReimbursementAccount/PlaidOAuthPage.js | 21 +++++++++++++++---- .../ReimbursementAccountPage.js | 5 ++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 40d3ab414b4a..db76798f1273 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -693,6 +693,7 @@ function setupWithdrawalAccount(data) { let error = lodashGet(achData, CONST.BANK_ACCOUNT.VERIFICATIONS.ERROR_MESSAGE); let isErrorHTML = false; const errors = {}; + console.log(currentStep); if (response.jsonCode === 200 && !error) { // Save an NVP with the bankAccountID for this account. This is temporary since we are not showing lists @@ -826,6 +827,7 @@ function setupWithdrawalAccount(data) { * @param {String} params.account.plaidAccountID */ function addPlaidBusinessBankAccount(params) { + console.log(params); setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 9b0c4e3a76ca..fe787d844e1c 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -134,6 +134,7 @@ class BankAccountStep extends React.Component { const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; const subStep = this.props.achData.subStep; + console.log("BankAccountStep", this.props.achData); return ( { + bankAccountType === CONST.BANK_ACCOUNT.BUSINESS + ? addPlaidBusinessBankAccount(params) : ({account, password, plaidLinkToken}) => { + addPersonalBankAccount(account, password, plaidLinkToken); + }; + Navigation.navigate(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); +}; + const PlaidOAuthPage = (props) => { const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); @@ -41,14 +51,17 @@ const PlaidOAuthPage = (props) => { onCloseButtonPress={Navigation.dismissModal} /> { - addPersonalBankAccount(account, password, plaidLinkToken); - }} + onSubmit={params => onSubmit(params, bankAccountType)} receivedRedirectURI={receivedRedirectURI} onExitPlaid={Navigation.dismissModal} plaidLinkToken={props.plaidLinkToken} /> + {/**/} ); }; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 757fd7ab1fd2..176d7b0d6104 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -33,6 +33,7 @@ import ROUTES from '../../ROUTES'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; import WorkspaceResetBankAccountModal from '../workspace/WorkspaceResetBankAccountModal'; +import Button from "../../components/Button"; const propTypes = { /** List of betas */ @@ -206,10 +207,12 @@ class ReimbursementAccountPage extends React.Component { ); } - + console.log(">>>>", currentStep); return ( + + {currentStep === CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT && ( Date: Fri, 12 Nov 2021 20:28:38 -0500 Subject: [PATCH 40/67] Improvement to redirectURI --- src/components/AddPlaidBankAccount/index.js | 13 ++++++++++++- src/pages/ReimbursementAccount/PlaidOAuthPage.js | 14 ++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index ba5ef101f237..6602bdc0013c 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -28,6 +28,7 @@ import ReimbursementAccountForm from '../../pages/ReimbursementAccount/Reimburse import getBankIcon from '../Icon/BankIcons'; import Icon from '../Icon'; import {propTypes, defaultProps} from './plaidBankPropTypes'; +import CONFIG from "../../CONFIG"; const plaidBankPropTypes = { ...withLocalizePropTypes, @@ -52,7 +53,7 @@ class AddPlaidBankAccount extends React.Component { componentDidMount() { // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one - if (this.props.receivedRedirectURI || this.props.plaidLinkToken) { + if (this.props.receivedRedirectURI && this.props.plaidLinkToken) { return; } @@ -72,6 +73,16 @@ class AddPlaidBankAccount extends React.Component { return lodashGet(this.props.plaidBankAccounts, 'accounts', []); } + getRedirectURI() { + let redirectURI = ''; + if (/staging/.test(process.env.EXPENSIFY_URL_CASH)) { + redirectURI = 'staging.expensify.com'; + //https://staging.new.expensify.com/ + return redirectURI; + } + redirectURI = `${CONFIG.EXPENSIFY.URL_EXPENSIFY_COM}`; + } + /** * @returns {Boolean} */ diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index ee72aa9031c5..d4060de5c190 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -12,7 +12,7 @@ import ScreenWrapper from '../../components/ScreenWrapper'; import Navigation from '../../libs/Navigation/Navigation'; import { addPlaidBusinessBankAccount, - addPersonalBankAccount, + addPersonalBankAccount, setBankAccountSubStep, } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import ROUTES from "../../ROUTES"; @@ -33,13 +33,12 @@ const onSubmit = (params, bankAccountType) => { }; const PlaidOAuthPage = (props) => { - const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; + let receivedRedirectURI = window.location.href; + const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); const bankAccountType = lodashGet(props.route, ['params', 'bankAccountType']); - let receivedRedirectURI = window.location.href; - // If there's no stateID passed, then setting the redirectURI to null - // will return the user to the start of the Plaid flow + // If there's no stateID passed, then return user to start of Plaid flow by setting the redirectURI to null if (!oauthStateID) { receivedRedirectURI = null; } @@ -53,7 +52,10 @@ const PlaidOAuthPage = (props) => { onSubmit(params, bankAccountType)} receivedRedirectURI={receivedRedirectURI} - onExitPlaid={Navigation.dismissModal} + onExitPlaid={() => { + setBankAccountSubStep(null); + Navigation.dismissModal(); + }} plaidLinkToken={props.plaidLinkToken} /> {/* Date: Fri, 19 Nov 2021 13:09:15 -0500 Subject: [PATCH 41/67] try to switch over to using ReimbursementPage as base component for PlaidOAuthPage --- src/ROUTES.js | 1 + src/components/AddPlaidBankAccount/index.js | 15 ++++++-- .../AddPlaidBankAccount/plaidBankPropTypes.js | 2 + src/libs/actions/BankAccounts.js | 1 + .../ReimbursementAccount/BankAccountStep.js | 16 ++++++++ .../ReimbursementAccount/PlaidOAuthPage.js | 38 ++++++++++++++----- .../ReimbursementAccountPage.js | 9 ++++- 7 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 20a9291f1ade..de22c8547b2c 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -19,6 +19,7 @@ export default { BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, OAUTH_PLAID: 'partners/plaid/oauth_web/:bankAccountType', + // OAUTH_PLAID: '', HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 6602bdc0013c..7741a9f1934a 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -51,9 +51,12 @@ class AddPlaidBankAccount extends React.Component { } componentDidMount() { + console.log("in AddPlaid", this.props.receivedRedirectURI); + console.log("in AddPlaid", this.props.plaidLinkToken); + console.log("in AddPlaid", this.props.existingPlaidLinkToken); // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one - if (this.props.receivedRedirectURI && this.props.plaidLinkToken) { + if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { return; } @@ -103,6 +106,7 @@ class AddPlaidBankAccount extends React.Component { const account = this.getAccounts()[this.state.selectedIndex]; const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); + const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; this.props.onSubmit({ bankName, account, @@ -116,17 +120,20 @@ class AddPlaidBankAccount extends React.Component { value: index, label: `${account.addressName} ${account.accountNumber}`, })); const {icon, iconSize} = getBankIcon(this.state.institution.name); + const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.existingPlaidLinkToken); + const plaidLinkTokenToUse = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; + return ( <> - {(!this.props.plaidLinkToken || this.props.plaidBankAccounts.loading) + {(plaidLinkToken || this.props.plaidBankAccounts.loading) && ( )} - {!_.isEmpty(this.props.plaidLinkToken) && ( + {plaidLinkToken && ( { Log.info('[PlaidLink] Success!'); getPlaidBankAccounts(publicToken, metadata.institution.name); diff --git a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js index 4b6d72e7c409..2685438904fa 100644 --- a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js +++ b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js @@ -15,6 +15,8 @@ const propTypes = { /** If the bank account being added is a business bank account */ isBusinessBankAccount: PropTypes.bool, + + existingPlaidLinkToken: PropTypes.string, }; const defaultProps = { diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index db76798f1273..6c3e726426da 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -796,6 +796,7 @@ function setupWithdrawalAccount(data) { } // Go to next step + console.log("Before go to withdrawal account", nextStep); goToWithdrawalAccountSetupStep(nextStep, achData); if (_.size(errors)) { diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index fe787d844e1c..085a9481c434 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -20,6 +20,7 @@ import exampleCheckImage from './exampleCheckImage'; import Text from '../../components/Text'; import ExpensiTextInput from '../../components/ExpensiTextInput'; import { + addPersonalBankAccount, addPlaidBusinessBankAccount, setBankAccountFormValidationErrors, setBankAccountSubStep, @@ -35,15 +36,25 @@ import ReimbursementAccountForm from './ReimbursementAccountForm'; import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; import WorkspaceSection from '../workspace/WorkspaceSection'; import {BankMouseGreen} from '../../components/Icon/Illustrations'; +import lodashGet from "lodash/get"; +import PropTypes from "prop-types"; const propTypes = { /** Bank account currently in setup */ // eslint-disable-next-line react/no-unused-prop-types reimbursementAccount: reimbursementAccountPropTypes.isRequired, + receivedRedirectURI: PropTypes.string, + existingPlaidLinkToken: PropTypes.string, + ...withLocalizePropTypes, }; +const defaultProps = { + receivedRedirectURI: null, + existingPlaidLinkToken: '', +}; + class BankAccountStep extends React.Component { constructor(props) { super(props); @@ -135,6 +146,7 @@ class BankAccountStep extends React.Component { const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; const subStep = this.props.achData.subStep; console.log("BankAccountStep", this.props.achData); + console.log(isFromPlaid); return ( setBankAccountSubStep(null)} isBusinessBankAccount + receivedRedirectURI={this.props.receivedRedirectURI} + existingPlaidLinkToken={this.props.existingPlaidLinkToken} /> )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( @@ -270,6 +284,8 @@ class BankAccountStep extends React.Component { } BankAccountStep.propTypes = propTypes; +BankAccountStep.defaultProps = defaultProps; + export default compose( withLocalize, withOnyx({ diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index d4060de5c190..17454891209b 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -16,6 +16,7 @@ import { } from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import ROUTES from "../../ROUTES"; +import ReimbursementAccountPage from "./ReimbursementAccountPage"; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -24,15 +25,27 @@ const propTypes = { ...withLocalizePropTypes, }; -const onSubmit = (params, bankAccountType) => { +const onSubmit = (params, bankAccountType, reimbursementAccount) => { bankAccountType === CONST.BANK_ACCOUNT.BUSINESS ? addPlaidBusinessBankAccount(params) : ({account, password, plaidLinkToken}) => { addPersonalBankAccount(account, password, plaidLinkToken); }; - Navigation.navigate(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); + // const promise = bankAccountType === CONST.BANK_ACCOUNT.BUSINESS + // ? addPlaidBusinessBankAccount(params) : ({account, password, plaidLinkToken}) => { + // addPersonalBankAccount(account, password, plaidLinkToken); + // }; + // promise.then(() => { + // console.log("Here in resolved promise", ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); + // Navigation.navigate(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); + // }) + console.log(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); + console.log(reimbursementAccount); + // Navigation.navigate(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); + // console.log(ONYXKEYS.REIMBURSEMENT_ACCOUNT); }; const PlaidOAuthPage = (props) => { + console.log(props); let receivedRedirectURI = window.location.href; const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); @@ -49,16 +62,20 @@ const PlaidOAuthPage = (props) => { title={props.translate('bankAccount.addBankAccount')} onCloseButtonPress={Navigation.dismissModal} /> - onSubmit(params, bankAccountType)} + { - setBankAccountSubStep(null); - Navigation.dismissModal(); - }} - plaidLinkToken={props.plaidLinkToken} + existingPlaidLinkToken={props.plaidLinkToken} /> {/* onSubmit(params, bankAccountType, props.reimbursementAccount)}*/} + {/* receivedRedirectURI={receivedRedirectURI}*/} + {/* onExitPlaid={() => {*/} + {/* setBankAccountSubStep(null);*/} + {/* Navigation.dismissModal();*/} + {/* }}*/} + {/* plaidLinkToken={props.plaidLinkToken}*/} + {/*/>*/} + {/* ); } - console.log(">>>>", currentStep); + console.log("ReimbursementAccountPage", currentStep); return ( @@ -217,6 +222,8 @@ class ReimbursementAccountPage extends React.Component { )} {currentStep === CONST.BANK_ACCOUNT.STEP.COMPANY && ( From 01dad51b01abe0f2a495bdb72018a1fda5e6361d Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Fri, 19 Nov 2021 15:38:41 -0500 Subject: [PATCH 42/67] Cleanup, going from selecting account to CompanyStep works now --- src/ROUTES.js | 1 - .../ReimbursementAccount/PlaidOAuthPage.js | 40 ++++++++----------- .../ReimbursementAccountPage.js | 2 - 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index de22c8547b2c..20a9291f1ade 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -19,7 +19,6 @@ export default { BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, OAUTH_PLAID: 'partners/plaid/oauth_web/:bankAccountType', - // OAUTH_PLAID: '', HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 17454891209b..6175682c52b1 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -1,4 +1,3 @@ - import React from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; @@ -58,29 +57,22 @@ const PlaidOAuthPage = (props) => { return ( - - - {/* onSubmit(params, bankAccountType, props.reimbursementAccount)}*/} - {/* receivedRedirectURI={receivedRedirectURI}*/} - {/* onExitPlaid={() => {*/} - {/* setBankAccountSubStep(null);*/} - {/* Navigation.dismissModal();*/} - {/* }}*/} - {/* plaidLinkToken={props.plaidLinkToken}*/} - {/*/>*/} - {/**/} + {bankAccountType === CONST.BANK_ACCOUNT.BUSINESS ? ( + + ) : ( + { + addPersonalBankAccount(account, password, plaidLinkToken); + }} + onExitPlaid={Navigation.dismissModal} + isBusinessBankAccount={false} + existingPlaidLinkToken={props.plaidLinkToken} + receivedRedirectURI={receivedRedirectURI} + /> + )} ); }; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index b955bdc4255e..e5b99385c69c 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -216,8 +216,6 @@ class ReimbursementAccountPage extends React.Component { return ( - - {currentStep === CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT && ( Date: Fri, 19 Nov 2021 16:34:09 -0500 Subject: [PATCH 43/67] Fix error where substep returns null and makes us go back to BankAccountStep page --- src/components/AddPlaidBankAccount/index.js | 2 +- src/pages/ReimbursementAccount/BankAccountStep.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 7741a9f1934a..e1c0a07eb12c 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -125,7 +125,7 @@ class AddPlaidBankAccount extends React.Component { return ( <> - {(plaidLinkToken || this.props.plaidBankAccounts.loading) + {(!plaidLinkToken || this.props.plaidBankAccounts.loading) && ( diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 085a9481c434..96dfe737b897 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -144,9 +144,12 @@ class BankAccountStep extends React.Component { // Disable bank account fields once they've been added in db so they can't be changed const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; - const subStep = this.props.achData.subStep; + const shouldReinitializedPlaidLink = this.props.existingPlaidLinkToken && this.props.receivedRedirectURI; + const subStep = shouldReinitializedPlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; + console.log("BankAccountStep", this.props.achData); console.log(isFromPlaid); + console.log(subStep); return ( Date: Fri, 19 Nov 2021 17:11:54 -0500 Subject: [PATCH 44/67] Revert BankAccountStep external setupBankAccount method --- .../ReimbursementAccount/BankAccountStep.js | 36 ++++++++++++++++++- .../ReimbursementAccount/PlaidOAuthPage.js | 28 ++------------- .../ReimbursementAccountPage.js | 2 -- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 96dfe737b897..a21b15f4a248 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -61,6 +61,7 @@ class BankAccountStep extends React.Component { this.toggleTerms = this.toggleTerms.bind(this); this.addManualAccount = this.addManualAccount.bind(this); + this.addPlaidAccount = this.addPlaidAccount.bind(this); this.state = { // One of CONST.BANK_ACCOUNT.SETUP_TYPE hasAcceptedTerms: ReimbursementAccountUtils.getDefaultStateForField(props, 'acceptTerms', true), @@ -140,6 +141,39 @@ class BankAccountStep extends React.Component { }); } + /** + * @param {Object} params + * @param {Object} params.account + * @param {String} params.account.bankName + * @param {Boolean} params.account.isSavings + * @param {String} params.account.addressName + * @param {String} params.account.ownershipType + * @param {String} params.account.accountNumber + * @param {String} params.account.routingNumber + * @param {String} params.account.plaidAccountID + */ + addPlaidAccount(params) { + setupWithdrawalAccount({ + acceptTerms: true, + setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, + + // Params passed via the Plaid callback when an account is selected + plaidAccessToken: params.plaidLinkToken, + accountNumber: params.account.accountNumber, + routingNumber: params.account.routingNumber, + plaidAccountID: params.account.plaidAccountID, + ownershipType: params.account.ownershipType, + isSavings: params.account.isSavings, + bankName: params.bankName, + addressName: params.account.addressName, + + // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan + country: CONST.COUNTRY.US, + currency: CONST.CURRENCY.USD, + fieldsType: CONST.BANK_ACCOUNT.FIELDS_TYPE.LOCAL, + }); + } + render() { // Disable bank account fields once they've been added in db so they can't be changed const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; @@ -227,7 +261,7 @@ class BankAccountStep extends React.Component { {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( setBankAccountSubStep(null)} isBusinessBankAccount receivedRedirectURI={this.props.receivedRedirectURI} diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js index 6175682c52b1..48be49c93d9f 100644 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ b/src/pages/ReimbursementAccount/PlaidOAuthPage.js @@ -6,16 +6,11 @@ import CONST from '../../CONST'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ONYXKEYS from '../../ONYXKEYS'; import compose from '../../libs/compose'; -import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import ScreenWrapper from '../../components/ScreenWrapper'; import Navigation from '../../libs/Navigation/Navigation'; -import { - addPlaidBusinessBankAccount, - addPersonalBankAccount, setBankAccountSubStep, -} from '../../libs/actions/BankAccounts'; +import {addPersonalBankAccount} from '../../libs/actions/BankAccounts'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; -import ROUTES from "../../ROUTES"; -import ReimbursementAccountPage from "./ReimbursementAccountPage"; +import ReimbursementAccountPage from './ReimbursementAccountPage'; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -24,25 +19,6 @@ const propTypes = { ...withLocalizePropTypes, }; -const onSubmit = (params, bankAccountType, reimbursementAccount) => { - bankAccountType === CONST.BANK_ACCOUNT.BUSINESS - ? addPlaidBusinessBankAccount(params) : ({account, password, plaidLinkToken}) => { - addPersonalBankAccount(account, password, plaidLinkToken); - }; - // const promise = bankAccountType === CONST.BANK_ACCOUNT.BUSINESS - // ? addPlaidBusinessBankAccount(params) : ({account, password, plaidLinkToken}) => { - // addPersonalBankAccount(account, password, plaidLinkToken); - // }; - // promise.then(() => { - // console.log("Here in resolved promise", ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); - // Navigation.navigate(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); - // }) - console.log(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); - console.log(reimbursementAccount); - // Navigation.navigate(ROUTES.getWorkspaceBankAccountRoute('420CE21A85AC96F0')); - // console.log(ONYXKEYS.REIMBURSEMENT_ACCOUNT); -}; - const PlaidOAuthPage = (props) => { console.log(props); let receivedRedirectURI = window.location.href; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index e5b99385c69c..1798026337be 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -33,7 +33,6 @@ import ROUTES from '../../ROUTES'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; import WorkspaceResetBankAccountModal from '../workspace/WorkspaceResetBankAccountModal'; -import Button from "../../components/Button"; const propTypes = { /** List of betas */ @@ -212,7 +211,6 @@ class ReimbursementAccountPage extends React.Component { ); } - console.log("ReimbursementAccountPage", currentStep); return ( From a254c03ce6cac109e9e620760d7586ac384817b7 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 14:41:04 -0500 Subject: [PATCH 45/67] Switch over to just using ReimbursementPage instead of new OAuthPlaid page --- src/components/AddPlaidBankAccount/index.js | 11 +++++++---- src/libs/actions/BankAccounts.js | 6 +++++- .../ReimbursementAccount/BankAccountStep.js | 5 +++-- .../ReimbursementAccount/PlaidOAuthPage.js | 1 - .../ReimbursementAccountPage.js | 19 +++++++++++++++++-- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index e1c0a07eb12c..a5cd903857ce 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -44,6 +44,7 @@ class AddPlaidBankAccount extends React.Component { this.state = { selectedIndex: undefined, institution: {}, + plaidConnectionErrors: {}, }; this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); @@ -60,9 +61,10 @@ class AddPlaidBankAccount extends React.Component { return; } - const redirectURI = this.props.isBusinessBankAccount - ? `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.BUSINESS}` - : `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.PERSONAL}`; + // const redirectURI = this.props.isBusinessBankAccount + // ? `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.BUSINESS}` + // : `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.PERSONAL}`; + const redirectURI = `http://localhost:8080/bank-account`; clearPlaidBankAccountsAndToken(); fetchPlaidLinkToken(redirectURI); } @@ -110,7 +112,7 @@ class AddPlaidBankAccount extends React.Component { this.props.onSubmit({ bankName, account, - plaidLinkToken: this.props.plaidLinkToken, + plaidLinkToken: plaidLinkToken, }); } @@ -141,6 +143,7 @@ class AddPlaidBankAccount extends React.Component { }} onError={(error) => { Log.hmmm('[PlaidLink] Error: ', error.message); + // this.setState({plaidConnectionErrors: error}); }} // User prematurely exited the Plaid flow diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 6c3e726426da..8628a29a040c 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -49,12 +49,13 @@ Onyx.connect({ * * @param {String} redirectURI */ -function fetchPlaidLinkToken(redirectURI = null) { +function fetchPlaidLinkToken(redirectURI) { API.Plaid_GetLinkToken({redirect_uri: redirectURI}) .then((response) => { if (response.jsonCode !== 200) { return; } + console.log("Fetched plaidLink token", response); Onyx.merge(ONYXKEYS.PLAID_LINK_TOKEN, response.linkToken); }); } @@ -684,11 +685,14 @@ function setupWithdrawalAccount(data) { )); newACHData.accountNumber = unmaskedAccount.accountNumber; } + console.log("newACHData", newACHData); API.BankAccount_SetupWithdrawal(newACHData) .then((response) => { + console.log("response", response); Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {...newACHData}}); const currentStep = newACHData.currentStep; + console.log("in .then with currentStep", currentStep); let achData = lodashGet(response, 'achData', {}); let error = lodashGet(achData, CONST.BANK_ACCOUNT.VERIFICATIONS.ERROR_MESSAGE); let isErrorHTML = false; diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index a21b15f4a248..3fca3928cea6 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -153,6 +153,7 @@ class BankAccountStep extends React.Component { * @param {String} params.account.plaidAccountID */ addPlaidAccount(params) { + console.log("addPlaidAccount", params); setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, @@ -182,8 +183,8 @@ class BankAccountStep extends React.Component { const subStep = shouldReinitializedPlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; console.log("BankAccountStep", this.props.achData); - console.log(isFromPlaid); - console.log(subStep); + console.log("BankAccountStep isFromPlaid", isFromPlaid); + console.log("BankAccountStep subStep", subStep); return ( { - console.log(props); let receivedRedirectURI = window.location.href; const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 1798026337be..c292add96cc0 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -82,6 +82,15 @@ class ReimbursementAccountPage extends React.Component { // If we are trying to navigate to `/bank-account/new` and we already have a bank account then don't allow returning to `/new` fetchFreePlanVerifiedBankAccount(stepToOpen !== CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT ? stepToOpen : ''); + this.receivedRedirectURI = window.location.href; + const receivedRedirectSearchParams = (new URL(this.receivedRedirectURI)).searchParams; + const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); + const bankAccountType = lodashGet(this.props.route, ['params', 'bankAccountType']); + + // If there's no stateID passed, then return user to start of Plaid flow by setting the redirectURI to null + if (!oauthStateID) { + this.receivedRedirectURI = null; + } } componentDidUpdate(prevProps) { @@ -199,6 +208,7 @@ class ReimbursementAccountPage extends React.Component { ); } + console.log("throttled date", throttledDate); if (errorComponent) { return ( @@ -218,8 +228,10 @@ class ReimbursementAccountPage extends React.Component { )} {currentStep === CONST.BANK_ACCOUNT.STEP.COMPANY && ( @@ -260,6 +272,9 @@ export default compose( betas: { key: ONYXKEYS.BETAS, }, + plaidLinkToken: { + key: ONYXKEYS.PLAID_LINK_TOKEN, + }, }), withLocalize, )(ReimbursementAccountPage); From 9ae9461ed228bdade715ed16e931a26620235dfe Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 15:41:27 -0500 Subject: [PATCH 46/67] Add getOAuthReceivedRedirectURI and add it to Personal Bank Account Page --- src/libs/actions/BankAccounts.js | 13 +++++++ src/pages/AddPersonalBankAccountPage.js | 38 +++++++++++-------- .../ReimbursementAccountPage.js | 12 ++---- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 8628a29a040c..c600460a2df5 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -947,6 +947,18 @@ function validateRoutingNumber(number) { return false; } +function getOAuthReceivedRedirectURI() { + let receivedRedirectURI = window.location.href; + const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; + const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); + + // If there's no stateID passed, then return user to start of Plaid flow by setting the redirectURI to null + if (!oauthStateID) { + receivedRedirectURI = null; + } + return receivedRedirectURI; +} + export { activateWallet, addPersonalBankAccount, @@ -956,6 +968,7 @@ export { fetchOnfidoToken, fetchPlaidLinkToken, fetchUserWallet, + getOAuthReceivedRedirectURI, getPlaidBankAccounts, goToWithdrawalAccountSetupStep, setupWithdrawalAccount, diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js index 35f7b0996fb5..1b6808f8f505 100644 --- a/src/pages/AddPersonalBankAccountPage.js +++ b/src/pages/AddPersonalBankAccountPage.js @@ -4,6 +4,7 @@ import ScreenWrapper from '../components/ScreenWrapper'; import Navigation from '../libs/Navigation/Navigation'; import { addPersonalBankAccount, + getOAuthReceivedRedirectURI, } from '../libs/actions/BankAccounts'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import AddPlaidBankAccount from '../components/AddPlaidBankAccount'; @@ -12,21 +13,28 @@ const propTypes = { ...withLocalizePropTypes, }; -const AddPersonalBankAccountPage = props => ( - - - { - addPersonalBankAccount(account, password, plaidLinkToken); - }} - onExitPlaid={Navigation.dismissModal} - isBusinessBankAccount={false} - /> - -); +const AddPersonalBankAccountPage = props => { + // If we are coming back from the Plaid OAuth flow + const receivedRedirectURI = getOAuthReceivedRedirectURI(); + + return ( + + + { + addPersonalBankAccount(account, password, plaidLinkToken); + }} + onExitPlaid={Navigation.dismissModal} + isBusinessBankAccount={false} + receivedRedirectURI={receivedRedirectURI} + existingPlaidLinkToken={props.plaidLinkToken} + /> + + ); +} AddPersonalBankAccountPage.propTypes = propTypes; AddPersonalBankAccountPage.displayName = 'AddPersonalBankAccountPage'; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index c292add96cc0..a8cd5892b56e 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -9,6 +9,7 @@ import Log from '../../libs/Log'; import ScreenWrapper from '../../components/ScreenWrapper'; import { fetchFreePlanVerifiedBankAccount, + getOAuthReceivedRedirectURI, hideBankAccountErrors, } from '../../libs/actions/BankAccounts'; import ONYXKEYS from '../../ONYXKEYS'; @@ -82,15 +83,9 @@ class ReimbursementAccountPage extends React.Component { // If we are trying to navigate to `/bank-account/new` and we already have a bank account then don't allow returning to `/new` fetchFreePlanVerifiedBankAccount(stepToOpen !== CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT ? stepToOpen : ''); - this.receivedRedirectURI = window.location.href; - const receivedRedirectSearchParams = (new URL(this.receivedRedirectURI)).searchParams; - const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); - const bankAccountType = lodashGet(this.props.route, ['params', 'bankAccountType']); - // If there's no stateID passed, then return user to start of Plaid flow by setting the redirectURI to null - if (!oauthStateID) { - this.receivedRedirectURI = null; - } + // If we are coming back from the Plaid OAuth flow + this.receivedRedirectURI = getOAuthReceivedRedirectURI(); } componentDidUpdate(prevProps) { @@ -208,7 +203,6 @@ class ReimbursementAccountPage extends React.Component { ); } - console.log("throttled date", throttledDate); if (errorComponent) { return ( From 1d50056d6f367c8ac72f778f3b6c7acd7a6f877c Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 15:44:42 -0500 Subject: [PATCH 47/67] Revert old changes --- src/CONST.js | 2 -- src/ROUTES.js | 1 - src/libs/Navigation/AppNavigator/AuthScreens.js | 7 ------- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 7 ------- src/libs/Navigation/linkingConfig.js | 5 ----- src/pages/AddPersonalBankAccountPage.js | 1 - src/pages/ReimbursementAccount/ReimbursementAccountPage.js | 2 -- 7 files changed, 25 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 0741eccd04af..9a0fe6e80263 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -17,8 +17,6 @@ const CONST = { DOMAIN: '@expensify.sms', }, BANK_ACCOUNT: { - BUSINESS: 'business', - PERSONAL: 'personal', PLAID: { ALLOWED_THROTTLED_COUNT: 2, ERROR: { diff --git a/src/ROUTES.js b/src/ROUTES.js index 20a9291f1ade..9facdbd64a1b 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -18,7 +18,6 @@ export default { BANK_ACCOUNT: 'bank-account/:stepToOpen?', BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, - OAUTH_PLAID: 'partners/plaid/oauth_web/:bankAccountType', HOME: '', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 5e2b6d1accd7..9f94279e144d 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -54,7 +54,6 @@ import { AddPersonalBankAccountModalStackNavigator, RequestCallModalStackNavigator, ReportDetailsModalStackNavigator, - PlaidOAuthModalStackNavigator, } from './ModalStackNavigators'; import SCREENS from '../../../SCREENS'; import Timers from '../../Timers'; @@ -369,12 +368,6 @@ class AuthScreens extends React.Component { component={IOUSendModalStackNavigator} listeners={modalScreenListeners} /> - ); } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 5da0c4209a5c..4b998a632ee4 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -37,7 +37,6 @@ import WorkspaceBillsPage from '../../../pages/workspace/bills/WorkspaceBillsPag import WorkspaceTravelPage from '../../../pages/workspace/travel/WorkspaceTravelPage'; import WorkspaceMembersPage from '../../../pages/workspace/WorkspaceMembersPage'; import WorkspaceBankAccountPage from '../../../pages/workspace/WorkspaceBankAccountPage'; -import PlaidOAuthPage from '../../../pages/ReimbursementAccount/PlaidOAuthPage'; import CONST from '../../../CONST'; const defaultSubRouteOptions = { @@ -250,11 +249,6 @@ const RequestCallModalStackNavigator = createModalStackNavigator([{ name: 'RequestCall_Root', }]); -const PlaidOAuthModalStackNavigator = createModalStackNavigator([{ - Component: PlaidOAuthPage, - name: 'OAuth_Plaid_Root', -}]); - export { IOUBillStackNavigator, IOURequestModalStackNavigator, @@ -271,5 +265,4 @@ export { AddPersonalBankAccountModalStackNavigator, ReimbursementAccountModalStackNavigator, RequestCallModalStackNavigator, - PlaidOAuthModalStackNavigator, }; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index aacc6f607bfc..a5a13343b0c2 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -178,11 +178,6 @@ export default { RequestCall_Root: ROUTES.REQUEST_CALL, }, }, - OAUTH_PLAID_REDIRECT: { - screens: { - OAuth_Plaid_Root: ROUTES.OAUTH_PLAID, - }, - }, }, }, }; diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js index 1b6808f8f505..af4204ea9943 100644 --- a/src/pages/AddPersonalBankAccountPage.js +++ b/src/pages/AddPersonalBankAccountPage.js @@ -28,7 +28,6 @@ const AddPersonalBankAccountPage = props => { addPersonalBankAccount(account, password, plaidLinkToken); }} onExitPlaid={Navigation.dismissModal} - isBusinessBankAccount={false} receivedRedirectURI={receivedRedirectURI} existingPlaidLinkToken={props.plaidLinkToken} /> diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index a8cd5892b56e..91aac01ccb0c 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -222,9 +222,7 @@ class ReimbursementAccountPage extends React.Component { )} From fc1095a9999f90bbcc13a660e5bb9287ef199315 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 15:47:46 -0500 Subject: [PATCH 48/67] More cleanup --- src/libs/actions/BankAccounts.js | 41 ------------------- .../ReimbursementAccount/BankAccountStep.js | 5 --- .../ReimbursementAccountPage.js | 5 --- 3 files changed, 51 deletions(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index c600460a2df5..6b4cb94eb15e 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -55,7 +55,6 @@ function fetchPlaidLinkToken(redirectURI) { if (response.jsonCode !== 200) { return; } - console.log("Fetched plaidLink token", response); Onyx.merge(ONYXKEYS.PLAID_LINK_TOKEN, response.linkToken); }); } @@ -685,19 +684,15 @@ function setupWithdrawalAccount(data) { )); newACHData.accountNumber = unmaskedAccount.accountNumber; } - console.log("newACHData", newACHData); API.BankAccount_SetupWithdrawal(newACHData) .then((response) => { - console.log("response", response); Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {...newACHData}}); const currentStep = newACHData.currentStep; - console.log("in .then with currentStep", currentStep); let achData = lodashGet(response, 'achData', {}); let error = lodashGet(achData, CONST.BANK_ACCOUNT.VERIFICATIONS.ERROR_MESSAGE); let isErrorHTML = false; const errors = {}; - console.log(currentStep); if (response.jsonCode === 200 && !error) { // Save an NVP with the bankAccountID for this account. This is temporary since we are not showing lists @@ -800,7 +795,6 @@ function setupWithdrawalAccount(data) { } // Go to next step - console.log("Before go to withdrawal account", nextStep); goToWithdrawalAccountSetupStep(nextStep, achData); if (_.size(errors)) { @@ -820,40 +814,6 @@ function setupWithdrawalAccount(data) { }); } -/** - * @param {Object} params - * @param {Object} params.account - * @param {String} params.account.bankName - * @param {Boolean} params.account.isSavings - * @param {String} params.account.addressName - * @param {String} params.account.ownershipType - * @param {String} params.account.accountNumber - * @param {String} params.account.routingNumber - * @param {String} params.account.plaidAccountID - */ -function addPlaidBusinessBankAccount(params) { - console.log(params); - setupWithdrawalAccount({ - acceptTerms: true, - setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, - - // Params passed via the Plaid callback when an account is selected - plaidAccessToken: params.plaidLinkToken, - accountNumber: params.account.accountNumber, - routingNumber: params.account.routingNumber, - plaidAccountID: params.account.plaidAccountID, - ownershipType: params.account.ownershipType, - isSavings: params.account.isSavings, - bankName: params.bankName, - addressName: params.account.addressName, - - // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan - country: CONST.COUNTRY.US, - currency: CONST.CURRENCY.USD, - fieldsType: CONST.BANK_ACCOUNT.FIELDS_TYPE.LOCAL, - }); -} - function hideBankAccountErrors() { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error: '', errors: null}); } @@ -962,7 +922,6 @@ function getOAuthReceivedRedirectURI() { export { activateWallet, addPersonalBankAccount, - addPlaidBusinessBankAccount, clearPlaidBankAccountsAndToken, fetchFreePlanVerifiedBankAccount, fetchOnfidoToken, diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 3fca3928cea6..686839d7bb6d 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -153,7 +153,6 @@ class BankAccountStep extends React.Component { * @param {String} params.account.plaidAccountID */ addPlaidAccount(params) { - console.log("addPlaidAccount", params); setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, @@ -182,9 +181,6 @@ class BankAccountStep extends React.Component { const shouldReinitializedPlaidLink = this.props.existingPlaidLinkToken && this.props.receivedRedirectURI; const subStep = shouldReinitializedPlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; - console.log("BankAccountStep", this.props.achData); - console.log("BankAccountStep isFromPlaid", isFromPlaid); - console.log("BankAccountStep subStep", subStep); return ( setBankAccountSubStep(null)} - isBusinessBankAccount receivedRedirectURI={this.props.receivedRedirectURI} existingPlaidLinkToken={this.props.existingPlaidLinkToken} /> diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 91aac01ccb0c..e58bf31ec281 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -57,9 +57,6 @@ const propTypes = { }), }), - receivedRedirectURI: PropTypes.string, - existingPlaidLinkToken: PropTypes.string, - ...withLocalizePropTypes, }; @@ -72,8 +69,6 @@ const defaultProps = { stepToOpen: '', }, }, - receivedRedirectURI: null, - existingPlaidLinkToken: '', }; class ReimbursementAccountPage extends React.Component { From 791dc619c0b938984738eb0dd531559cbd760948 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 16:46:55 -0500 Subject: [PATCH 49/67] Cleanup redirect URI logic and fix IdentityForm address error --- src/components/AddPlaidBankAccount/index.js | 24 +++++++++---------- src/libs/Url.js | 14 +++++++++++ .../ReimbursementAccount/IdentityForm.js | 4 ++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index a5cd903857ce..734b4949ac12 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -28,7 +28,8 @@ import ReimbursementAccountForm from '../../pages/ReimbursementAccount/Reimburse import getBankIcon from '../Icon/BankIcons'; import Icon from '../Icon'; import {propTypes, defaultProps} from './plaidBankPropTypes'; -import CONFIG from "../../CONFIG"; +import ROUTES from '../../ROUTES'; +import {removeTrailingForwardSlash} from '../../libs/Url'; const plaidBankPropTypes = { ...withLocalizePropTypes, @@ -52,21 +53,14 @@ class AddPlaidBankAccount extends React.Component { } componentDidMount() { - console.log("in AddPlaid", this.props.receivedRedirectURI); - console.log("in AddPlaid", this.props.plaidLinkToken); - console.log("in AddPlaid", this.props.existingPlaidLinkToken); // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { return; } - // const redirectURI = this.props.isBusinessBankAccount - // ? `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.BUSINESS}` - // : `http://localhost:8080/partners/plaid/oauth_web/${CONST.BANK_ACCOUNT.PERSONAL}`; - const redirectURI = `http://localhost:8080/bank-account`; clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(redirectURI); + fetchPlaidLinkToken(this.getRedirectURI()); } /** @@ -78,14 +72,18 @@ class AddPlaidBankAccount extends React.Component { return lodashGet(this.props.plaidBankAccounts, 'accounts', []); } + /** + * @returns {String} + */ getRedirectURI() { - let redirectURI = ''; + let redirectURI; + let bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); if (/staging/.test(process.env.EXPENSIFY_URL_CASH)) { - redirectURI = 'staging.expensify.com'; - //https://staging.new.expensify.com/ + redirectURI = `${CONST.STAGING_NEW_EXPENSIFY_URL}/${bankAccountRoute}`; return redirectURI; } - redirectURI = `${CONFIG.EXPENSIFY.URL_EXPENSIFY_COM}`; + redirectURI = `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`; + return `http://localhost:8080/${bankAccountRoute}`; } /** diff --git a/src/libs/Url.js b/src/libs/Url.js index e166c127a83f..b48f113c3f32 100644 --- a/src/libs/Url.js +++ b/src/libs/Url.js @@ -10,7 +10,21 @@ function addTrailingForwardSlash(url) { return url; } +/** + * Remove / to the end of any URL if present + * @param {String} url + * @returns {String} + */ +function removeTrailingForwardSlash(url) { + if (url.endsWith('/')) { + return url.slice(0, -1); + } + return url; +} + + export { // eslint-disable-next-line import/prefer-default-export addTrailingForwardSlash, + removeTrailingForwardSlash, }; diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 683de6a3f350..cfbdaa466ef2 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -133,7 +133,7 @@ const IdentityForm = (props) => { errorText={props.errors.ssnLast4 ? props.translate('bankAccount.error.ssnLast4') : ''} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.SSN} /> - {props.manualAddress ? ( + {props.values.manualAddress ? ( <> { props.onFieldChange('addressState', value)} errorText={props.errors.state ? props.translate('bankAccount.error.addressState') : ''} hasError={Boolean(props.errors.state)} From 3314dc4a1bd1e6423d661334e2653104d6f809d7 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 17:15:51 -0500 Subject: [PATCH 50/67] Hook up BaseAddPlaidPage and delete old OAuthPlaidPage --- .../BaseAddPlaidBankAccount.js | 212 +++++++++++++++++ src/components/AddPlaidBankAccount/index.js | 222 +----------------- .../ReimbursementAccount/BankAccountStep.js | 2 - .../ReimbursementAccount/PlaidOAuthPage.js | 67 ------ 4 files changed, 224 insertions(+), 279 deletions(-) create mode 100644 src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js delete mode 100644 src/pages/ReimbursementAccount/PlaidOAuthPage.js diff --git a/src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js b/src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js new file mode 100644 index 000000000000..e9b0916d95f8 --- /dev/null +++ b/src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js @@ -0,0 +1,212 @@ +import _ from 'underscore'; +import React from 'react'; +import { + ActivityIndicator, + View, +} from 'react-native'; +import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; +import Log from '../../libs/Log'; +import PlaidLink from '../PlaidLink/index'; +import CONST from '../../CONST'; +import { + clearPlaidBankAccountsAndToken, + fetchPlaidLinkToken, + getPlaidBankAccounts, + setBankAccountFormValidationErrors, + showBankAccountErrorModal, +} from '../../libs/actions/BankAccounts'; +import ONYXKEYS from '../../ONYXKEYS'; +import styles from '../../styles/styles'; +import themeColors from '../../styles/themes/default'; +import compose from '../../libs/compose'; +import withLocalize, {withLocalizePropTypes} from '../withLocalize'; +import ExpensiPicker from '../ExpensiPicker'; +import Text from '../Text'; +import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; +import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; +import getBankIcon from '../Icon/BankIcons'; +import Icon from '../Icon'; +import {propTypes, defaultProps} from './plaidBankPropTypes'; +import ROUTES from '../../ROUTES'; +import {removeTrailingForwardSlash} from '../../libs/Url'; + +const plaidBankPropTypes = { + ...withLocalizePropTypes, + ...propTypes, +}; + +class BaseAddPlaidBankAccount extends React.Component { + constructor(props) { + super(props); + + this.selectAccount = this.selectAccount.bind(this); + + this.state = { + selectedIndex: undefined, + institution: {}, + plaidConnectionErrors: {}, + }; + + this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); + this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); + } + + componentDidMount() { + // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken + // Otherwise, clear the existing token and fetch a new one + if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { + return; + } + + clearPlaidBankAccountsAndToken(); + fetchPlaidLinkToken(this.getRedirectURI()); + } + + /** + * Get list of bank accounts + * + * @returns {Object[]} + */ + getAccounts() { + return lodashGet(this.props.plaidBankAccounts, 'accounts', []); + } + + /** + * @returns {String} + */ + getRedirectURI() { + let redirectURI; + let bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); + if (/staging/.test(process.env.EXPENSIFY_URL_CASH)) { + redirectURI = `${CONST.STAGING_NEW_EXPENSIFY_URL}/${bankAccountRoute}`; + return redirectURI; + } + redirectURI = `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`; + return `http://localhost:8080/${bankAccountRoute}`; + } + + /** + * @returns {Boolean} + */ + validate() { + const errors = {}; + if (_.isUndefined(this.state.selectedIndex)) { + errors.selectedBank = true; + } + setBankAccountFormValidationErrors(errors); + return _.size(errors) === 0; + } + + selectAccount() { + if (!this.validate()) { + showBankAccountErrorModal(); + return; + } + + const account = this.getAccounts()[this.state.selectedIndex]; + const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); + const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; + this.props.onSubmit({ + bankName, + account, + plaidLinkToken: plaidLinkToken, + }); + } + + render() { + const accounts = this.getAccounts(); + const options = _.map(accounts, (account, index) => ({ + value: index, label: `${account.addressName} ${account.accountNumber}`, + })); + const {icon, iconSize} = getBankIcon(this.state.institution.name); + const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.existingPlaidLinkToken); + const plaidLinkTokenToUse = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; + + return ( + <> + {(!plaidLinkToken || this.props.plaidBankAccounts.loading) + && ( + + + + )} + {plaidLinkToken && ( + { + Log.info('[PlaidLink] Success!'); + getPlaidBankAccounts(publicToken, metadata.institution.name); + this.setState({institution: metadata.institution}); + }} + onError={(error) => { + Log.hmmm('[PlaidLink] Error: ', error.message); + // this.setState({plaidConnectionErrors: error}); + }} + + // User prematurely exited the Plaid flow + // eslint-disable-next-line react/jsx-props-no-multi-spaces + onExit={this.props.onExitPlaid} + receivedRedirectUri={this.props.receivedRedirectURI} + /> + )} + {accounts.length > 0 && ( + + {!_.isEmpty(this.props.text) && ( + {this.props.text} + )} + + + {this.state.institution.name} + + + { + this.setState({selectedIndex: Number(index)}); + this.clearError('selectedBank'); + }} + items={options} + placeholder={_.isUndefined(this.state.selectedIndex) ? { + value: '', + label: this.props.translate('bankAccount.chooseAnAccount'), + } : {}} + value={this.state.selectedIndex} + hasError={this.getErrors().selectedBank} + /> + + + )} + + ); + } +} + +BaseAddPlaidBankAccount.propTypes = plaidBankPropTypes; +BaseAddPlaidBankAccount.defaultProps = defaultProps; + +export default compose( + withLocalize, + withOnyx({ + plaidLinkToken: { + key: ONYXKEYS.PLAID_LINK_TOKEN, + + // We always fetch a new token to call Plaid. If we don't then it's possible to open multiple Plaid Link instances. In particular, this can cause issues for Android e.g. + // inability to hand off to React Native once the bank connection is made. This is because an old stashed token will mount the PlaidLink component then it gets set again + // which will mount another PlaidLink component. + initWithStoredValues: false, + }, + plaidBankAccounts: { + key: ONYXKEYS.PLAID_BANK_ACCOUNTS, + }, + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + }), +)(BaseAddPlaidBankAccount); diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js index 734b4949ac12..002c2ab932fb 100644 --- a/src/components/AddPlaidBankAccount/index.js +++ b/src/components/AddPlaidBankAccount/index.js @@ -1,212 +1,14 @@ -import _ from 'underscore'; import React from 'react'; -import { - ActivityIndicator, - View, -} from 'react-native'; -import lodashGet from 'lodash/get'; -import {withOnyx} from 'react-native-onyx'; -import Log from '../../libs/Log'; -import PlaidLink from '../PlaidLink/index'; -import CONST from '../../CONST'; -import { - clearPlaidBankAccountsAndToken, - fetchPlaidLinkToken, - getPlaidBankAccounts, - setBankAccountFormValidationErrors, - showBankAccountErrorModal, -} from '../../libs/actions/BankAccounts'; -import ONYXKEYS from '../../ONYXKEYS'; -import styles from '../../styles/styles'; -import themeColors from '../../styles/themes/default'; -import compose from '../../libs/compose'; -import withLocalize, {withLocalizePropTypes} from '../withLocalize'; -import ExpensiPicker from '../ExpensiPicker'; -import Text from '../Text'; -import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; -import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; -import getBankIcon from '../Icon/BankIcons'; -import Icon from '../Icon'; -import {propTypes, defaultProps} from './plaidBankPropTypes'; -import ROUTES from '../../ROUTES'; -import {removeTrailingForwardSlash} from '../../libs/Url'; +import BaseAddPlaidBankAccount from './BaseAddPlaidBankAccount'; +import {propTypes} from './plaidBankPropTypes'; + +const AddPlaidBankAccount = props => ( + +); +AddPlaidBankAccount.propTypes = propTypes; +AddPlaidBankAccount.displayName = 'AddPlaidBankAccount'; +export default AddPlaidBankAccount; -const plaidBankPropTypes = { - ...withLocalizePropTypes, - ...propTypes, -}; - -class AddPlaidBankAccount extends React.Component { - constructor(props) { - super(props); - - this.selectAccount = this.selectAccount.bind(this); - - this.state = { - selectedIndex: undefined, - institution: {}, - plaidConnectionErrors: {}, - }; - - this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); - this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); - } - - componentDidMount() { - // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken - // Otherwise, clear the existing token and fetch a new one - if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { - return; - } - - clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(this.getRedirectURI()); - } - - /** - * Get list of bank accounts - * - * @returns {Object[]} - */ - getAccounts() { - return lodashGet(this.props.plaidBankAccounts, 'accounts', []); - } - - /** - * @returns {String} - */ - getRedirectURI() { - let redirectURI; - let bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); - if (/staging/.test(process.env.EXPENSIFY_URL_CASH)) { - redirectURI = `${CONST.STAGING_NEW_EXPENSIFY_URL}/${bankAccountRoute}`; - return redirectURI; - } - redirectURI = `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`; - return `http://localhost:8080/${bankAccountRoute}`; - } - - /** - * @returns {Boolean} - */ - validate() { - const errors = {}; - if (_.isUndefined(this.state.selectedIndex)) { - errors.selectedBank = true; - } - setBankAccountFormValidationErrors(errors); - return _.size(errors) === 0; - } - - selectAccount() { - if (!this.validate()) { - showBankAccountErrorModal(); - return; - } - - const account = this.getAccounts()[this.state.selectedIndex]; - const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); - const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; - this.props.onSubmit({ - bankName, - account, - plaidLinkToken: plaidLinkToken, - }); - } - - render() { - const accounts = this.getAccounts(); - const options = _.map(accounts, (account, index) => ({ - value: index, label: `${account.addressName} ${account.accountNumber}`, - })); - const {icon, iconSize} = getBankIcon(this.state.institution.name); - const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.existingPlaidLinkToken); - const plaidLinkTokenToUse = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; - - return ( - <> - {(!plaidLinkToken || this.props.plaidBankAccounts.loading) - && ( - - - - )} - {plaidLinkToken && ( - { - Log.info('[PlaidLink] Success!'); - getPlaidBankAccounts(publicToken, metadata.institution.name); - this.setState({institution: metadata.institution}); - }} - onError={(error) => { - Log.hmmm('[PlaidLink] Error: ', error.message); - // this.setState({plaidConnectionErrors: error}); - }} - - // User prematurely exited the Plaid flow - // eslint-disable-next-line react/jsx-props-no-multi-spaces - onExit={this.props.onExitPlaid} - receivedRedirectUri={this.props.receivedRedirectURI} - /> - )} - {accounts.length > 0 && ( - - {!_.isEmpty(this.props.text) && ( - {this.props.text} - )} - - - {this.state.institution.name} - - - { - this.setState({selectedIndex: Number(index)}); - this.clearError('selectedBank'); - }} - items={options} - placeholder={_.isUndefined(this.state.selectedIndex) ? { - value: '', - label: this.props.translate('bankAccount.chooseAnAccount'), - } : {}} - value={this.state.selectedIndex} - hasError={this.getErrors().selectedBank} - /> - - - )} - - ); - } -} - -AddPlaidBankAccount.propTypes = plaidBankPropTypes; -AddPlaidBankAccount.defaultProps = defaultProps; - -export default compose( - withLocalize, - withOnyx({ - plaidLinkToken: { - key: ONYXKEYS.PLAID_LINK_TOKEN, - - // We always fetch a new token to call Plaid. If we don't then it's possible to open multiple Plaid Link instances. In particular, this can cause issues for Android e.g. - // inability to hand off to React Native once the bank connection is made. This is because an old stashed token will mount the PlaidLink component then it gets set again - // which will mount another PlaidLink component. - initWithStoredValues: false, - }, - plaidBankAccounts: { - key: ONYXKEYS.PLAID_BANK_ACCOUNTS, - }, - reimbursementAccount: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, - }, - }), -)(AddPlaidBankAccount); diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 686839d7bb6d..4206c806c628 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -20,8 +20,6 @@ import exampleCheckImage from './exampleCheckImage'; import Text from '../../components/Text'; import ExpensiTextInput from '../../components/ExpensiTextInput'; import { - addPersonalBankAccount, - addPlaidBusinessBankAccount, setBankAccountFormValidationErrors, setBankAccountSubStep, setupWithdrawalAccount, diff --git a/src/pages/ReimbursementAccount/PlaidOAuthPage.js b/src/pages/ReimbursementAccount/PlaidOAuthPage.js deleted file mode 100644 index 68e174be6ae5..000000000000 --- a/src/pages/ReimbursementAccount/PlaidOAuthPage.js +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; -import lodashGet from 'lodash/get'; -import CONST from '../../CONST'; -import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import ONYXKEYS from '../../ONYXKEYS'; -import compose from '../../libs/compose'; -import ScreenWrapper from '../../components/ScreenWrapper'; -import Navigation from '../../libs/Navigation/Navigation'; -import {addPersonalBankAccount} from '../../libs/actions/BankAccounts'; -import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; -import ReimbursementAccountPage from './ReimbursementAccountPage'; - -const propTypes = { - /** Plaid SDK token to use to initialize the widget */ - plaidLinkToken: PropTypes.string.isRequired, - - ...withLocalizePropTypes, -}; - -const PlaidOAuthPage = (props) => { - let receivedRedirectURI = window.location.href; - const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; - const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); - const bankAccountType = lodashGet(props.route, ['params', 'bankAccountType']); - - // If there's no stateID passed, then return user to start of Plaid flow by setting the redirectURI to null - if (!oauthStateID) { - receivedRedirectURI = null; - } - - return ( - - {bankAccountType === CONST.BANK_ACCOUNT.BUSINESS ? ( - - ) : ( - { - addPersonalBankAccount(account, password, plaidLinkToken); - }} - onExitPlaid={Navigation.dismissModal} - isBusinessBankAccount={false} - existingPlaidLinkToken={props.plaidLinkToken} - receivedRedirectURI={receivedRedirectURI} - /> - )} - - ); -}; - -PlaidOAuthPage.propTypes = propTypes; -PlaidOAuthPage.displayName = 'PlaidOAuthPage'; -export default compose( - withLocalize, - withOnyx({ - plaidLinkToken: { - key: ONYXKEYS.PLAID_LINK_TOKEN, - }, - reimbursementAccount: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, - }, - }), -)(PlaidOAuthPage); From 2622ce5b45efc867c5de6f3bddd936e691310985 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Tue, 23 Nov 2021 20:24:44 -0500 Subject: [PATCH 51/67] Revert platform extensions --- ...dBankAccount.js => AddPlaidBankAccount.js} | 117 ++++++++--- src/components/AddPlaidBankAccount/index.js | 14 -- .../AddPlaidBankAccount/index.native.js | 183 ------------------ .../AddPlaidBankAccount/plaidBankPropTypes.js | 36 ---- .../ReimbursementAccount/BankAccountStep.js | 1 + 5 files changed, 94 insertions(+), 257 deletions(-) rename src/components/{AddPlaidBankAccount/BaseAddPlaidBankAccount.js => AddPlaidBankAccount.js} (70%) delete mode 100644 src/components/AddPlaidBankAccount/index.js delete mode 100644 src/components/AddPlaidBankAccount/index.native.js delete mode 100644 src/components/AddPlaidBankAccount/plaidBankPropTypes.js diff --git a/src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js similarity index 70% rename from src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js rename to src/components/AddPlaidBankAccount.js index e9b0916d95f8..5654158bb1ed 100644 --- a/src/components/AddPlaidBankAccount/BaseAddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -6,37 +6,106 @@ import { } from 'react-native'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import Log from '../../libs/Log'; -import PlaidLink from '../PlaidLink/index'; -import CONST from '../../CONST'; +import Log from '../libs/Log'; +import PlaidLink from './PlaidLink/index'; +import CONST from '../CONST'; import { clearPlaidBankAccountsAndToken, fetchPlaidLinkToken, getPlaidBankAccounts, setBankAccountFormValidationErrors, showBankAccountErrorModal, -} from '../../libs/actions/BankAccounts'; -import ONYXKEYS from '../../ONYXKEYS'; -import styles from '../../styles/styles'; -import themeColors from '../../styles/themes/default'; -import compose from '../../libs/compose'; -import withLocalize, {withLocalizePropTypes} from '../withLocalize'; -import ExpensiPicker from '../ExpensiPicker'; -import Text from '../Text'; -import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; -import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; -import getBankIcon from '../Icon/BankIcons'; -import Icon from '../Icon'; -import {propTypes, defaultProps} from './plaidBankPropTypes'; -import ROUTES from '../../ROUTES'; -import {removeTrailingForwardSlash} from '../../libs/Url'; +} from '../libs/actions/BankAccounts'; +import ONYXKEYS from '../ONYXKEYS'; +import styles from '../styles/styles'; +import themeColors from '../styles/themes/default'; +import compose from '../libs/compose'; +import withLocalize, {withLocalizePropTypes} from './withLocalize'; +import ExpensiPicker from './ExpensiPicker'; +import Text from './Text'; +import * as ReimbursementAccountUtils from '../libs/ReimbursementAccountUtils'; +import ReimbursementAccountForm from '../pages/ReimbursementAccount/ReimbursementAccountForm'; +import getBankIcon from './Icon/BankIcons'; +import Icon from './Icon'; +import ROUTES from '../ROUTES'; +import {removeTrailingForwardSlash} from '../libs/Url'; +import PropTypes from 'prop-types'; + +// const plaidBankPropTypes = { +// ...withLocalizePropTypes, +// ...propTypes, +// }; const plaidBankPropTypes = { ...withLocalizePropTypes, - ...propTypes, + + /** Plaid SDK token to use to initialize the widget */ + plaidLinkToken: PropTypes.string, + + /** Contains list of accounts and loading state while fetching them */ + plaidBankAccounts: PropTypes.shape({ + /** Whether we are fetching the bank accounts from the API */ + loading: PropTypes.bool, + + /** Error object */ + error: PropTypes.shape({ + /** Error message */ + message: PropTypes.string, + + /** Error title */ + title: PropTypes.string, + }), + + /** List of accounts */ + accounts: PropTypes.arrayOf(PropTypes.shape({ + /** Masked account number */ + accountNumber: PropTypes.string, + + /** Name of account */ + addressName: PropTypes.string, + + /** Has this account has already been added? */ + alreadyExists: PropTypes.bool, + + /** Is the account a savings account? */ + isSavings: PropTypes.bool, + + /** Unique identifier for this account in Plaid */ + plaidAccountID: PropTypes.string, + + /** Routing number for the account */ + routingNumber: PropTypes.string, + })), + }), + + /** Fired when the user exits the Plaid flow */ + onExitPlaid: PropTypes.func, + + /** Fired when the user selects an account and submits the form */ + onSubmit: PropTypes.func, + + /** Additional text to display */ + text: PropTypes.string, + + /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ + receivedRedirectURI: PropTypes.string, + + /** During the OAuth flow we need to use the plaidLink token that we initially connected with */ + existingPlaidLinkToken: PropTypes.string, +}; + +const defaultProps = { + plaidLinkToken: '', + plaidBankAccounts: { + loading: false, + }, + onExitPlaid: () => {}, + onSubmit: () => {}, + text: '', + receivedRedirectURI: null, }; -class BaseAddPlaidBankAccount extends React.Component { +class AddPlaidBankAccount extends React.Component { constructor(props) { super(props); @@ -53,6 +122,7 @@ class BaseAddPlaidBankAccount extends React.Component { } componentDidMount() { + console.log("in no directory plaidLink"); // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { @@ -141,7 +211,6 @@ class BaseAddPlaidBankAccount extends React.Component { }} onError={(error) => { Log.hmmm('[PlaidLink] Error: ', error.message); - // this.setState({plaidConnectionErrors: error}); }} // User prematurely exited the Plaid flow @@ -188,8 +257,8 @@ class BaseAddPlaidBankAccount extends React.Component { } } -BaseAddPlaidBankAccount.propTypes = plaidBankPropTypes; -BaseAddPlaidBankAccount.defaultProps = defaultProps; +AddPlaidBankAccount.propTypes = plaidBankPropTypes; +AddPlaidBankAccount.defaultProps = defaultProps; export default compose( withLocalize, @@ -209,4 +278,4 @@ export default compose( key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, }, }), -)(BaseAddPlaidBankAccount); +)(AddPlaidBankAccount); diff --git a/src/components/AddPlaidBankAccount/index.js b/src/components/AddPlaidBankAccount/index.js deleted file mode 100644 index 002c2ab932fb..000000000000 --- a/src/components/AddPlaidBankAccount/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import BaseAddPlaidBankAccount from './BaseAddPlaidBankAccount'; -import {propTypes} from './plaidBankPropTypes'; - -const AddPlaidBankAccount = props => ( - -); -AddPlaidBankAccount.propTypes = propTypes; -AddPlaidBankAccount.displayName = 'AddPlaidBankAccount'; -export default AddPlaidBankAccount; - diff --git a/src/components/AddPlaidBankAccount/index.native.js b/src/components/AddPlaidBankAccount/index.native.js deleted file mode 100644 index fa54bc6d5bc7..000000000000 --- a/src/components/AddPlaidBankAccount/index.native.js +++ /dev/null @@ -1,183 +0,0 @@ -import _ from 'underscore'; -import React from 'react'; -import { - ActivityIndicator, - View, -} from 'react-native'; -import lodashGet from 'lodash/get'; -import {withOnyx} from 'react-native-onyx'; -import Log from '../../libs/Log'; -import PlaidLink from '../PlaidLink/index'; -import { - clearPlaidBankAccountsAndToken, - fetchPlaidLinkToken, - getPlaidBankAccounts, - setBankAccountFormValidationErrors, - showBankAccountErrorModal, -} from '../../libs/actions/BankAccounts'; -import ONYXKEYS from '../../ONYXKEYS'; -import styles from '../../styles/styles'; -import themeColors from '../../styles/themes/default'; -import compose from '../../libs/compose'; -import withLocalize, {withLocalizePropTypes} from '../withLocalize'; -import ExpensiPicker from '../ExpensiPicker'; -import Text from '../Text'; -import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; -import ReimbursementAccountForm from '../../pages/ReimbursementAccount/ReimbursementAccountForm'; -import getBankIcon from '../Icon/BankIcons'; -import Icon from '../Icon'; -import {propTypes, defaultProps} from './plaidBankPropTypes'; - -const plaidBankPropTypes = { - ...withLocalizePropTypes, - ...propTypes, -}; - -class AddPlaidBankAccount extends React.Component { - constructor(props) { - super(props); - - this.selectAccount = this.selectAccount.bind(this); - - this.state = { - selectedIndex: undefined, - institution: {}, - }; - - this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); - this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); - } - - componentDidMount() { - clearPlaidBankAccountsAndToken(); - fetchPlaidLinkToken(); - } - - /** - * Get list of bank accounts - * - * @returns {Object[]} - */ - getAccounts() { - return lodashGet(this.props.plaidBankAccounts, 'accounts', []); - } - - /** - * @returns {Boolean} - */ - validate() { - const errors = {}; - if (_.isUndefined(this.state.selectedIndex)) { - errors.selectedBank = true; - } - setBankAccountFormValidationErrors(errors); - return _.size(errors) === 0; - } - - selectAccount() { - if (!this.validate()) { - showBankAccountErrorModal(); - return; - } - - const account = this.getAccounts()[this.state.selectedIndex]; - const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); - this.props.onSubmit({ - bankName, - account, - plaidLinkToken: this.props.plaidLinkToken, - }); - } - - render() { - const accounts = this.getAccounts(); - const options = _.map(accounts, (account, index) => ({ - value: index, label: `${account.addressName} ${account.accountNumber}`, - })); - const {icon, iconSize} = getBankIcon(this.state.institution.name); - return ( - <> - {(!this.props.plaidLinkToken || this.props.plaidBankAccounts.loading) - && ( - - - - )} - {!_.isEmpty(this.props.plaidLinkToken) && ( - { - Log.info('[PlaidLink] Success!'); - getPlaidBankAccounts(publicToken, metadata.institution.name); - this.setState({institution: metadata.institution}); - }} - onError={(error) => { - Log.hmmm('[PlaidLink] Error: ', error.message); - }} - - // User prematurely exited the Plaid flow - // eslint-disable-next-line react/jsx-props-no-multi-spaces - onExit={this.props.onExitPlaid} - receivedRedirectUri={this.props.receivedRedirectURI} - /> - )} - {accounts.length > 0 && ( - - {!_.isEmpty(this.props.text) && ( - {this.props.text} - )} - - - {this.state.institution.name} - - - { - this.setState({selectedIndex: Number(index)}); - this.clearError('selectedBank'); - }} - items={options} - placeholder={_.isUndefined(this.state.selectedIndex) ? { - value: '', - label: this.props.translate('bankAccount.chooseAnAccount'), - } : {}} - value={this.state.selectedIndex} - hasError={this.getErrors().selectedBank} - /> - - - )} - - ); - } -} - -AddPlaidBankAccount.propTypes = plaidBankPropTypes; -AddPlaidBankAccount.defaultProps = defaultProps; - -export default compose( - withLocalize, - withOnyx({ - plaidLinkToken: { - key: ONYXKEYS.PLAID_LINK_TOKEN, - - // We always fetch a new token to call Plaid. If we don't then it's possible to open multiple Plaid Link instances. In particular, this can cause issues for Android e.g. - // inability to hand off to React Native once the bank connection is made. This is because an old stashed token will mount the PlaidLink component then it gets set again - // which will mount another PlaidLink component. - initWithStoredValues: false, - }, - plaidBankAccounts: { - key: ONYXKEYS.PLAID_BANK_ACCOUNTS, - }, - reimbursementAccount: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, - }, - }), -)(AddPlaidBankAccount); diff --git a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js b/src/components/AddPlaidBankAccount/plaidBankPropTypes.js deleted file mode 100644 index 2685438904fa..000000000000 --- a/src/components/AddPlaidBankAccount/plaidBankPropTypes.js +++ /dev/null @@ -1,36 +0,0 @@ -import PropTypes from 'prop-types'; - -const propTypes = { - /** Fired when the user exits the Plaid flow */ - onExitPlaid: PropTypes.func, - - /** Fired when the user selects an account and submits the form */ - onSubmit: PropTypes.func, - - /** Additional text to display */ - text: PropTypes.string, - - /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ - receivedRedirectURI: PropTypes.string, - - /** If the bank account being added is a business bank account */ - isBusinessBankAccount: PropTypes.bool, - - existingPlaidLinkToken: PropTypes.string, -}; - -const defaultProps = { - plaidLinkToken: '', - plaidBankAccounts: { - loading: false, - }, - onExitPlaid: () => {}, - onSubmit: () => {}, - text: '', - receivedRedirectURI: null, -}; - -export { - propTypes, - defaultProps, -}; diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 4206c806c628..94a896c9e974 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -13,6 +13,7 @@ import Icon from '../../components/Icon'; import colors from '../../styles/colors'; import Navigation from '../../libs/Navigation/Navigation'; import CONST from '../../CONST'; +// import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import CheckboxWithLabel from '../../components/CheckboxWithLabel'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; From add0815a251d460450685947a61f47764203eb74 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 24 Nov 2021 12:07:13 -0500 Subject: [PATCH 52/67] Fix lint warnings --- src/components/AddPlaidBankAccount.js | 14 ++++---------- src/pages/AddPersonalBankAccountPage.js | 4 ++-- src/pages/ReimbursementAccount/BankAccountStep.js | 4 +--- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 5654158bb1ed..4a47a3d2408a 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -6,6 +6,7 @@ import { } from 'react-native'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; import Log from '../libs/Log'; import PlaidLink from './PlaidLink/index'; import CONST from '../CONST'; @@ -29,12 +30,6 @@ import getBankIcon from './Icon/BankIcons'; import Icon from './Icon'; import ROUTES from '../ROUTES'; import {removeTrailingForwardSlash} from '../libs/Url'; -import PropTypes from 'prop-types'; - -// const plaidBankPropTypes = { -// ...withLocalizePropTypes, -// ...propTypes, -// }; const plaidBankPropTypes = { ...withLocalizePropTypes, @@ -103,6 +98,7 @@ const defaultProps = { onSubmit: () => {}, text: '', receivedRedirectURI: null, + existingPlaidLinkToken: '', }; class AddPlaidBankAccount extends React.Component { @@ -114,7 +110,6 @@ class AddPlaidBankAccount extends React.Component { this.state = { selectedIndex: undefined, institution: {}, - plaidConnectionErrors: {}, }; this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); @@ -122,7 +117,6 @@ class AddPlaidBankAccount extends React.Component { } componentDidMount() { - console.log("in no directory plaidLink"); // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { @@ -147,7 +141,7 @@ class AddPlaidBankAccount extends React.Component { */ getRedirectURI() { let redirectURI; - let bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); + const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); if (/staging/.test(process.env.EXPENSIFY_URL_CASH)) { redirectURI = `${CONST.STAGING_NEW_EXPENSIFY_URL}/${bankAccountRoute}`; return redirectURI; @@ -180,7 +174,7 @@ class AddPlaidBankAccount extends React.Component { this.props.onSubmit({ bankName, account, - plaidLinkToken: plaidLinkToken, + plaidLinkToken, }); } diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js index af4204ea9943..0811b94f2dd4 100644 --- a/src/pages/AddPersonalBankAccountPage.js +++ b/src/pages/AddPersonalBankAccountPage.js @@ -13,7 +13,7 @@ const propTypes = { ...withLocalizePropTypes, }; -const AddPersonalBankAccountPage = props => { +const AddPersonalBankAccountPage = (props) => { // If we are coming back from the Plaid OAuth flow const receivedRedirectURI = getOAuthReceivedRedirectURI(); @@ -33,7 +33,7 @@ const AddPersonalBankAccountPage = props => { /> ); -} +}; AddPersonalBankAccountPage.propTypes = propTypes; AddPersonalBankAccountPage.displayName = 'AddPersonalBankAccountPage'; diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 94a896c9e974..0989cb2263d5 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import React from 'react'; import {View, Image} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import MenuItem from '../../components/MenuItem'; import { @@ -13,7 +14,6 @@ import Icon from '../../components/Icon'; import colors from '../../styles/colors'; import Navigation from '../../libs/Navigation/Navigation'; import CONST from '../../CONST'; -// import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import CheckboxWithLabel from '../../components/CheckboxWithLabel'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; @@ -35,8 +35,6 @@ import ReimbursementAccountForm from './ReimbursementAccountForm'; import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; import WorkspaceSection from '../workspace/WorkspaceSection'; import {BankMouseGreen} from '../../components/Icon/Illustrations'; -import lodashGet from "lodash/get"; -import PropTypes from "prop-types"; const propTypes = { /** Bank account currently in setup */ From fcf15e6c4906aba06e59366242b045b1fa4afe15 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 24 Nov 2021 12:42:09 -0500 Subject: [PATCH 53/67] Include early return --- src/libs/actions/BankAccounts.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 6b4cb94eb15e..21e49679decd 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -908,6 +908,10 @@ function validateRoutingNumber(number) { } function getOAuthReceivedRedirectURI() { + if (!window.location) { + return null; + } + let receivedRedirectURI = window.location.href; const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); From 842fb777309f04e458fdf87accf843311aa1d0e3 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Wed, 24 Nov 2021 12:52:27 -0500 Subject: [PATCH 54/67] Variable name cleanup and comments --- src/components/AddPlaidBankAccount.js | 8 ++++---- src/pages/ReimbursementAccount/BankAccountStep.js | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 4a47a3d2408a..41528144b4cb 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -4,11 +4,11 @@ import { ActivityIndicator, View, } from 'react-native'; +import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; import Log from '../libs/Log'; -import PlaidLink from './PlaidLink/index'; +import PlaidLink from './PlaidLink'; import CONST from '../CONST'; import { clearPlaidBankAccountsAndToken, @@ -31,7 +31,7 @@ import Icon from './Icon'; import ROUTES from '../ROUTES'; import {removeTrailingForwardSlash} from '../libs/Url'; -const plaidBankPropTypes = { +const propTypes = { ...withLocalizePropTypes, /** Plaid SDK token to use to initialize the widget */ @@ -251,7 +251,7 @@ class AddPlaidBankAccount extends React.Component { } } -AddPlaidBankAccount.propTypes = plaidBankPropTypes; +AddPlaidBankAccount.propTypes = propTypes; AddPlaidBankAccount.defaultProps = defaultProps; export default compose( diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 0989cb2263d5..fd069fca7aa3 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -41,7 +41,10 @@ const propTypes = { // eslint-disable-next-line react/no-unused-prop-types reimbursementAccount: reimbursementAccountPropTypes.isRequired, + /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ receivedRedirectURI: PropTypes.string, + + /** During the OAuth flow we need to use the plaidLink token that we initially connected with */ existingPlaidLinkToken: PropTypes.string, ...withLocalizePropTypes, @@ -175,8 +178,8 @@ class BankAccountStep extends React.Component { // Disable bank account fields once they've been added in db so they can't be changed const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; - const shouldReinitializedPlaidLink = this.props.existingPlaidLinkToken && this.props.receivedRedirectURI; - const subStep = shouldReinitializedPlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; + const shouldReinitializePlaidLink = this.props.existingPlaidLinkToken && this.props.receivedRedirectURI; + const subStep = shouldReinitializePlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; return ( From dfd9d7a0a4171dc48ec62bd7f46100fd5e94d7bc Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Fri, 26 Nov 2021 13:26:40 -0500 Subject: [PATCH 55/67] Test on web, desktop with complete uri --- src/libs/getPlaidLinkTokenParameters/index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index 56bf55ff188d..c95c0a285b99 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -1 +1,8 @@ -export default () => ({}); +import ROUTES from "../../ROUTES"; +import {removeTrailingForwardSlash} from "../Url"; +import CONST from "../../CONST"; + +export default () => { + const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); + return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; +}; From 7c1be4fc547a23f1265f19fc2d1015e6e7cc64b7 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Fri, 26 Nov 2021 14:45:52 -0500 Subject: [PATCH 56/67] Removed getRedirect logic out of AddPlaid, cleaned up src/libs/getPlaidLinkTokenParameters/index.js --- src/components/AddPlaidBankAccount.js | 17 ----------------- src/libs/getPlaidLinkTokenParameters/index.js | 6 +++--- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index ea4ef7e94f5f..5d2694b23a9c 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -9,7 +9,6 @@ import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import Log from '../libs/Log'; import PlaidLink from './PlaidLink'; -import CONST from '../CONST'; import * as BankAccounts from '../libs/actions/BankAccounts'; import ONYXKEYS from '../ONYXKEYS'; import styles from '../styles/styles'; @@ -22,8 +21,6 @@ import * as ReimbursementAccountUtils from '../libs/ReimbursementAccountUtils'; import ReimbursementAccountForm from '../pages/ReimbursementAccount/ReimbursementAccountForm'; import getBankIcon from './Icon/BankIcons'; import Icon from './Icon'; -import ROUTES from '../ROUTES'; -import {removeTrailingForwardSlash} from '../libs/Url'; const propTypes = { ...withLocalizePropTypes, @@ -130,20 +127,6 @@ class AddPlaidBankAccount extends React.Component { return lodashGet(this.props.plaidBankAccounts, 'accounts', []); } - /** - * @returns {String} - */ - getRedirectURI() { - let redirectURI; - const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); - if (/staging/.test(process.env.EXPENSIFY_URL_CASH)) { - redirectURI = `${CONST.STAGING_NEW_EXPENSIFY_URL}/${bankAccountRoute}`; - return redirectURI; - } - redirectURI = `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`; - return `http://localhost:8080/${bankAccountRoute}`; - } - /** * @returns {Boolean} */ diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index c95c0a285b99..f7d8991e10f3 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -1,6 +1,6 @@ -import ROUTES from "../../ROUTES"; -import {removeTrailingForwardSlash} from "../Url"; -import CONST from "../../CONST"; +import ROUTES from '../../ROUTES'; +import {removeTrailingForwardSlash} from '../Url'; +import CONST from '../../CONST'; export default () => { const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); From 07a0f6eb6557f49f336bce42ba63ffd1769eead1 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Fri, 26 Nov 2021 14:48:00 -0500 Subject: [PATCH 57/67] Clean up BankAccounts.js --- src/libs/actions/BankAccounts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index e2e4eb93c23a..e149a3d1a137 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -46,7 +46,6 @@ Onyx.connect({ /** * Gets the Plaid Link token used to initialize the Plaid SDK - * */ function fetchPlaidLinkToken() { API.Plaid_GetLinkToken() @@ -54,6 +53,7 @@ function fetchPlaidLinkToken() { if (response.jsonCode !== 200) { return; } + Onyx.merge(ONYXKEYS.PLAID_LINK_TOKEN, response.linkToken); }); } From e792b0c8f4a7bda630417b47e0e7476f28fba5bf Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Fri, 26 Nov 2021 14:55:00 -0500 Subject: [PATCH 58/67] Fix Url import --- src/libs/getPlaidLinkTokenParameters/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index f7d8991e10f3..d644ce361c7e 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -1,8 +1,8 @@ import ROUTES from '../../ROUTES'; -import {removeTrailingForwardSlash} from '../Url'; +import * as Url from '../Url'; import CONST from '../../CONST'; export default () => { - const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); + const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : Url.removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; }; From 6842a4722847a88d289803b44e906c4c6428f8a1 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 11:20:14 -0500 Subject: [PATCH 59/67] Reduce condition to only using existing plaidLinkToken --- src/components/AddPlaidBankAccount.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 5d2694b23a9c..ca79f9a2c82c 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -110,7 +110,7 @@ class AddPlaidBankAccount extends React.Component { componentDidMount() { // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one - if (this.props.receivedRedirectURI && (this.props.existingPlaidLinkToken || this.props.plaidLinkToken)) { + if (this.props.receivedRedirectURI && this.props.existingPlaidLinkToken) { return; } From 6e68c70b98e8c064453f464f80d9f68cb85c034f Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 15:57:52 -0500 Subject: [PATCH 60/67] Review comments, refactor existingPlaidToken prop --- src/components/AddPlaidBankAccount.js | 20 +++++----- src/components/PlaidLink/index.js | 2 +- .../PlaidLink/plaidLinkPropTypes.js | 5 +++ src/libs/actions/BankAccounts.js | 17 --------- src/pages/AddPersonalBankAccountPage.js | 38 +++++++++---------- .../ReimbursementAccount/BankAccountStep.js | 8 ++-- .../ReimbursementAccountPage.js | 7 ++-- 7 files changed, 41 insertions(+), 56 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index ca79f9a2c82c..0c9e6edd1a74 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -77,7 +77,7 @@ const propTypes = { receivedRedirectURI: PropTypes.string, /** During the OAuth flow we need to use the plaidLink token that we initially connected with */ - existingPlaidLinkToken: PropTypes.string, + plaidLinkOAuthToken: PropTypes.string, }; const defaultProps = { @@ -89,7 +89,7 @@ const defaultProps = { onSubmit: () => {}, text: '', receivedRedirectURI: null, - existingPlaidLinkToken: '', + plaidLinkOAuthToken: '', }; class AddPlaidBankAccount extends React.Component { @@ -110,7 +110,7 @@ class AddPlaidBankAccount extends React.Component { componentDidMount() { // If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken // Otherwise, clear the existing token and fetch a new one - if (this.props.receivedRedirectURI && this.props.existingPlaidLinkToken) { + if (this.props.receivedRedirectURI && this.props.plaidLinkOAuthToken) { return; } @@ -147,7 +147,7 @@ class AddPlaidBankAccount extends React.Component { const account = this.getAccounts()[this.state.selectedIndex]; const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); - const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; + const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.plaidLinkOAuthToken; this.props.onSubmit({ bankName, account, @@ -161,20 +161,20 @@ class AddPlaidBankAccount extends React.Component { value: index, label: `${account.addressName} ${account.accountNumber}`, })); const {icon, iconSize} = getBankIcon(this.state.institution.name); - const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.existingPlaidLinkToken); - const plaidLinkTokenToUse = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.existingPlaidLinkToken; + const hasPlaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.plaidLinkOAuthToken); + const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.plaidLinkOAuthToken; return ( <> - {(!plaidLinkToken || this.props.plaidBankAccounts.loading) + {(!hasPlaidLinkToken || this.props.plaidBankAccounts.loading) && ( )} - {plaidLinkToken && ( + {hasPlaidLinkToken && ( { Log.info('[PlaidLink] Success!'); BankAccounts.getPlaidBankAccounts(publicToken, metadata.institution.name); @@ -187,7 +187,7 @@ class AddPlaidBankAccount extends React.Component { // User prematurely exited the Plaid flow // eslint-disable-next-line react/jsx-props-no-multi-spaces onExit={this.props.onExitPlaid} - receivedRedirectUri={this.props.receivedRedirectURI} + receivedRedirectURI={this.props.receivedRedirectURI} /> )} {accounts.length > 0 && ( diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js index db1ca8ad124b..8d51adb8a605 100644 --- a/src/components/PlaidLink/index.js +++ b/src/components/PlaidLink/index.js @@ -21,7 +21,7 @@ const PlaidLink = (props) => { // The redirect URI with an OAuth state ID. Needed to re-initialize the PlaidLink after directing the // user to their respective bank platform - receivedRedirectUri: props.receivedRedirectUri, + receivedRedirectUri: props.receivedRedirectURI, }); useEffect(() => { diff --git a/src/components/PlaidLink/plaidLinkPropTypes.js b/src/components/PlaidLink/plaidLinkPropTypes.js index 70af75dd0836..b36dade2a782 100644 --- a/src/components/PlaidLink/plaidLinkPropTypes.js +++ b/src/components/PlaidLink/plaidLinkPropTypes.js @@ -12,12 +12,17 @@ const plaidLinkPropTypes = { // Callback to execute when the user leaves the Plaid widget flow without entering any information onExit: PropTypes.func, + + // The redirect URI with an OAuth state ID. Needed to re-initialize the PlaidLink after directing the + // user to their respective bank platform + receivedRedirectURI: PropTypes.string, }; const plaidLinkDefaultProps = { onSuccess: () => {}, onError: () => {}, onExit: () => {}, + receivedRedirectURI: null, }; export { diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index e149a3d1a137..2c681f1650f3 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -906,22 +906,6 @@ function validateRoutingNumber(number) { return false; } -function getOAuthReceivedRedirectURI() { - if (!window.location) { - return null; - } - - let receivedRedirectURI = window.location.href; - const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; - const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); - - // If there's no stateID passed, then return user to start of Plaid flow by setting the redirectURI to null - if (!oauthStateID) { - receivedRedirectURI = null; - } - return receivedRedirectURI; -} - export { activateWallet, addPersonalBankAccount, @@ -930,7 +914,6 @@ export { fetchOnfidoToken, fetchPlaidLinkToken, fetchUserWallet, - getOAuthReceivedRedirectURI, getPlaidBankAccounts, goToWithdrawalAccountSetupStep, setupWithdrawalAccount, diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js index 4045600af063..961d10c0051c 100644 --- a/src/pages/AddPersonalBankAccountPage.js +++ b/src/pages/AddPersonalBankAccountPage.js @@ -5,32 +5,28 @@ import Navigation from '../libs/Navigation/Navigation'; import * as BankAccounts from '../libs/actions/BankAccounts'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import AddPlaidBankAccount from '../components/AddPlaidBankAccount'; +import getPlaidOAuthReceivedRedirectURI from '../libs/getPlaidOAuthReceivedRedirectURI'; const propTypes = { ...withLocalizePropTypes, }; -const AddPersonalBankAccountPage = (props) => { - // If we are coming back from the Plaid OAuth flow - const receivedRedirectURI = BankAccounts.getOAuthReceivedRedirectURI(); - - return ( - - - { - BankAccounts.addPersonalBankAccount(account, password, plaidLinkToken); - }} - onExitPlaid={Navigation.dismissModal} - receivedRedirectURI={receivedRedirectURI} - existingPlaidLinkToken={props.plaidLinkToken} - /> - - ); -}; +const AddPersonalBankAccountPage = props => ( + + + { + BankAccounts.addPersonalBankAccount(account, password, plaidLinkToken); + }} + onExitPlaid={Navigation.dismissModal} + receivedRedirectURI={getPlaidOAuthReceivedRedirectURI()} + plaidLinkOAuthToken={props.plaidLinkToken} + /> + +); AddPersonalBankAccountPage.propTypes = propTypes; AddPersonalBankAccountPage.displayName = 'AddPersonalBankAccountPage'; diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 9cb6df631200..8bb20ad6a52b 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -36,14 +36,14 @@ const propTypes = { receivedRedirectURI: PropTypes.string, /** During the OAuth flow we need to use the plaidLink token that we initially connected with */ - existingPlaidLinkToken: PropTypes.string, + plaidLinkOAuthToken: PropTypes.string, ...withLocalizePropTypes, }; const defaultProps = { receivedRedirectURI: null, - existingPlaidLinkToken: '', + plaidLinkOAuthToken: '', }; class BankAccountStep extends React.Component { @@ -170,7 +170,7 @@ class BankAccountStep extends React.Component { // Disable bank account fields once they've been added in db so they can't be changed const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; - const shouldReinitializePlaidLink = this.props.existingPlaidLinkToken && this.props.receivedRedirectURI; + const shouldReinitializePlaidLink = this.props.plaidLinkOAuthToken && this.props.receivedRedirectURI; const subStep = shouldReinitializePlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; return ( @@ -253,7 +253,7 @@ class BankAccountStep extends React.Component { onSubmit={this.addPlaidAccount} onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)} receivedRedirectURI={this.props.receivedRedirectURI} - existingPlaidLinkToken={this.props.existingPlaidLinkToken} + plaidLinkOAuthToken={this.props.plaidLinkOAuthToken} /> )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 537d2dccef63..11f4937556f6 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -18,6 +18,7 @@ import compose from '../../libs/compose'; import styles from '../../styles/styles'; import KeyboardAvoidingView from '../../components/KeyboardAvoidingView'; import Text from '../../components/Text'; +import getPlaidOAuthReceivedRedirectURI from '../../libs/getPlaidOAuthReceivedRedirectURI'; // Steps import BankAccountStep from './BankAccountStep'; @@ -76,7 +77,7 @@ class ReimbursementAccountPage extends React.Component { BankAccounts.fetchFreePlanVerifiedBankAccount(stepToOpen !== CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT ? stepToOpen : ''); // If we are coming back from the Plaid OAuth flow - this.receivedRedirectURI = BankAccounts.getOAuthReceivedRedirectURI(); + this.receivedRedirectURI = getPlaidOAuthReceivedRedirectURI(); } componentDidUpdate(prevProps) { @@ -213,8 +214,8 @@ class ReimbursementAccountPage extends React.Component { )} {currentStep === CONST.BANK_ACCOUNT.STEP.COMPANY && ( From 3a8ac3aa2863c110530649d3900616487c27f7da Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 16:19:46 -0500 Subject: [PATCH 61/67] Refactor ROUTE --- src/ROUTES.js | 3 ++- src/libs/Navigation/linkingConfig.js | 2 +- src/libs/Url.js | 14 -------------- src/libs/getPlaidLinkTokenParameters/index.js | 3 +-- .../getPlaidOAuthReceivedRedirectURI/index.js | 17 +++++++++++++++++ .../index.native.js | 1 + 6 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 src/libs/getPlaidOAuthReceivedRedirectURI/index.js create mode 100644 src/libs/getPlaidOAuthReceivedRedirectURI/index.native.js diff --git a/src/ROUTES.js b/src/ROUTES.js index ca7d80b93881..f3b856a469de 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -15,7 +15,8 @@ const IOU_BILL_CURRENCY = `${IOU_BILL}/currency`; const IOU_SEND_CURRENCY = `${IOU_SEND}/currency`; export default { - BANK_ACCOUNT: 'bank-account/:stepToOpen?', + BANK_ACCOUNT: 'bank-account', + BANK_ACCOUNT_WITH_STEP_TO_OPEN: 'bank-account/:stepToOpen?', BANK_ACCOUNT_PERSONAL: 'bank-account/personal', getBankAccountRoute: (stepToOpen = '') => `bank-account/${stepToOpen}`, HOME: '', diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index a5a13343b0c2..ae61f37952c1 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -103,7 +103,7 @@ export default { path: ROUTES.WORKSPACE_INVITE, }, ReimbursementAccount: { - path: ROUTES.BANK_ACCOUNT, + path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN, exact: true, }, }, diff --git a/src/libs/Url.js b/src/libs/Url.js index b48f113c3f32..e166c127a83f 100644 --- a/src/libs/Url.js +++ b/src/libs/Url.js @@ -10,21 +10,7 @@ function addTrailingForwardSlash(url) { return url; } -/** - * Remove / to the end of any URL if present - * @param {String} url - * @returns {String} - */ -function removeTrailingForwardSlash(url) { - if (url.endsWith('/')) { - return url.slice(0, -1); - } - return url; -} - - export { // eslint-disable-next-line import/prefer-default-export addTrailingForwardSlash, - removeTrailingForwardSlash, }; diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index d644ce361c7e..d1cba9962958 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -1,8 +1,7 @@ import ROUTES from '../../ROUTES'; -import * as Url from '../Url'; import CONST from '../../CONST'; export default () => { - const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : Url.removeTrailingForwardSlash(ROUTES.getBankAccountRoute()); + const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : ROUTES.BANK_ACCOUNT; return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; }; diff --git a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js new file mode 100644 index 000000000000..a5bc9849f53b --- /dev/null +++ b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js @@ -0,0 +1,17 @@ +/* + * After a user authenticates their bank in the Plaid OAuth flow, Plaid returns us to the redirectURI we + * gave them along with a stateID param. We hand off the receivedRedirectUri to PlaidLink to finish connecting + * the user's account. + * @returns {String | null} + */ +export default function getPlaidOAuthReceivedRedirectURI() { + let receivedRedirectURI = window.location.href; + const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; + const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); + + // If no stateID passed in then we are either not in OAuth flow or flow is broken + if (!oauthStateID) { + return null; + } + return receivedRedirectURI; +} diff --git a/src/libs/getPlaidOAuthReceivedRedirectURI/index.native.js b/src/libs/getPlaidOAuthReceivedRedirectURI/index.native.js new file mode 100644 index 000000000000..461f67a0a4bc --- /dev/null +++ b/src/libs/getPlaidOAuthReceivedRedirectURI/index.native.js @@ -0,0 +1 @@ +export default () => null; From 36acde924f4f261ae90f025c6038b7bdc74382ec Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 16:28:43 -0500 Subject: [PATCH 62/67] Fix export default --- src/libs/getPlaidOAuthReceivedRedirectURI/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js index a5bc9849f53b..ba7ede389e84 100644 --- a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js +++ b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js @@ -4,7 +4,7 @@ * the user's account. * @returns {String | null} */ -export default function getPlaidOAuthReceivedRedirectURI() { +export default () => { let receivedRedirectURI = window.location.href; const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); From 419d74eaff848e88429c82aacc2b359cbf82800e Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 16:34:14 -0500 Subject: [PATCH 63/67] Lint fix --- src/libs/getPlaidOAuthReceivedRedirectURI/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js index ba7ede389e84..ac928392fa2d 100644 --- a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js +++ b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js @@ -5,8 +5,8 @@ * @returns {String | null} */ export default () => { - let receivedRedirectURI = window.location.href; - const receivedRedirectSearchParams = (new URL(receivedRedirectURI)).searchParams; + const receivedRedirectURI = window.location.href; + const receivedRedirectSearchParams = (new URL(window.location.href)).searchParams; const oauthStateID = receivedRedirectSearchParams.get('oauth_state_id'); // If no stateID passed in then we are either not in OAuth flow or flow is broken @@ -14,4 +14,4 @@ export default () => { return null; } return receivedRedirectURI; -} +}; From 51ec9c7aa0e619363f3731218066b0d2cc4baad5 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 21:27:19 -0500 Subject: [PATCH 64/67] Second round of review comments --- src/libs/getPlaidLinkTokenParameters/index.android.js | 2 +- src/libs/getPlaidLinkTokenParameters/index.js | 3 ++- src/pages/ReimbursementAccount/ReimbursementAccountPage.js | 3 --- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/getPlaidLinkTokenParameters/index.android.js b/src/libs/getPlaidLinkTokenParameters/index.android.js index 111d35dd1c7e..4174e2b8905b 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.android.js +++ b/src/libs/getPlaidLinkTokenParameters/index.android.js @@ -1,3 +1,3 @@ import CONST from '../../CONST'; -export default () => ({android_name: CONST.ANDROID_PACKAGE_NAME}); +export default () => ({android_package: CONST.ANDROID_PACKAGE_NAME}); diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index d1cba9962958..4805e780ad20 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -3,5 +3,6 @@ import CONST from '../../CONST'; export default () => { const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : ROUTES.BANK_ACCOUNT; - return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; + // return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; + return {redirect_uri: `http://localhost:8080/${bankAccountRoute}`}; }; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 11f4937556f6..09ec5b51d6a4 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -75,9 +75,6 @@ class ReimbursementAccountPage extends React.Component { // If we are trying to navigate to `/bank-account/new` and we already have a bank account then don't allow returning to `/new` BankAccounts.fetchFreePlanVerifiedBankAccount(stepToOpen !== CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT ? stepToOpen : ''); - - // If we are coming back from the Plaid OAuth flow - this.receivedRedirectURI = getPlaidOAuthReceivedRedirectURI(); } componentDidUpdate(prevProps) { From 7d27703f8ddbff6a3127159a06643d84cab6236d Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Mon, 29 Nov 2021 21:43:39 -0500 Subject: [PATCH 65/67] Have addPersonalBankAccount subscribe to plaidLinkToken --- src/libs/getPlaidLinkTokenParameters/index.js | 3 +-- src/pages/AddPersonalBankAccountPage.js | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index 4805e780ad20..d1cba9962958 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -3,6 +3,5 @@ import CONST from '../../CONST'; export default () => { const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : ROUTES.BANK_ACCOUNT; - // return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; - return {redirect_uri: `http://localhost:8080/${bankAccountRoute}`}; + return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; }; diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js index 961d10c0051c..0736f19bca85 100644 --- a/src/pages/AddPersonalBankAccountPage.js +++ b/src/pages/AddPersonalBankAccountPage.js @@ -1,4 +1,6 @@ import React from 'react'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import HeaderWithCloseButton from '../components/HeaderWithCloseButton'; import ScreenWrapper from '../components/ScreenWrapper'; import Navigation from '../libs/Navigation/Navigation'; @@ -6,9 +8,18 @@ import * as BankAccounts from '../libs/actions/BankAccounts'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import AddPlaidBankAccount from '../components/AddPlaidBankAccount'; import getPlaidOAuthReceivedRedirectURI from '../libs/getPlaidOAuthReceivedRedirectURI'; +import compose from '../libs/compose'; +import ONYXKEYS from '../ONYXKEYS'; const propTypes = { ...withLocalizePropTypes, + + /** Plaid SDK token to use to initialize the widget */ + plaidLinkToken: PropTypes.string, +}; + +const defaultProps = { + plaidLinkToken: '', }; const AddPersonalBankAccountPage = props => ( @@ -29,5 +40,14 @@ const AddPersonalBankAccountPage = props => ( ); AddPersonalBankAccountPage.propTypes = propTypes; +AddPersonalBankAccountPage.defaultProps = defaultProps; AddPersonalBankAccountPage.displayName = 'AddPersonalBankAccountPage'; -export default withLocalize(AddPersonalBankAccountPage); + +export default compose( + withLocalize, + withOnyx({ + plaidLinkToken: { + key: ONYXKEYS.PLAID_LINK_TOKEN, + }, + }), +)(AddPersonalBankAccountPage); From 34d24224e9cf3c0ffa3a1cf75b3d56aeb06bfb34 Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 2 Dec 2021 14:59:10 -0800 Subject: [PATCH 66/67] Update PlaidLink to check for receivedRedirectURI --- src/components/AddPlaidBankAccount.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 0c9e6edd1a74..618f65e61d01 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -97,6 +97,7 @@ class AddPlaidBankAccount extends React.Component { super(props); this.selectAccount = this.selectAccount.bind(this); + this.getPlaidLinkToken = this.getPlaidLinkToken.bind(this); this.state = { selectedIndex: undefined, @@ -155,6 +156,19 @@ class AddPlaidBankAccount extends React.Component { }); } + /** + * @returns {String} + */ + getPlaidLinkToken() { + if (!_.isEmpty(this.props.plaidLinkToken)) { + return this.props.plaidLinkToken; + } + + if (this.props.receivedRedirectURI) { + return this.props.plaidLinkOAuthToken; + } + } + render() { const accounts = this.getAccounts(); const options = _.map(accounts, (account, index) => ({ @@ -162,7 +176,6 @@ class AddPlaidBankAccount extends React.Component { })); const {icon, iconSize} = getBankIcon(this.state.institution.name); const hasPlaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.plaidLinkOAuthToken); - const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.plaidLinkOAuthToken; return ( <> @@ -174,7 +187,7 @@ class AddPlaidBankAccount extends React.Component { )} {hasPlaidLinkToken && ( { Log.info('[PlaidLink] Success!'); BankAccounts.getPlaidBankAccounts(publicToken, metadata.institution.name); From 5fa07dbe76d59048dcf8648510eb9d8943fd552b Mon Sep 17 00:00:00 2001 From: Nicholas Murray Date: Thu, 2 Dec 2021 16:20:28 -0800 Subject: [PATCH 67/67] Review comments and swap out CONST url for CONFIG url --- src/components/AddPlaidBankAccount.js | 37 +++++++++---------- src/libs/getPlaidLinkTokenParameters/index.js | 4 +- .../getPlaidOAuthReceivedRedirectURI/index.js | 2 +- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 618f65e61d01..0478800b7694 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -128,6 +128,19 @@ class AddPlaidBankAccount extends React.Component { return lodashGet(this.props.plaidBankAccounts, 'accounts', []); } + /** + * @returns {String} + */ + getPlaidLinkToken() { + if (!_.isEmpty(this.props.plaidLinkToken)) { + return this.props.plaidLinkToken; + } + + if (this.props.receivedRedirectURI && this.props.plaidLinkOAuthToken) { + return this.props.plaidLinkOAuthToken; + } + } + /** * @returns {Boolean} */ @@ -148,46 +161,32 @@ class AddPlaidBankAccount extends React.Component { const account = this.getAccounts()[this.state.selectedIndex]; const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName'); - const plaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) ? this.props.plaidLinkToken : this.props.plaidLinkOAuthToken; this.props.onSubmit({ bankName, account, - plaidLinkToken, + plaidLinkToken: this.getPlaidLinkToken(), }); } - /** - * @returns {String} - */ - getPlaidLinkToken() { - if (!_.isEmpty(this.props.plaidLinkToken)) { - return this.props.plaidLinkToken; - } - - if (this.props.receivedRedirectURI) { - return this.props.plaidLinkOAuthToken; - } - } - render() { const accounts = this.getAccounts(); + const token = this.getPlaidLinkToken(); const options = _.map(accounts, (account, index) => ({ value: index, label: `${account.addressName} ${account.accountNumber}`, })); const {icon, iconSize} = getBankIcon(this.state.institution.name); - const hasPlaidLinkToken = !_.isEmpty(this.props.plaidLinkToken) || !_.isEmpty(this.props.plaidLinkOAuthToken); return ( <> - {(!hasPlaidLinkToken || this.props.plaidBankAccounts.loading) + {(!token || this.props.plaidBankAccounts.loading) && ( )} - {hasPlaidLinkToken && ( + {token && ( { Log.info('[PlaidLink] Success!'); BankAccounts.getPlaidBankAccounts(publicToken, metadata.institution.name); diff --git a/src/libs/getPlaidLinkTokenParameters/index.js b/src/libs/getPlaidLinkTokenParameters/index.js index d1cba9962958..17a81fc9a24f 100644 --- a/src/libs/getPlaidLinkTokenParameters/index.js +++ b/src/libs/getPlaidLinkTokenParameters/index.js @@ -1,7 +1,7 @@ import ROUTES from '../../ROUTES'; -import CONST from '../../CONST'; +import CONFIG from '../../CONFIG'; export default () => { const bankAccountRoute = window.location.href.includes('personal') ? ROUTES.BANK_ACCOUNT_PERSONAL : ROUTES.BANK_ACCOUNT; - return {redirect_uri: `${CONST.NEW_EXPENSIFY_URL}/${bankAccountRoute}`}; + return {redirect_uri: `${CONFIG.EXPENSIFY.URL_EXPENSIFY_CASH}/${bankAccountRoute}`}; }; diff --git a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js index ac928392fa2d..c53e78e5ea6f 100644 --- a/src/libs/getPlaidOAuthReceivedRedirectURI/index.js +++ b/src/libs/getPlaidOAuthReceivedRedirectURI/index.js @@ -1,4 +1,4 @@ -/* +/** * After a user authenticates their bank in the Plaid OAuth flow, Plaid returns us to the redirectURI we * gave them along with a stateID param. We hand off the receivedRedirectUri to PlaidLink to finish connecting * the user's account.