aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-10-29 09:36:13 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-10-29 10:07:53 +0800
commit8d1689073b702d973075d30b2bb36369487fad1c (patch)
treecb0380d4782b0715f0d24e7a9c5f88b49a60fa50 /packages/instant
parent4f5ab1a72d33dc6a7516d7b1d51f1aa15752a6b8 (diff)
parentae6202ed3d777605a3fd02cd29141a3ba40f4b34 (diff)
downloaddexon-0x-contracts-8d1689073b702d973075d30b2bb36369487fad1c.tar.gz
dexon-0x-contracts-8d1689073b702d973075d30b2bb36369487fad1c.tar.zst
dexon-0x-contracts-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')
-rw-r--r--packages/instant/package.json2
-rw-r--r--packages/instant/src/components/buy_order_state_button.tsx26
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx63
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx5
-rw-r--r--packages/instant/src/components/retry_button.tsx11
-rw-r--r--packages/instant/src/components/scaling_amount_input.tsx3
-rw-r--r--packages/instant/src/components/scaling_input.tsx5
-rw-r--r--packages/instant/src/components/secondary_button.tsx5
-rw-r--r--packages/instant/src/components/ui/button.tsx1
-rw-r--r--packages/instant/src/components/view_transaction_button.tsx11
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx4
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_button.tsx20
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts (renamed from packages/instant/src/containers/selected_asset_buy_button.ts)44
-rw-r--r--packages/instant/src/containers/selected_asset_retry_button.tsx26
-rw-r--r--packages/instant/src/containers/selected_asset_view_transaction_button.tsx38
-rw-r--r--packages/instant/src/containers/selected_erc20_asset_amount_input.ts10
-rw-r--r--packages/instant/src/redux/reducer.ts47
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;
+ }
+};