diff options
7 files changed, 50 insertions, 24 deletions
diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html index 74975678a..1c08aa5a1 100644 --- a/packages/instant/public/index.html +++ b/packages/instant/public/index.html @@ -59,13 +59,13 @@ assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498', } const orderSourceOverride = queryParams.getQueryParamValue('orderSource'); + const availableAssetDatasString = queryParams.getQueryParamValue('availableAssetDatas'); const renderOptionsOverrides = { orderSource: orderSourceOverride === 'provided' ? [providedOrder] : orderSourceOverride, - assetData: queryParams.getQueryParamValue('assetData'), networkId: +queryParams.getQueryParamValue('networkId') || undefined, defaultAssetBuyAmount: +queryParams.getQueryParamValue('defaultAssetBuyAmount') || undefined, - availableAssetIdentifiers: JSON.parse(queryParams.getQueryParamValue('availableAssetIdentifiers') || '[]'), - defaultSelectedAssetIdentifier: queryParams.getQueryParamValue('defaultSelectedAssetIdentifier'), + availableAssetDatas: availableAssetDatasString ? JSON.parse(availableAssetDatasString) : undefined, + defaultSelectedAssetData: queryParams.getQueryParamValue('defaultSelectedAssetData'), } const renderOptions = Object.assign({}, renderOptionsDefaults, removeUndefined(renderOptionsOverrides)); zeroExInstant.render(renderOptions); diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index b1fec6405..e222bc576 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._generateSelectAssetClick(); 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._generateSelectAssetClick()} > - 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._generateSelectAssetClick()}> <Icon icon="chevron" width={12} /> </Container> ); @@ -110,7 +122,15 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput currentFontSizePx: fontSizePx, }); }; - private readonly _handleSymbolClick = () => { + // We don't want to allow opening the token selection panel if there are no assets. + private readonly _generateSelectAssetClick = (): (() => void) | undefined => { + const { numberOfAssetsAvailable } = this.props; + if (_.isUndefined(numberOfAssetsAvailable) || numberOfAssetsAvailable <= 1) { + return undefined; + } + return this._handleSelectAssetClick; + }; + private readonly _handleSelectAssetClick = () => { if (this.props.onSelectAssetClick) { this.props.onSelectAssetClick(this.props.asset); } diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index a98176e9b..12051b382 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -11,7 +11,9 @@ export interface ERC20TokenSelectorProps { } export const ERC20TokenSelector: React.StatelessComponent<ERC20TokenSelectorProps> = ({ tokens, onTokenSelect }) => ( - <Container>{_.map(tokens, token => <TokenSelectorRow token={token} onClick={onTokenSelect} />)}</Container> + <Container> + {_.map(tokens, token => <TokenSelectorRow key={token.assetData} token={token} onClick={onTokenSelect} />)} + </Container> ); interface TokenSelectorRowProps { diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index ab6350010..e49001d12 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -37,6 +37,7 @@ export interface ZeroExInstantOptionalProps { export class ZeroExInstant extends React.Component<ZeroExInstantProps> { private readonly _store: Store; + // TODO(fragosti): Write tests for this beast once we inject a provider. private static _mergeInitialStateWithProps(props: ZeroExInstantProps, state: State = INITIAL_STATE): State { const networkId = props.networkId || state.network; // TODO: Provider needs to not be hard-coded to injected web3. @@ -72,6 +73,9 @@ export class ZeroExInstant extends React.Component<ZeroExInstantProps> { 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; @@ -87,7 +91,7 @@ export class ZeroExInstant extends React.Component<ZeroExInstantProps> { // tslint:disable-next-line:no-floating-promises asyncData.fetchEthPriceAndDispatchToStore(this._store); // fetch available assets if none are specified - if (_.isEmpty(state.availableAssets)) { + if (_.isUndefined(state.availableAssets)) { // tslint:disable-next-line:no-floating-promises asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store); } diff --git a/packages/instant/src/containers/available_erc20_token_selector.ts b/packages/instant/src/containers/available_erc20_token_selector.ts index 6b5ecb6ac..e8bacdba0 100644 --- a/packages/instant/src/containers/available_erc20_token_selector.ts +++ b/packages/instant/src/containers/available_erc20_token_selector.ts @@ -20,7 +20,7 @@ interface ConnectedDispatch { } const mapStateToProps = (state: State, _ownProps: AvailableERC20TokenSelectorProps): ConnectedState => ({ - tokens: assetUtils.getERC20AssetsFromAssets(state.availableAssets), + tokens: assetUtils.getERC20AssetsFromAssets(state.availableAssets || []), }); const mapDispatchToProps = ( 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 217d603d2..64b6f4b3b 100644 --- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -27,6 +27,7 @@ interface ConnectedState { value?: BigNumberInput; asset?: ERC20Asset; isDisabled: boolean; + numberOfAssetsAvailable?: number; } interface ConnectedDispatch { @@ -38,6 +39,7 @@ interface ConnectedProps { asset?: ERC20Asset; onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; isDisabled: boolean; + numberOfAssetsAvailable?: number; } type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps; @@ -46,20 +48,17 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP 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, - }; - } - + const selectedAsset = + !_.isUndefined(state.selectedAsset) && state.selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20 + ? (state.selectedAsset as ERC20Asset) + : undefined; + const numberOfAssetsAvailable = _.isUndefined(state.availableAssets) ? undefined : state.availableAssets.length; return { assetBuyer: state.assetBuyer, value: state.selectedAssetAmount, - asset: selectedAsset as ERC20Asset, + asset: selectedAsset, isDisabled, + numberOfAssetsAvailable, }; }; @@ -138,6 +137,7 @@ const mergeProps = ( connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); }, isDisabled: connectedState.isDisabled, + numberOfAssetsAvailable: connectedState.numberOfAssetsAvailable, }; }; diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 57d95167a..20d927561 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -23,7 +23,7 @@ export interface State { assetBuyer?: AssetBuyer; assetMetaDataMap: ObjectMap<AssetMetaData>; selectedAsset?: Asset; - availableAssets: Asset[]; + availableAssets?: Asset[]; selectedAssetAmount?: BigNumberInput; buyOrderState: OrderState; ethUsdPrice?: BigNumber; @@ -36,7 +36,7 @@ export interface State { export const INITIAL_STATE: State = { network: Network.Mainnet, selectedAssetAmount: undefined, - availableAssets: [], + availableAssets: undefined, assetMetaDataMap, buyOrderState: { processState: OrderProcessState.NONE }, ethUsdPrice: undefined, |