diff options
author | fragosti <francesco.agosti93@gmail.com> | 2018-11-13 05:30:47 +0800 |
---|---|---|
committer | fragosti <francesco.agosti93@gmail.com> | 2018-11-13 05:30:47 +0800 |
commit | 79f0324abc6e59d5595770e44d620e6d0cccd6bc (patch) | |
tree | cab441568b4362b90f2626257576ebab60b7ecbb /packages/instant | |
parent | a8a1ea92a614181ebdf6c738139723f0d5c6da69 (diff) | |
download | dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.tar dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.tar.gz dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.tar.bz2 dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.tar.lz dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.tar.xz dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.tar.zst dexon-0x-contracts-79f0324abc6e59d5595770e44d620e6d0cccd6bc.zip |
feat: integrate wallet flow with heartbeat and other branches
Diffstat (limited to 'packages/instant')
6 files changed, 81 insertions, 48 deletions
diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx index cb02c8d8c..d93e74c9f 100644 --- a/packages/instant/src/components/buy_order_progress.tsx +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { ProgressBar, TimedProgressBar } from '../components/timed_progress_bar'; +import { TimedProgressBar } from '../components/timed_progress_bar'; import { TimeCounter } from '../components/time_counter'; import { Container } from '../components/ui/container'; diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index f596c5ad6..25c879519 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption } from '../style/theme'; -import { Account, AccountState, Network, StandardSlidingPanelContent } from '../types'; +import { Account, AccountState, Network } from '../types'; import { MetaMaskLogo } from './meta_mask_logo'; import { PaymentMethodDropdown } from './payment_method_dropdown'; @@ -15,7 +15,8 @@ import { Text } from './ui/text'; export interface PaymentMethodProps { account: Account; network: Network; - openStandardSlidingPanel: (content: StandardSlidingPanelContent) => void; + onInstallWalletClick: () => void; + onUnlockWalletClick: () => void; } export class PaymentMethod extends React.Component<PaymentMethodProps> { @@ -80,7 +81,7 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> { case AccountState.Locked: return ( <WalletPrompt - onClick={this._openInstallWalletPanel} + onClick={this.props.onUnlockWalletClick} image={<Icon width={13} icon="lock" color={ColorOption.black} />} > Please Unlock MetaMask @@ -89,7 +90,7 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> { case AccountState.None: return ( <WalletPrompt - onClick={this._openInstallWalletPanel} + onClick={this.props.onInstallWalletClick} image={<MetaMaskLogo width={19} height={18} />} > Install MetaMask @@ -107,9 +108,6 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> { return null; } }; - private readonly _openInstallWalletPanel = () => { - this.props.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet); - }; } interface WalletPromptProps { diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 411f118cc..863bc99b7 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -91,12 +91,13 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider } public componentDidMount(): void { const state = this._store.getState(); + const dispatch = this._store.dispatch; // tslint:disable-next-line:no-floating-promises - asyncData.fetchEthPriceAndDispatchToStore(this._store); + asyncData.fetchEthPriceAndDispatchToStore(dispatch); // fetch available assets if none are specified if (_.isUndefined(state.availableAssets)) { // tslint:disable-next-line:no-floating-promises - asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store); + asyncData.fetchAvailableAssetDatasAndDispatchToStore(state, dispatch); } if (state.providerState.account.state !== AccountState.None) { this._accountUpdateHeartbeat = generateAccountHeartbeater({ @@ -112,7 +113,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider }); this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS); // tslint:disable-next-line:no-floating-promises - asyncData.fetchCurrentBuyQuoteAndDispatchToStore({ store: this._store, shouldSetPending: true }); + asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, true); // warm up the gas price estimator cache just in case we can't // grab the gas price estimate when submitting the transaction // tslint:disable-next-line:no-floating-promises diff --git a/packages/instant/src/containers/connected_account_payment_method.ts b/packages/instant/src/containers/connected_account_payment_method.ts index ee57d1829..c20af67cc 100644 --- a/packages/instant/src/containers/connected_account_payment_method.ts +++ b/packages/instant/src/containers/connected_account_payment_method.ts @@ -4,34 +4,61 @@ import { Dispatch } from 'redux'; import { PaymentMethod } from '../components/payment_method'; import { Action, actions } from '../redux/actions'; +import { asyncData } from '../redux/async_data'; import { State } from '../redux/reducer'; -import { Account, Network, StandardSlidingPanelContent } from '../types'; +import { Account, Network, ProviderState, StandardSlidingPanelContent } from '../types'; export interface ConnectedAccountPaymentMethodProps {} interface ConnectedState { - account: Account; network: Network; + providerState: ProviderState; } interface ConnectedDispatch { - openStandardSlidingPanel: (content: StandardSlidingPanelContent) => void; + onInstallWalletClick: () => void; + unlockWalletAndDispatchToStore: (providerState: ProviderState) => void; +} + +interface ConnectedProps { + onInstallWalletClick: () => void; + onUnlockWalletClick: () => void; + account: Account; + network: Network; } +type FinalProps = ConnectedProps & ConnectedAccountPaymentMethodProps; + const mapStateToProps = (state: State, _ownProps: ConnectedAccountPaymentMethodProps): ConnectedState => ({ - account: state.providerState.account, network: state.network, + providerState: state.providerState, }); const mapDispatchToProps = ( dispatch: Dispatch<Action>, ownProps: ConnectedAccountPaymentMethodProps, ): ConnectedDispatch => ({ - openStandardSlidingPanel: (content: StandardSlidingPanelContent) => - dispatch(actions.openStandardSlidingPanel(content)), + onInstallWalletClick: () => dispatch(actions.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet)), + unlockWalletAndDispatchToStore: async (providerState: ProviderState) => + asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true), +}); + +const mergeProps = ( + connectedState: ConnectedState, + connectedDispatch: ConnectedDispatch, + ownProps: ConnectedAccountPaymentMethodProps, +): FinalProps => ({ + ...ownProps, + network: connectedState.network, + account: connectedState.providerState.account, + onInstallWalletClick: connectedDispatch.onInstallWalletClick, + onUnlockWalletClick: () => { + connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState); + }, }); export const ConnectedAccountPaymentMethod: React.ComponentClass<ConnectedAccountPaymentMethodProps> = connect( mapStateToProps, mapDispatchToProps, + mergeProps, )(PaymentMethod); diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index b920ac914..8999ef097 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -1,71 +1,75 @@ import { AssetProxyId } from '@0x/types'; import * as _ from 'lodash'; +import { Dispatch } from 'redux'; import { BIG_NUMBER_ZERO } from '../constants'; -import { AccountState, ERC20Asset, OrderProcessState } from '../types'; +import { AccountState, ERC20Asset, OrderProcessState, ProviderState } from '../types'; import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; import { coinbaseApi } from '../util/coinbase_api'; import { errorFlasher } from '../util/error_flasher'; import { actions } from './actions'; -import { Store } from './store'; +import { State } from './reducer'; export const asyncData = { - fetchEthPriceAndDispatchToStore: async (store: Store) => { + fetchEthPriceAndDispatchToStore: async (dispatch: Dispatch) => { try { const ethUsdPrice = await coinbaseApi.getEthUsdPrice(); - store.dispatch(actions.updateEthUsdPrice(ethUsdPrice)); + dispatch(actions.updateEthUsdPrice(ethUsdPrice)); } catch (e) { const errorMessage = 'Error fetching ETH/USD price'; - errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage); - store.dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); } }, - fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => { - const { providerState, assetMetaDataMap, network } = store.getState(); + fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => { + const { providerState, assetMetaDataMap, network } = state; const assetBuyer = providerState.assetBuyer; try { const assetDatas = await assetBuyer.getAvailableAssetDatasAsync(); const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); - store.dispatch(actions.setAvailableAssets(assets)); + dispatch(actions.setAvailableAssets(assets)); } catch (e) { const errorMessage = 'Could not find any assets'; - errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage); + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); // On error, just specify that none are available - store.dispatch(actions.setAvailableAssets([])); + dispatch(actions.setAvailableAssets([])); } }, - fetchAccountInfoAndDispatchToStore: async (options: { store: Store; shouldSetToLoading: boolean }) => { - const { store, shouldSetToLoading } = options; - const { providerState } = store.getState(); + fetchAccountInfoAndDispatchToStore: async ( + providerState: ProviderState, + dispatch: Dispatch, + shouldAttemptUnlock: boolean = false, + shouldSetToLoading: boolean = false, + ) => { const web3Wrapper = providerState.web3Wrapper; const provider = providerState.provider; if (shouldSetToLoading && providerState.account.state !== AccountState.Loading) { - store.dispatch(actions.setAccountStateLoading()); + dispatch(actions.setAccountStateLoading()); } let availableAddresses: string[]; try { // TODO(bmillman): Add support at the web3Wrapper level for calling `eth_requestAccounts` instead of calling enable here const isPrivacyModeEnabled = !_.isUndefined((provider as any).enable); - availableAddresses = isPrivacyModeEnabled - ? await (provider as any).enable() - : await web3Wrapper.getAvailableAddressesAsync(); + availableAddresses = + isPrivacyModeEnabled && shouldAttemptUnlock + ? await (provider as any).enable() + : await web3Wrapper.getAvailableAddressesAsync(); } catch (e) { - store.dispatch(actions.setAccountStateLocked()); + dispatch(actions.setAccountStateLocked()); return; } if (!_.isEmpty(availableAddresses)) { const activeAddress = availableAddresses[0]; - store.dispatch(actions.setAccountStateReady(activeAddress)); + dispatch(actions.setAccountStateReady(activeAddress)); // tslint:disable-next-line:no-floating-promises - asyncData.fetchAccountBalanceAndDispatchToStore(store); + asyncData.fetchAccountBalanceAndDispatchToStore(providerState, dispatch); } else { - store.dispatch(actions.setAccountStateLocked()); + dispatch(actions.setAccountStateLocked()); } }, - fetchAccountBalanceAndDispatchToStore: async (store: Store) => { - const { providerState } = store.getState(); + fetchAccountBalanceAndDispatchToStore: async (providerState: ProviderState, dispatch: Dispatch) => { const web3Wrapper = providerState.web3Wrapper; const account = providerState.account; if (account.state !== AccountState.Ready) { @@ -74,15 +78,18 @@ export const asyncData = { try { const address = account.address; const ethBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(address); - store.dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei })); + dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei })); } catch (e) { // leave balance as is return; } }, - fetchCurrentBuyQuoteAndDispatchToStore: async (options: { store: Store; shouldSetPending: boolean }) => { - const { store, shouldSetPending } = options; - const { buyOrderState, providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = store.getState(); + fetchCurrentBuyQuoteAndDispatchToStore: async ( + state: State, + dispatch: Dispatch, + shouldSetPending: boolean = false, + ) => { + const { buyOrderState, providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = state; const assetBuyer = providerState.assetBuyer; if ( !_.isUndefined(selectedAssetAmount) && @@ -92,7 +99,7 @@ export const asyncData = { ) { await buyQuoteUpdater.updateBuyQuoteAsync( assetBuyer, - store.dispatch, + dispatch, selectedAsset as ERC20Asset, selectedAssetAmount, shouldSetPending, diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts index 96a8ac4e6..06fcdb8bb 100644 --- a/packages/instant/src/util/heartbeater_factory.ts +++ b/packages/instant/src/util/heartbeater_factory.ts @@ -10,13 +10,13 @@ export interface HeartbeatFactoryOptions { export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => { const { store, shouldPerformImmediatelyOnStart } = options; return new Heartbeater(async () => { - await asyncData.fetchAccountInfoAndDispatchToStore({ store, shouldSetToLoading: false }); + await asyncData.fetchAccountInfoAndDispatchToStore(store.getState().providerState, store.dispatch, false); }, shouldPerformImmediatelyOnStart); }; export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => { const { store, shouldPerformImmediatelyOnStart } = options; return new Heartbeater(async () => { - await asyncData.fetchCurrentBuyQuoteAndDispatchToStore({ store, shouldSetPending: false }); + await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, false); }, shouldPerformImmediatelyOnStart); }; |