diff options
author | Brandon Millman <brandon.millman@gmail.com> | 2018-10-29 09:36:13 +0800 |
---|---|---|
committer | Brandon Millman <brandon.millman@gmail.com> | 2018-10-29 10:07:53 +0800 |
commit | 8d1689073b702d973075d30b2bb36369487fad1c (patch) | |
tree | cb0380d4782b0715f0d24e7a9c5f88b49a60fa50 /packages/instant | |
parent | 4f5ab1a72d33dc6a7516d7b1d51f1aa15752a6b8 (diff) | |
parent | ae6202ed3d777605a3fd02cd29141a3ba40f4b34 (diff) | |
download | dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.gz dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.bz2 dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.lz dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.xz dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.tar.zst dexon-sol-tools-8d1689073b702d973075d30b2bb36369487fad1c.zip |
Merge branch 'development' into feature/instant/fixed-orders-in-render-method
* development:
fix(instant): refactor some props to use isDisabled instead of disabled
linting imports
feat(instant): Disable input when processing
Add back debounce
Make doesBuyQuoteMatchState in reducer less strict
fix(instant): prevent outdated quote requests from overriding the correct quote
selected asset buy order state button -> selected asset buy order state buttons
buy order state button -> buy order state buttons
feat(order_utils.py): ERC721 asset data codec (#1186)
Add note about tslint false positive
tsx -> ts
Get BuyOrderState one big connected component, and let user view failure
Show View Transaction button on failure, and allow setting of width for Try Again button and View Txn button
Added string to constants
chore: Update contract-wrappers CHANGELOG.json
fix(contract-wrappers): Fix tslint errors that were lingering due to misconfiguration
chore: Add --format stylish to tslint
Diffstat (limited to 'packages/instant')
17 files changed, 168 insertions, 153 deletions
diff --git a/packages/instant/package.json b/packages/instant/package.json index 977126867..81d2e4c7b 100644 --- a/packages/instant/package.json +++ b/packages/instant/package.json @@ -16,7 +16,7 @@ "build:ci": "yarn build", "watch_without_deps": "tsc -w", "dev": "webpack-dev-server --mode development", - "lint": "tslint --project .", + "lint": "tslint --format stylish --project .", "test": "jest", "test:coverage": "jest --coverage", "rebuild_and_test": "run-s clean build test", diff --git a/packages/instant/src/components/buy_order_state_button.tsx b/packages/instant/src/components/buy_order_state_button.tsx deleted file mode 100644 index 44115e5a1..000000000 --- a/packages/instant/src/components/buy_order_state_button.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import * as React from 'react'; - -import { PlacingOrderButton } from '../components/placing_order_button'; -import { SelectedAssetBuyButton } from '../containers/selected_asset_buy_button'; -import { SelectedAssetRetryButton } from '../containers/selected_asset_retry_button'; -import { SelectedAssetViewTransactionButton } from '../containers/selected_asset_view_transaction_button'; -import { OrderProcessState } from '../types'; - -export interface BuyOrderStateButtonProps { - buyOrderProcessingState: OrderProcessState; -} - -export const BuyOrderStateButton: React.StatelessComponent<BuyOrderStateButtonProps> = props => { - if (props.buyOrderProcessingState === OrderProcessState.FAILURE) { - return <SelectedAssetRetryButton />; - } else if ( - props.buyOrderProcessingState === OrderProcessState.SUCCESS || - props.buyOrderProcessingState === OrderProcessState.PROCESSING - ) { - return <SelectedAssetViewTransactionButton />; - } else if (props.buyOrderProcessingState === OrderProcessState.AWAITING_SIGNATURE) { - return <PlacingOrderButton />; - } - - return <SelectedAssetBuyButton />; -}; diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx new file mode 100644 index 000000000..758eabcb7 --- /dev/null +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -0,0 +1,63 @@ +import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; +import * as React from 'react'; + +import { BuyButton } from '../components/buy_button'; +import { SecondaryButton } from '../components/secondary_button'; +import { Flex } from '../components/ui/flex'; + +import { PlacingOrderButton } from '../components/placing_order_button'; +import { ColorOption } from '../style/theme'; +import { OrderProcessState } from '../types'; + +import { Button } from './ui/button'; +import { Text } from './ui/text'; + +export interface BuyOrderStateButtonProps { + buyQuote?: BuyQuote; + buyOrderProcessingState: OrderProcessState; + assetBuyer?: AssetBuyer; + onViewTransaction: () => void; + onAwaitingSignature: (buyQuote: BuyQuote) => void; + onSignatureDenied: (buyQuote: BuyQuote) => void; + onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void; + onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; + onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; + onRetry: () => void; +} + +// TODO: rename to buttons +export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonProps> = props => { + if (props.buyOrderProcessingState === OrderProcessState.FAILURE) { + return ( + <Flex justify="space-between"> + <Button width="48%" onClick={props.onRetry}> + <Text fontColor={ColorOption.white} fontWeight={600} fontSize="16px"> + Back + </Text> + </Button> + <SecondaryButton width="48%" onClick={props.onViewTransaction}> + Details + </SecondaryButton> + </Flex> + ); + } else if ( + props.buyOrderProcessingState === OrderProcessState.SUCCESS || + props.buyOrderProcessingState === OrderProcessState.PROCESSING + ) { + return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>; + } else if (props.buyOrderProcessingState === OrderProcessState.AWAITING_SIGNATURE) { + return <PlacingOrderButton />; + } + + return ( + <BuyButton + buyQuote={props.buyQuote} + assetBuyer={props.assetBuyer} + onAwaitingSignature={props.onAwaitingSignature} + onSignatureDenied={props.onSignatureDenied} + onBuyProcessing={props.onBuyProcessing} + onBuySuccess={props.onBuySuccess} + onBuyFailure={props.onBuyFailure} + /> + ); +}; diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 583fad28b..5abb34c2f 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -17,6 +17,7 @@ export interface ERC20AssetAmountInputProps { onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; startingFontSizePx: number; fontColor?: ColorOption; + isDisabled: boolean; } export interface ERC20AssetAmountInputState { @@ -26,6 +27,7 @@ export interface ERC20AssetAmountInputState { export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> { public static defaultProps = { onChange: util.boundNoop, + isDisabled: false, }; constructor(props: ERC20AssetAmountInputProps) { super(props); @@ -35,9 +37,10 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput } public render(): React.ReactNode { const { asset, onChange, ...rest } = this.props; + const amountBorderBottom = this.props.isDisabled ? '' : `1px solid ${transparentWhite}`; return ( <Container whiteSpace="nowrap"> - <Container borderBottom={`1px solid ${transparentWhite}`} display="inline-block"> + <Container borderBottom={amountBorderBottom} display="inline-block"> <ScalingAmountInput {...rest} textLengthThreshold={this._textLengthThresholdForAsset(asset)} diff --git a/packages/instant/src/components/retry_button.tsx b/packages/instant/src/components/retry_button.tsx deleted file mode 100644 index 0d6188e6a..000000000 --- a/packages/instant/src/components/retry_button.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import * as React from 'react'; - -import { SecondaryButton } from './secondary_button'; - -export interface RetryButtonProps { - onClick: () => void; -} - -export const RetryButton: React.StatelessComponent<RetryButtonProps> = props => { - return <SecondaryButton onClick={props.onClick}>Try Again</SecondaryButton>; -}; diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 655ae2b74..cfbf3b7cc 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -8,6 +8,7 @@ import { util } from '../util/util'; import { ScalingInput } from './scaling_input'; export interface ScalingAmountInputProps { + isDisabled: boolean; maxFontSizePx: number; textLengthThreshold: number; fontColor?: ColorOption; @@ -20,6 +21,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps> public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, + isDisabled: false, }; public render(): React.ReactNode { const { textLengthThreshold, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props; @@ -33,6 +35,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps> value={!_.isUndefined(value) ? value.toDisplayString() : ''} placeholder="0.00" emptyInputWidthCh={3.5} + isDisabled={this.props.isDisabled} /> ); } diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 34cb0b5fd..11748b729 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -27,6 +27,7 @@ export interface ScalingInputProps { placeholder?: string; maxLength?: number; scalingSettings: ScalingSettings; + isDisabled: boolean; } export interface ScalingInputState { @@ -49,6 +50,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu onFontSizeChange: util.boundNoop, maxLength: 7, scalingSettings: defaultScalingSettings, + isDisabled: false, }; public state: ScalingInputState = { inputWidthPxAtPhaseChange: undefined, @@ -121,7 +123,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu } } public render(): React.ReactNode { - const { fontColor, onChange, placeholder, value, maxLength } = this.props; + const { isDisabled, fontColor, onChange, placeholder, value, maxLength } = this.props; const phase = ScalingInput.getPhaseFromProps(this.props); return ( <Input @@ -133,6 +135,7 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu fontSize={`${this._calculateFontSize(phase)}px`} width={this._calculateWidth(phase)} maxLength={maxLength} + disabled={isDisabled} /> ); } diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx index 3c139a233..583058b5b 100644 --- a/packages/instant/src/components/secondary_button.tsx +++ b/packages/instant/src/components/secondary_button.tsx @@ -14,7 +14,7 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p <Button backgroundColor={ColorOption.white} borderColor={ColorOption.lightGrey} - width="100%" + width={props.width} onClick={props.onClick} {...buttonProps} > @@ -24,3 +24,6 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p </Button> ); }; +SecondaryButton.defaultProps = { + width: '100%', +}; diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx index 1fcb2591c..5274d835b 100644 --- a/packages/instant/src/components/ui/button.tsx +++ b/packages/instant/src/components/ui/button.tsx @@ -52,6 +52,7 @@ export const Button = styled(PlainButton)` Button.defaultProps = { backgroundColor: ColorOption.primaryColor, + borderColor: ColorOption.primaryColor, width: 'auto', isDisabled: false, padding: '1em 2.2em', diff --git a/packages/instant/src/components/view_transaction_button.tsx b/packages/instant/src/components/view_transaction_button.tsx deleted file mode 100644 index 7aa44e657..000000000 --- a/packages/instant/src/components/view_transaction_button.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import * as React from 'react'; - -import { SecondaryButton } from './secondary_button'; - -export interface ViewTransactionButtonProps { - onClick: () => void; -} - -export const ViewTransactionButton: React.StatelessComponent<ViewTransactionButtonProps> = props => { - return <SecondaryButton onClick={props.onClick}>View Transaction</SecondaryButton>; -}; diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 1d17ed12a..ff19351ff 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details'; import { LatestError } from '../containers/latest_error'; -import { SelectedAssetBuyOrderStateButton } from '../containers/selected_asset_buy_order_state_button'; +import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; import { ColorOption } from '../style/theme'; @@ -27,7 +27,7 @@ export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantConta <SelectedAssetInstantHeading /> <LatestBuyQuoteOrderDetails /> <Container padding="20px" width="100%"> - <SelectedAssetBuyOrderStateButton /> + <SelectedAssetBuyOrderStateButtons /> </Container> </Flex> </Container> diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_button.tsx b/packages/instant/src/containers/selected_asset_buy_order_state_button.tsx deleted file mode 100644 index 7faa79912..000000000 --- a/packages/instant/src/containers/selected_asset_buy_order_state_button.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; - -import { State } from '../redux/reducer'; -import { OrderProcessState } from '../types'; - -import { BuyOrderStateButton } from '../components/buy_order_state_button'; - -interface ConnectedState { - buyOrderProcessingState: OrderProcessState; -} -export interface SelectedAssetButtonProps {} -const mapStateToProps = (state: State, _ownProps: SelectedAssetButtonProps): ConnectedState => ({ - buyOrderProcessingState: state.buyOrderState.processState, -}); - -export const SelectedAssetBuyOrderStateButton: React.ComponentClass<SelectedAssetButtonProps> = connect( - mapStateToProps, -)(BuyOrderStateButton); diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts index 377831b43..10734df96 100644 --- a/packages/instant/src/containers/selected_asset_buy_button.ts +++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts @@ -8,14 +8,15 @@ import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; import { OrderProcessState, OrderState } from '../types'; import { errorFlasher } from '../util/error_flasher'; +import { etherscanUtil } from '../util/etherscan'; -import { BuyButton } from '../components/buy_button'; - -export interface SelectedAssetBuyButtonProps {} +import { BuyOrderStateButtons } from '../components/buy_order_state_buttons'; interface ConnectedState { - assetBuyer?: AssetBuyer; buyQuote?: BuyQuote; + buyOrderProcessingState: OrderProcessState; + assetBuyer?: AssetBuyer; + onViewTransaction: () => void; } interface ConnectedDispatch { @@ -24,14 +25,36 @@ interface ConnectedDispatch { onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void; onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void; onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void; + onRetry: () => void; } - -const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps): ConnectedState => ({ +export interface SelectedAssetBuyOrderStateButtons {} +const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({ + buyOrderProcessingState: state.buyOrderState.processState, assetBuyer: state.assetBuyer, buyQuote: state.latestBuyQuote, + onViewTransaction: () => { + if ( + state.assetBuyer && + (state.buyOrderState.processState === OrderProcessState.PROCESSING || + state.buyOrderState.processState === OrderProcessState.SUCCESS || + state.buyOrderState.processState === OrderProcessState.FAILURE) + ) { + const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists( + state.buyOrderState.txHash, + state.assetBuyer.networkId, + ); + if (etherscanUrl) { + window.open(etherscanUrl, '_blank'); + return; + } + } + }, }); -const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({ +const mapDispatchToProps = ( + dispatch: Dispatch<Action>, + ownProps: SelectedAssetBuyOrderStateButtons, +): ConnectedDispatch => ({ onAwaitingSignature: (buyQuote: BuyQuote) => { const newOrderState: OrderState = { processState: OrderProcessState.AWAITING_SIGNATURE }; dispatch(actions.updateBuyOrderState(newOrderState)); @@ -49,9 +72,12 @@ const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetB const errorMessage = 'You denied this transaction'; errorFlasher.flashNewErrorMessage(dispatch, errorMessage); }, + onRetry: () => { + dispatch(actions.resetAmount()); + }, }); -export const SelectedAssetBuyButton: React.ComponentClass<SelectedAssetBuyButtonProps> = connect( +export const SelectedAssetBuyOrderStateButtons: React.ComponentClass<SelectedAssetBuyOrderStateButtons> = connect( mapStateToProps, mapDispatchToProps, -)(BuyButton); +)(BuyOrderStateButtons); diff --git a/packages/instant/src/containers/selected_asset_retry_button.tsx b/packages/instant/src/containers/selected_asset_retry_button.tsx deleted file mode 100644 index b2b140be6..000000000 --- a/packages/instant/src/containers/selected_asset_retry_button.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; - -import { Action, actions } from '../redux/actions'; - -import { RetryButton } from '../components/retry_button'; - -export interface SelectedAssetRetryButtonProps {} - -interface ConnectedDispatch { - onClick: () => void; -} - -const mapDispatchToProps = ( - dispatch: Dispatch<Action>, - _ownProps: SelectedAssetRetryButtonProps, -): ConnectedDispatch => ({ - onClick: () => dispatch(actions.resetAmount()), -}); - -export const SelectedAssetRetryButton: React.ComponentClass<SelectedAssetRetryButtonProps> = connect( - undefined, - mapDispatchToProps, -)(RetryButton); diff --git a/packages/instant/src/containers/selected_asset_view_transaction_button.tsx b/packages/instant/src/containers/selected_asset_view_transaction_button.tsx deleted file mode 100644 index 064b877be..000000000 --- a/packages/instant/src/containers/selected_asset_view_transaction_button.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; - -import { State } from '../redux/reducer'; - -import { ViewTransactionButton } from '../components/view_transaction_button'; -import { OrderProcessState } from '../types'; -import { etherscanUtil } from '../util/etherscan'; - -export interface SelectedAssetViewTransactionButtonProps {} - -interface ConnectedState { - onClick: () => void; -} - -const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({ - onClick: () => { - if ( - state.assetBuyer && - (state.buyOrderState.processState === OrderProcessState.PROCESSING || - state.buyOrderState.processState === OrderProcessState.SUCCESS) - ) { - const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists( - state.buyOrderState.txHash, - state.assetBuyer.networkId, - ); - if (etherscanUrl) { - window.open(etherscanUrl, '_blank'); - return; - } - } - }, -}); - -export const SelectedAssetViewTransactionButton: React.ComponentClass< - SelectedAssetViewTransactionButtonProps -> = connect(mapStateToProps)(ViewTransactionButton); diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts index 8fcb430a7..1e93a6deb 100644 --- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -26,6 +26,7 @@ interface ConnectedState { assetBuyer?: AssetBuyer; value?: BigNumberInput; asset?: ERC20Asset; + isDisabled: boolean; } interface ConnectedDispatch { @@ -36,21 +37,29 @@ interface ConnectedProps { value?: BigNumberInput; asset?: ERC20Asset; onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; + isDisabled: boolean; } type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps; const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => { + const processState = state.buyOrderState.processState; + const isEnabled = processState === OrderProcessState.NONE || processState === OrderProcessState.FAILURE; + const isDisabled = !isEnabled; + const selectedAsset = state.selectedAsset; if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) { return { value: state.selectedAssetAmount, + isDisabled, }; } + return { assetBuyer: state.assetBuyer, value: state.selectedAssetAmount, asset: selectedAsset as ERC20Asset, + isDisabled, }; }; @@ -128,6 +137,7 @@ const mergeProps = ( onChange: (value, asset) => { connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); }, + isDisabled: connectedState.isDisabled, }; }; diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 3884eeea9..dd9403052 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -1,6 +1,7 @@ import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; -import { ObjectMap } from '@0x/types'; +import { AssetProxyId, ObjectMap } from '@0x/types'; import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import { assetMetaDataMap } from '../data/asset_meta_data_map'; @@ -57,11 +58,19 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => selectedAssetAmount: action.data, }; case ActionTypes.UPDATE_LATEST_BUY_QUOTE: - return { - ...state, - latestBuyQuote: action.data, - quoteRequestState: AsyncProcessState.SUCCESS, - }; + const newBuyQuoteIfExists = action.data; + const shouldUpdate = + _.isUndefined(newBuyQuoteIfExists) || doesBuyQuoteMatchState(newBuyQuoteIfExists, state); + if (shouldUpdate) { + return { + ...state, + latestBuyQuote: newBuyQuoteIfExists, + quoteRequestState: AsyncProcessState.SUCCESS, + }; + } else { + return state; + } + case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING: return { ...state, @@ -122,3 +131,29 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => return state; } }; + +const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => { + const selectedAssetIfExists = state.selectedAsset; + const selectedAssetAmountIfExists = state.selectedAssetAmount; + // if no selectedAsset or selectedAssetAmount exists on the current state, return false + if (_.isUndefined(selectedAssetIfExists) || _.isUndefined(selectedAssetAmountIfExists)) { + return false; + } + // if buyQuote's assetData does not match that of the current selected asset, return false + if (selectedAssetIfExists.assetData !== buyQuote.assetData) { + return false; + } + // if ERC20 and buyQuote's assetBuyAmount does not match selectedAssetAmount, return false + // if ERC721, return true + const selectedAssetMetaData = selectedAssetIfExists.metaData; + if (selectedAssetMetaData.assetProxyId === AssetProxyId.ERC20) { + const selectedAssetAmountBaseUnits = Web3Wrapper.toBaseUnitAmount( + selectedAssetAmountIfExists, + selectedAssetMetaData.decimals, + ); + const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(buyQuote.assetBuyAmount); + return doesAssetAmountMatch; + } else { + return true; + } +}; |