aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant/src/components')
-rw-r--r--packages/instant/src/components/erc20_asset_amount_input.tsx37
-rw-r--r--packages/instant/src/components/erc20_token_selector.tsx36
-rw-r--r--packages/instant/src/components/ui/icon.tsx1
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx3
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx36
5 files changed, 94 insertions, 19 deletions
diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx
index b1fec6405..56f892328 100644
--- a/packages/instant/src/components/erc20_asset_amount_input.tsx
+++ b/packages/instant/src/components/erc20_asset_amount_input.tsx
@@ -19,6 +19,7 @@ export interface ERC20AssetAmountInputProps {
startingFontSizePx: number;
fontColor?: ColorOption;
isDisabled: boolean;
+ numberOfAssetsAvailable?: number;
}
export interface ERC20AssetAmountInputState {
@@ -47,6 +48,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
private readonly _renderContentForAsset = (asset: ERC20Asset): React.ReactNode => {
const { onChange, ...rest } = this.props;
const amountBorderBottom = this.props.isDisabled ? '' : `1px solid ${transparentWhite}`;
+ const onSymbolClick = this._generateSelectAssetClickHandler();
return (
<React.Fragment>
<Container borderBottom={amountBorderBottom} display="inline-block">
@@ -59,7 +61,6 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
/>
</Container>
<Container
- cursor="pointer"
display="inline-block"
marginLeft="8px"
title={assetUtils.bestNameForAsset(asset, undefined)}
@@ -69,7 +70,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
fontSize={`${this.state.currentFontSizePx}px`}
fontColor={ColorOption.white}
textTransform="uppercase"
- onClick={this._handleSymbolClick}
+ onClick={onSymbolClick}
>
{assetUtils.formattedSymbolForAsset(asset)}
</Text>
@@ -80,6 +81,13 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
);
};
private readonly _renderBackupContent = (): React.ReactNode => {
+ const { numberOfAssetsAvailable } = this.props;
+ let text = 'Select Token';
+ if (_.isUndefined(numberOfAssetsAvailable)) {
+ text = '...Loading';
+ } else if (numberOfAssetsAvailable === 0) {
+ text = 'Assets Unavailable';
+ }
return (
<Flex>
<Text
@@ -87,17 +95,21 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
fontColor={ColorOption.white}
opacity={0.7}
fontWeight="500"
- onClick={this._handleSymbolClick}
+ onClick={this._generateSelectAssetClickHandler()}
>
- Select Token
+ {text}
</Text>
{this._renderChevronIcon()}
</Flex>
);
};
private readonly _renderChevronIcon = (): React.ReactNode => {
+ const { numberOfAssetsAvailable } = this.props;
+ if (_.isUndefined(numberOfAssetsAvailable) || numberOfAssetsAvailable <= 1) {
+ return null;
+ }
return (
- <Container marginLeft="5px" onClick={this._handleSymbolClick}>
+ <Container cursor="pointer" marginLeft="5px" onClick={this._generateSelectAssetClickHandler()}>
<Icon icon="chevron" width={12} />
</Container>
);
@@ -110,10 +122,19 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
currentFontSizePx: fontSizePx,
});
};
- private readonly _handleSymbolClick = () => {
- if (this.props.onSelectAssetClick) {
- this.props.onSelectAssetClick(this.props.asset);
+ private readonly _generateSelectAssetClickHandler = (): (() => void) | undefined => {
+ // We don't want to allow opening the token selection panel if there are no assets.
+ // Since styles are inferred from the presence of a click handler, we want to return undefined
+ // instead of providing a noop.
+ const { numberOfAssetsAvailable, onSelectAssetClick } = this.props;
+ if (
+ _.isUndefined(numberOfAssetsAvailable) ||
+ numberOfAssetsAvailable <= 1 ||
+ _.isUndefined(onSelectAssetClick)
+ ) {
+ return undefined;
}
+ return () => onSelectAssetClick(this.props.asset);
};
// For assets with symbols of different length,
// start scaling the input at different character lengths
diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
new file mode 100644
index 000000000..12051b382
--- /dev/null
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -0,0 +1,36 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { ERC20Asset } from '../types';
+
+import { Button, Container } from './ui';
+
+export interface ERC20TokenSelectorProps {
+ tokens: ERC20Asset[];
+ onTokenSelect: (token: ERC20Asset) => void;
+}
+
+export const ERC20TokenSelector: React.StatelessComponent<ERC20TokenSelectorProps> = ({ tokens, onTokenSelect }) => (
+ <Container>
+ {_.map(tokens, token => <TokenSelectorRow key={token.assetData} token={token} onClick={onTokenSelect} />)}
+ </Container>
+);
+
+interface TokenSelectorRowProps {
+ token: ERC20Asset;
+ onClick: (token: ERC20Asset) => void;
+}
+
+class TokenSelectorRow extends React.Component<TokenSelectorRowProps> {
+ public render(): React.ReactNode {
+ const { token } = this.props;
+ return (
+ <Container>
+ <Button onClick={this._handleClick}>Select {token.metaData.symbol}</Button>
+ </Container>
+ );
+ }
+ private readonly _handleClick = (): void => {
+ this.props.onClick(this.props.token);
+ };
+}
diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx
index f12059cff..574cb26b7 100644
--- a/packages/instant/src/components/ui/icon.tsx
+++ b/packages/instant/src/components/ui/icon.tsx
@@ -104,7 +104,6 @@ export const Icon = styled(PlainIcon)`
`;
Icon.defaultProps = {
- color: 'white',
padding: '0em 0em',
};
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index 009ad9b2a..850beb49c 100644
--- a/packages/instant/src/components/zero_ex_instant_container.tsx
+++ b/packages/instant/src/components/zero_ex_instant_container.tsx
@@ -1,5 +1,6 @@
import * as React from 'react';
+import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector';
import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
import { LatestError } from '../containers/latest_error';
import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons';
@@ -45,7 +46,7 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
animationState={this.state.tokenSelectionPanelAnimationState}
onClose={this._handlePanelClose}
>
- Select Your Token
+ <AvailableERC20TokenSelector onTokenSelect={this._handlePanelClose} />
</SlidingPanel>
</Container>
</Container>
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 8c1025723..8552a7fb5 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -17,25 +17,28 @@ import { gasPriceEstimator } from '../util/gas_price_estimator';
import { getProvider } from '../util/provider';
import { web3Wrapper } from '../util/web3_wrapper';
+import { ZeroExInstantContainer } from './zero_ex_instant_container';
+
fonts.include();
export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps &
Partial<ZeroExInstantProviderOptionalProps>;
export interface ZeroExInstantProviderRequiredProps {
- // TODO: Change API when we allow the selection of different assetDatas
- assetData: string;
- liquiditySource: string | SignedOrder[];
+ orderSource: string | SignedOrder[];
}
export interface ZeroExInstantProviderOptionalProps {
- defaultAssetBuyAmount?: number;
+ availableAssetDatas: string[];
+ defaultAssetBuyAmount: number;
+ defaultSelectedAssetData: string;
additionalAssetMetaDataMap: ObjectMap<AssetMetaData>;
networkId: Network;
}
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
private readonly _store: Store;
+ // TODO(fragosti): Write tests for this beast once we inject a provider.
private static _mergeInitialStateWithProps(props: ZeroExInstantProviderProps, state: State = INITIAL_STATE): State {
const networkId = props.networkId || state.network;
// TODO: Provider needs to not be hard-coded to injected web3.
@@ -44,14 +47,14 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
networkId,
};
let assetBuyer;
- if (_.isString(props.liquiditySource)) {
+ if (_.isString(props.orderSource)) {
assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(
provider,
- props.liquiditySource,
+ props.orderSource,
assetBuyerOptions,
);
} else {
- assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.liquiditySource, assetBuyerOptions);
+ assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.orderSource, assetBuyerOptions);
}
const completeAssetMetaDataMap = {
...props.additionalAssetMetaDataMap,
@@ -61,10 +64,19 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
...state,
assetBuyer,
network: networkId,
- selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap, networkId),
+ selectedAsset: _.isUndefined(props.defaultSelectedAssetData)
+ ? undefined
+ : assetUtils.createAssetFromAssetDataOrThrow(
+ props.defaultSelectedAssetData,
+ completeAssetMetaDataMap,
+ networkId,
+ ),
selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount)
? state.selectedAssetAmount
: new BigNumberInput(props.defaultAssetBuyAmount),
+ availableAssets: _.isUndefined(props.availableAssetDatas)
+ ? undefined
+ : assetUtils.createAssetsFromAssetDatas(props.availableAssetDatas, completeAssetMetaDataMap, networkId),
assetMetaDataMap: completeAssetMetaDataMap,
};
return storeStateFromProps;
@@ -76,8 +88,14 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
}
public componentDidMount(): void {
+ const state = this._store.getState();
// tslint:disable-next-line:no-floating-promises
- asyncData.fetchAndDispatchToStore(this._store);
+ asyncData.fetchEthPriceAndDispatchToStore(this._store);
+ // fetch available assets if none are specified
+ if (_.isUndefined(state.availableAssets)) {
+ // tslint:disable-next-line:no-floating-promises
+ asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
+ }
// warm up the gas price estimator cache just in case we can't
// grab the gas price estimate when submitting the transaction