From 6091ee732d208eaf9889087b8308dfd0427b9be5 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 31 Oct 2018 19:20:37 -0700 Subject: feat: modify public API to allow for passing in available assets, or fetch assets from SRA --- packages/instant/public/index.html | 8 +++-- .../instant/src/components/zero_ex_instant.tsx | 28 ++++++++++----- packages/instant/src/index.umd.ts | 6 ++-- packages/instant/src/redux/actions.ts | 4 ++- packages/instant/src/redux/async_data.ts | 25 +++++++++---- packages/instant/src/redux/reducer.ts | 9 ++++- packages/instant/src/util/assert.ts | 8 ++--- packages/instant/src/util/asset.ts | 41 ++++++++++++++++++++-- 8 files changed, 100 insertions(+), 29 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html index 9f1dfdb64..74975678a 100644 --- a/packages/instant/public/index.html +++ b/packages/instant/public/index.html @@ -55,15 +55,17 @@ }; const queryParams = new Uri(window.location.search); const renderOptionsDefaults = { - liquiditySource: 'https://api.radarrelay.com/0x/v2/', + orderSource: 'https://api.radarrelay.com/0x/v2/', assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498', } - const liquiditySourceOverride = queryParams.getQueryParamValue('liquiditySource'); + const orderSourceOverride = queryParams.getQueryParamValue('orderSource'); const renderOptionsOverrides = { - liquiditySource: liquiditySourceOverride === 'provided' ? [providedOrder] : liquiditySourceOverride, + 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'), } const renderOptions = Object.assign({}, renderOptionsDefaults, removeUndefined(renderOptionsOverrides)); zeroExInstant.render(renderOptions); diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index d54dfc153..ab6350010 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -24,13 +24,13 @@ fonts.include(); export type ZeroExInstantProps = ZeroExInstantRequiredProps & Partial; export interface ZeroExInstantRequiredProps { - // TODO: Change API when we allow the selection of different assetDatas - assetData: string; - liquiditySource: string | SignedOrder[]; + orderSource: string | SignedOrder[]; } export interface ZeroExInstantOptionalProps { + availableAssetDatas: string[]; defaultAssetBuyAmount?: number; + defaultSelectedAssetData?: string; additionalAssetMetaDataMap: ObjectMap; networkId: Network; } @@ -45,14 +45,14 @@ export class ZeroExInstant extends React.Component { 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, @@ -62,7 +62,13 @@ export class ZeroExInstant extends React.Component { ...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), @@ -77,8 +83,14 @@ export class ZeroExInstant extends React.Component { } 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 (_.isEmpty(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 diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index dabd45cae..77bdb66e1 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -7,8 +7,10 @@ import { ZeroExInstant, ZeroExInstantProps } from './index'; import { assert } from './util/assert'; export const render = (props: ZeroExInstantProps, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { - assert.isHexString('assetData', props.assetData); - assert.isValidLiquiditySource('liquiditySource', props.liquiditySource); + assert.isValidOrderSource('orderSource', props.orderSource); + if (!_.isUndefined(props.defaultSelectedAssetData)) { + assert.isHexString('defaultSelectedAssetData', props.defaultSelectedAssetData); + } if (!_.isUndefined(props.additionalAssetMetaDataMap)) { assert.isValidAssetMetaDataMap('additionalAssetMetaDataMap', props.additionalAssetMetaDataMap); } diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index bfae68e2b..eadd8b42c 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash'; import { BigNumberInput } from '../util/big_number_input'; -import { ActionsUnion, OrderState } from '../types'; +import { ActionsUnion, Asset, OrderState } from '../types'; export interface PlainAction { type: T; @@ -28,6 +28,7 @@ export enum ActionTypes { UPDATE_BUY_ORDER_STATE = 'UPDATE_BUY_ORDER_STATE', UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', UPDATE_SELECTED_ASSET = 'UPDATE_SELECTED_ASSET', + SET_AVAILABLE_ASSETS = 'SET_AVAILABLE_ASSETS', SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE', SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE', @@ -43,6 +44,7 @@ export const actions = { updateBuyOrderState: (orderState: OrderState) => createAction(ActionTypes.UPDATE_BUY_ORDER_STATE, orderState), updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote), updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData), + setAvailableAssets: (availableAssets: Asset[]) => createAction(ActionTypes.SET_AVAILABLE_ASSETS, availableAssets), setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING), setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE), setErrorMessage: (errorMessage: string) => createAction(ActionTypes.SET_ERROR_MESSAGE, errorMessage), diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 4ed89bdc3..f8dbe9fd4 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -1,22 +1,33 @@ +import * as _ from 'lodash'; + import { BIG_NUMBER_ZERO } from '../constants'; +import { assetUtils } from '../util/asset'; import { coinbaseApi } from '../util/coinbase_api'; -import { ActionTypes } from './actions'; - +import { actions } from './actions'; import { Store } from './store'; export const asyncData = { - fetchAndDispatchToStore: async (store: Store) => { + fetchEthPriceAndDispatchToStore: async (store: Store) => { let ethUsdPrice = BIG_NUMBER_ZERO; try { ethUsdPrice = await coinbaseApi.getEthUsdPrice(); } catch (e) { // ignore } finally { - store.dispatch({ - type: ActionTypes.UPDATE_ETH_USD_PRICE, - data: ethUsdPrice, - }); + store.dispatch(actions.updateEthUsdPrice(ethUsdPrice)); + } + }, + fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => { + const { assetBuyer, assetMetaDataMap, network } = store.getState(); + if (!_.isUndefined(assetBuyer)) { + try { + const assetDatas = await assetBuyer.getAvailableAssetDatasAsync(); + const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); + store.dispatch(actions.setAvailableAssets(assets)); + } catch (e) { + // ignore + } } }, }; diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index dd9403052..c0a8c1771 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -24,6 +24,7 @@ export interface State { assetBuyer?: AssetBuyer; assetMetaDataMap: ObjectMap; selectedAsset?: Asset; + availableAssets: Asset[]; selectedAssetAmount?: BigNumberInput; buyOrderState: OrderState; ethUsdPrice?: BigNumber; @@ -36,6 +37,7 @@ export interface State { export const INITIAL_STATE: State = { network: Network.Mainnet, selectedAssetAmount: undefined, + availableAssets: [], assetMetaDataMap, buyOrderState: { processState: OrderProcessState.NONE }, ethUsdPrice: undefined, @@ -109,7 +111,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => const newSelectedAssetData = action.data; let newSelectedAsset: Asset | undefined; if (!_.isUndefined(newSelectedAssetData)) { - newSelectedAsset = assetUtils.createAssetFromAssetData( + newSelectedAsset = assetUtils.createAssetFromAssetDataOrThrow( newSelectedAssetData, state.assetMetaDataMap, state.network, @@ -127,6 +129,11 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => buyOrderState: { processState: OrderProcessState.NONE }, selectedAssetAmount: undefined, }; + case ActionTypes.SET_AVAILABLE_ASSETS: + return { + ...state, + availableAssets: action.data, + }; default: return state; } diff --git a/packages/instant/src/util/assert.ts b/packages/instant/src/util/assert.ts index 584d3d4b1..1267a1d23 100644 --- a/packages/instant/src/util/assert.ts +++ b/packages/instant/src/util/assert.ts @@ -8,12 +8,12 @@ import { AssetMetaData } from '../types'; export const assert = { ...sharedAssert, - isValidLiquiditySource(variableName: string, liquiditySource: string | SignedOrder[]): void { - if (_.isString(liquiditySource)) { - sharedAssert.isUri(variableName, liquiditySource); + isValidOrderSource(variableName: string, orderSource: string | SignedOrder[]): void { + if (_.isString(orderSource)) { + sharedAssert.isUri(variableName, orderSource); return; } - sharedAssert.doesConformToSchema(variableName, liquiditySource, schemas.signedOrdersSchema); + sharedAssert.doesConformToSchema(variableName, orderSource, schemas.signedOrdersSchema); }, isValidAssetMetaDataMap(variableName: string, metaDataMap: ObjectMap): void { _.forEach(metaDataMap, (metaData, assetData) => { diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 630103c7b..0576a7b60 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -5,7 +5,31 @@ import { assetDataNetworkMapping } from '../data/asset_data_network_mapping'; import { Asset, AssetMetaData, ERC20Asset, Network, ZeroExInstantError } from '../types'; export const assetUtils = { - createAssetFromAssetData: ( + createAssetsFromAssetDatas: ( + assetDatas: string[], + assetMetaDataMap: ObjectMap, + network: Network, + ): Asset[] => { + const arrayOfAssetOrUndefined = _.map(assetDatas, assetData => + assetUtils.createAssetFromAssetDataIfExists(assetData, assetMetaDataMap, network), + ); + return _.compact(arrayOfAssetOrUndefined); + }, + createAssetFromAssetDataIfExists: ( + assetData: string, + assetMetaDataMap: ObjectMap, + network: Network, + ): Asset | undefined => { + const metaData = assetUtils.getMetaDataIfExists(assetData, assetMetaDataMap, network); + if (_.isUndefined(metaData)) { + return; + } + return { + assetData, + metaData, + }; + }, + createAssetFromAssetDataOrThrow: ( assetData: string, assetMetaDataMap: ObjectMap, network: Network, @@ -16,6 +40,17 @@ export const assetUtils = { }; }, getMetaDataOrThrow: (assetData: string, metaDataMap: ObjectMap, network: Network): AssetMetaData => { + const metaDataIfExists = assetUtils.getMetaDataIfExists(assetData, metaDataMap, network); + if (_.isUndefined(metaDataIfExists)) { + throw new Error(ZeroExInstantError.AssetMetaDataNotAvailable); + } + return metaDataIfExists; + }, + getMetaDataIfExists: ( + assetData: string, + metaDataMap: ObjectMap, + network: Network, + ): AssetMetaData | undefined => { let mainnetAssetData: string | undefined = assetData; if (network !== Network.Mainnet) { const mainnetAssetDataIfExists = assetUtils.getAssociatedAssetDataIfExists(assetData, network); @@ -24,11 +59,11 @@ export const assetUtils = { mainnetAssetData = mainnetAssetDataIfExists || assetData; } if (_.isUndefined(mainnetAssetData)) { - throw new Error(ZeroExInstantError.AssetMetaDataNotAvailable); + return; } const metaData = metaDataMap[mainnetAssetData]; if (_.isUndefined(metaData)) { - throw new Error(ZeroExInstantError.AssetMetaDataNotAvailable); + return; } return metaData; }, -- cgit v1.2.3 From 3f918622bcce21ba104e0f13e71247796345ab0f Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 31 Oct 2018 19:50:37 -0700 Subject: feat: implement basic erc20 token selector --- .../src/components/erc20_token_selector.tsx | 34 ++++++++++++++++++++ .../src/components/zero_ex_instant_container.tsx | 3 +- .../containers/available_erc20_token_selector.ts | 36 ++++++++++++++++++++++ packages/instant/src/redux/actions.ts | 2 +- packages/instant/src/redux/reducer.ts | 12 +------- packages/instant/src/util/asset.ts | 7 +++++ 6 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 packages/instant/src/components/erc20_token_selector.tsx create mode 100644 packages/instant/src/containers/available_erc20_token_selector.ts (limited to 'packages/instant') 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..a98176e9b --- /dev/null +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -0,0 +1,34 @@ +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 = ({ tokens, onTokenSelect }) => ( + {_.map(tokens, token => )} +); + +interface TokenSelectorRowProps { + token: ERC20Asset; + onClick: (token: ERC20Asset) => void; +} + +class TokenSelectorRow extends React.Component { + public render(): React.ReactNode { + const { token } = this.props; + return ( + + + + ); + } + private readonly _handleClick = (): void => { + this.props.onClick(this.props.token); + }; +} diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 009ad9b2a..765ff7e3d 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 - Select Your Token + diff --git a/packages/instant/src/containers/available_erc20_token_selector.ts b/packages/instant/src/containers/available_erc20_token_selector.ts new file mode 100644 index 000000000..6b5ecb6ac --- /dev/null +++ b/packages/instant/src/containers/available_erc20_token_selector.ts @@ -0,0 +1,36 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { State } from '../redux/reducer'; +import { ERC20Asset } from '../types'; +import { assetUtils } from '../util/asset'; + +import { ERC20TokenSelector } from '../components/erc20_token_selector'; +import { Action, actions } from '../redux/actions'; + +export interface AvailableERC20TokenSelectorProps {} + +interface ConnectedState { + tokens: ERC20Asset[]; +} + +interface ConnectedDispatch { + onTokenSelect: (token: ERC20Asset) => void; +} + +const mapStateToProps = (state: State, _ownProps: AvailableERC20TokenSelectorProps): ConnectedState => ({ + tokens: assetUtils.getERC20AssetsFromAssets(state.availableAssets), +}); + +const mapDispatchToProps = ( + dispatch: Dispatch, + ownProps: AvailableERC20TokenSelectorProps, +): ConnectedDispatch => ({ + onTokenSelect: (token: ERC20Asset) => dispatch(actions.updateSelectedAsset(token)), +}); + +export const AvailableERC20TokenSelector: React.ComponentClass = connect( + mapStateToProps, + mapDispatchToProps, +)(ERC20TokenSelector); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index eadd8b42c..813c5e819 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -43,7 +43,7 @@ export const actions = { createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount), updateBuyOrderState: (orderState: OrderState) => createAction(ActionTypes.UPDATE_BUY_ORDER_STATE, orderState), updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote), - updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData), + updateSelectedAsset: (asset: Asset) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, asset), setAvailableAssets: (availableAssets: Asset[]) => createAction(ActionTypes.SET_AVAILABLE_ASSETS, availableAssets), setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING), setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index c0a8c1771..57d95167a 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -14,7 +14,6 @@ import { OrderProcessState, OrderState, } from '../types'; -import { assetUtils } from '../util/asset'; import { BigNumberInput } from '../util/big_number_input'; import { Action, ActionTypes } from './actions'; @@ -108,18 +107,9 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => latestErrorDisplayStatus: DisplayStatus.Hidden, }; case ActionTypes.UPDATE_SELECTED_ASSET: - const newSelectedAssetData = action.data; - let newSelectedAsset: Asset | undefined; - if (!_.isUndefined(newSelectedAssetData)) { - newSelectedAsset = assetUtils.createAssetFromAssetDataOrThrow( - newSelectedAssetData, - state.assetMetaDataMap, - state.network, - ); - } return { ...state, - selectedAsset: newSelectedAsset, + selectedAsset: action.data, }; case ActionTypes.RESET_AMOUNT: return { diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 0576a7b60..2efaadbd2 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -98,4 +98,11 @@ export const assetUtils = { } return assetDataGroupIfExists[Network.Mainnet]; }, + getERC20AssetsFromAssets: (assets: Asset[]): ERC20Asset[] => { + const erc20sOrUndefined = _.map( + assets, + asset => (asset.metaData.assetProxyId === AssetProxyId.ERC20 ? (asset as ERC20Asset) : undefined), + ); + return _.compact(erc20sOrUndefined); + }, }; -- cgit v1.2.3 From b55ba3a31823699fa2460fad6fd22b913c38c946 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:10:51 -0700 Subject: feat: add states to the erc20 input for no assets or only 1 asset --- packages/instant/public/index.html | 6 ++-- .../src/components/erc20_asset_amount_input.tsx | 32 ++++++++++++++++++---- .../src/components/erc20_token_selector.tsx | 4 ++- .../instant/src/components/zero_ex_instant.tsx | 6 +++- .../containers/available_erc20_token_selector.ts | 2 +- .../selected_erc20_asset_amount_input.ts | 20 +++++++------- packages/instant/src/redux/reducer.ts | 4 +-- 7 files changed, 50 insertions(+), 24 deletions(-) (limited to 'packages/instant') 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 { const { onChange, ...rest } = this.props; const amountBorderBottom = this.props.isDisabled ? '' : `1px solid ${transparentWhite}`; + const onSymbolClick = this._generateSelectAssetClick(); return ( @@ -59,7 +61,6 @@ export class ERC20AssetAmountInput extends React.Component {assetUtils.formattedSymbolForAsset(asset)} @@ -80,6 +81,13 @@ export class ERC20AssetAmountInput extends React.Component { + const { numberOfAssetsAvailable } = this.props; + let text = 'Select Token'; + if (_.isUndefined(numberOfAssetsAvailable)) { + text = '...Loading'; + } else if (numberOfAssetsAvailable === 0) { + text = 'Assets Unavailable'; + } return ( - Select Token + {text} {this._renderChevronIcon()} ); }; private readonly _renderChevronIcon = (): React.ReactNode => { + const { numberOfAssetsAvailable } = this.props; + if (_.isUndefined(numberOfAssetsAvailable) || numberOfAssetsAvailable <= 1) { + return null; + } return ( - + ); @@ -110,7 +122,15 @@ export class ERC20AssetAmountInput extends React.Component { + // 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 = ({ tokens, onTokenSelect }) => ( - {_.map(tokens, token => )} + + {_.map(tokens, token => )} + ); 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 { 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 { 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 { // 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; 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, -- cgit v1.2.3 From bda9d4c1b099fc4db05d34a1d8dc0543a68413b8 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:16:48 -0700 Subject: feat: auto-close panel when a token is selected --- .../instant/src/components/zero_ex_instant_container.tsx | 2 +- .../instant/src/containers/available_erc20_token_selector.ts | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 765ff7e3d..850beb49c 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -46,7 +46,7 @@ export class ZeroExInstantContainer extends React.Component - + diff --git a/packages/instant/src/containers/available_erc20_token_selector.ts b/packages/instant/src/containers/available_erc20_token_selector.ts index e8bacdba0..bb194cd6b 100644 --- a/packages/instant/src/containers/available_erc20_token_selector.ts +++ b/packages/instant/src/containers/available_erc20_token_selector.ts @@ -1,3 +1,4 @@ +import * as _ from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; @@ -9,7 +10,9 @@ import { assetUtils } from '../util/asset'; import { ERC20TokenSelector } from '../components/erc20_token_selector'; import { Action, actions } from '../redux/actions'; -export interface AvailableERC20TokenSelectorProps {} +export interface AvailableERC20TokenSelectorProps { + onTokenSelect?: (token: ERC20Asset) => void; +} interface ConnectedState { tokens: ERC20Asset[]; @@ -27,7 +30,12 @@ const mapDispatchToProps = ( dispatch: Dispatch, ownProps: AvailableERC20TokenSelectorProps, ): ConnectedDispatch => ({ - onTokenSelect: (token: ERC20Asset) => dispatch(actions.updateSelectedAsset(token)), + onTokenSelect: (token: ERC20Asset) => { + if (ownProps.onTokenSelect) { + ownProps.onTokenSelect(token); + } + dispatch(actions.updateSelectedAsset(token)); + }, }); export const AvailableERC20TokenSelector: React.ComponentClass = connect( -- cgit v1.2.3 From 9f5f31d39fffa873cedc889b5cf963b294a2dcc6 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:24:32 -0700 Subject: feat: add asserts for new API additions --- packages/instant/src/index.umd.ts | 3 +++ packages/instant/src/util/assert.ts | 3 +++ 2 files changed, 6 insertions(+) (limited to 'packages/instant') diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index 77bdb66e1..b998abe95 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -20,5 +20,8 @@ export const render = (props: ZeroExInstantProps, selector: string = DEFAULT_ZER if (!_.isUndefined(props.networkId)) { assert.isNumber('networkId', props.networkId); } + if (!_.isUndefined(props.availableAssetDatas)) { + assert.areValidAssetDatas('availableAssetDatas', props.availableAssetDatas); + } ReactDOM.render(React.createElement(ZeroExInstant, props), document.querySelector(selector)); }; diff --git a/packages/instant/src/util/assert.ts b/packages/instant/src/util/assert.ts index 1267a1d23..7c07215bf 100644 --- a/packages/instant/src/util/assert.ts +++ b/packages/instant/src/util/assert.ts @@ -15,6 +15,9 @@ export const assert = { } sharedAssert.doesConformToSchema(variableName, orderSource, schemas.signedOrdersSchema); }, + areValidAssetDatas(variableName: string, assetDatas: string[]): void { + _.forEach(assetDatas, (assetData, index) => assert.isHexString(`${variableName}[${index}]`, assetData)); + }, isValidAssetMetaDataMap(variableName: string, metaDataMap: ObjectMap): void { _.forEach(metaDataMap, (metaData, assetData) => { assert.isHexString(`key ${assetData} of ${variableName}`, assetData); -- cgit v1.2.3 From 7fc1a88680e85c5ab1a1ef7ba5eb1bc223614493 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:34:23 -0700 Subject: fix: better name method --- packages/instant/src/components/erc20_asset_amount_input.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index e222bc576..05b81e93d 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -48,7 +48,7 @@ export class ERC20AssetAmountInput extends React.Component { const { onChange, ...rest } = this.props; const amountBorderBottom = this.props.isDisabled ? '' : `1px solid ${transparentWhite}`; - const onSymbolClick = this._generateSelectAssetClick(); + const onSymbolClick = this._generateSelectAssetClickHandler(); return ( @@ -95,7 +95,7 @@ export class ERC20AssetAmountInput extends React.Component {text} @@ -109,7 +109,7 @@ export class ERC20AssetAmountInput extends React.Component + ); @@ -123,7 +123,7 @@ export class ERC20AssetAmountInput extends React.Component void) | undefined => { + private readonly _generateSelectAssetClickHandler = (): (() => void) | undefined => { const { numberOfAssetsAvailable } = this.props; if (_.isUndefined(numberOfAssetsAvailable) || numberOfAssetsAvailable <= 1) { return undefined; -- cgit v1.2.3 From 0a3af4eb224d68cfe1b3e16b912549cb52e5d0a5 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:37:43 -0700 Subject: chore: add clarification to _generateSelectAssetClickHandler --- .../src/components/erc20_asset_amount_input.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 05b81e93d..56f892328 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -122,18 +122,19 @@ export class ERC20AssetAmountInput extends React.Component void) | undefined => { - const { numberOfAssetsAvailable } = this.props; - if (_.isUndefined(numberOfAssetsAvailable) || numberOfAssetsAvailable <= 1) { + // 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 this._handleSelectAssetClick; - }; - private readonly _handleSelectAssetClick = () => { - if (this.props.onSelectAssetClick) { - this.props.onSelectAssetClick(this.props.asset); - } + return () => onSelectAssetClick(this.props.asset); }; // For assets with symbols of different length, // start scaling the input at different character lengths -- cgit v1.2.3 From 57fba86154451a247dc008a9080e1e65145e6778 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:40:23 -0700 Subject: chore: remove unneeded optional syntax --- packages/instant/src/components/zero_ex_instant.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index e49001d12..f3b212058 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -29,8 +29,8 @@ export interface ZeroExInstantRequiredProps { export interface ZeroExInstantOptionalProps { availableAssetDatas: string[]; - defaultAssetBuyAmount?: number; - defaultSelectedAssetData?: string; + defaultAssetBuyAmount: number; + defaultSelectedAssetData: string; additionalAssetMetaDataMap: ObjectMap; networkId: Network; } -- cgit v1.2.3 From 9fd931f7991398b9a6331d7bc5b8cd7a41491be9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 13:49:09 -0700 Subject: feat: better handle errors in async fetches --- packages/instant/src/redux/async_data.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index f8dbe9fd4..716558409 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -3,19 +3,20 @@ import * as _ from 'lodash'; import { BIG_NUMBER_ZERO } from '../constants'; import { assetUtils } from '../util/asset'; import { coinbaseApi } from '../util/coinbase_api'; +import { errorFlasher } from '../util/error_flasher'; import { actions } from './actions'; import { Store } from './store'; export const asyncData = { fetchEthPriceAndDispatchToStore: async (store: Store) => { - let ethUsdPrice = BIG_NUMBER_ZERO; try { - ethUsdPrice = await coinbaseApi.getEthUsdPrice(); - } catch (e) { - // ignore - } finally { + const ethUsdPrice = await coinbaseApi.getEthUsdPrice(); store.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)); } }, fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => { @@ -26,7 +27,10 @@ export const asyncData = { const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); store.dispatch(actions.setAvailableAssets(assets)); } catch (e) { - // ignore + const errorMessage = 'Error fetching available assets'; + errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage); + // On error, just specify that none are available + store.dispatch(actions.setAvailableAssets([])); } } }, -- cgit v1.2.3 From ce19ec207b07696a675bdadf71ea39d933ea2715 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 14:14:39 -0700 Subject: fix: remove assetData from default params --- packages/instant/public/index.html | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/instant') diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html index 1c08aa5a1..4c35e6f3b 100644 --- a/packages/instant/public/index.html +++ b/packages/instant/public/index.html @@ -56,7 +56,6 @@ const queryParams = new Uri(window.location.search); const renderOptionsDefaults = { orderSource: 'https://api.radarrelay.com/0x/v2/', - assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498', } const orderSourceOverride = queryParams.getQueryParamValue('orderSource'); const availableAssetDatasString = queryParams.getQueryParamValue('availableAssetDatas'); -- cgit v1.2.3 From ad96e953ceabd9e752eb9749f12090dd9ae17b9d Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 16:16:54 -0700 Subject: feat: use new Icon component functionality --- packages/instant/src/components/erc20_asset_amount_input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 56f892328..b27f349c0 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -109,8 +109,8 @@ export class ERC20AssetAmountInput extends React.Component - + + ); }; -- cgit v1.2.3 From 180f176716b57d43e2988b5db3a2423c7974177e Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 16:41:08 -0700 Subject: feat: use withTheme to use ColorOption to color Icon --- packages/instant/src/components/sliding_panel.tsx | 6 ++---- packages/instant/src/components/ui/icon.tsx | 14 ++++++++------ packages/instant/src/components/ui/overlay.tsx | 4 ++-- .../instant/src/components/zero_ex_instant_provider.tsx | 2 -- packages/instant/src/style/theme.ts | 4 ++-- 5 files changed, 14 insertions(+), 16 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 9219ad1f1..e83cf0fb5 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -5,7 +5,7 @@ import { zIndex } from '../style/z_index'; import { PositionAnimationSettings } from './animations/position_animation'; import { SlideAnimation, SlideAnimationState } from './animations/slide_animation'; -import { Button, Container, Text } from './ui'; +import { Container, Icon } from './ui'; export interface PanelProps { onClose?: () => void; @@ -13,9 +13,7 @@ export interface PanelProps { export const Panel: React.StatelessComponent = ({ children, onClose }) => ( - + {children} ); diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx index 574cb26b7..9b83d962a 100644 --- a/packages/instant/src/components/ui/icon.tsx +++ b/packages/instant/src/components/ui/icon.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { styled } from '../../style/theme'; +import { ColorOption, styled, Theme, withTheme } from '../../style/theme'; type svgRule = 'evenodd' | 'nonzero' | 'inherit'; interface IconInfo { @@ -58,13 +58,15 @@ export interface IconProps { className?: string; width: number; height?: number; - color?: string; + color?: ColorOption; icon: keyof IconInfoMapping; onClick?: (event: React.MouseEvent) => void; padding?: string; + theme: Theme; } -const PlainIcon: React.SFC = props => { +const PlainIcon: React.StatelessComponent = props => { const iconInfo = ICONS[props.icon]; + const colorValue = _.isUndefined(props.color) ? undefined : props.theme[props.color]; return (
= props => { > = props => { ); }; -export const Icon = styled(PlainIcon)` +export const Icon = withTheme(styled(PlainIcon)` cursor: ${props => (!_.isUndefined(props.onClick) ? 'pointer' : 'default')}; transition: opacity 0.5s ease; padding: ${props => props.padding}; @@ -101,7 +103,7 @@ export const Icon = styled(PlainIcon)` &:active { opacity: 1; } -`; +`); Icon.defaultProps = { padding: '0em 0em', diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index c5258b031..f1706c874 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { overlayBlack, styled } from '../../style/theme'; +import { ColorOption, overlayBlack, styled } from '../../style/theme'; import { Container } from './container'; import { Flex } from './flex'; @@ -16,7 +16,7 @@ export interface OverlayProps { const PlainOverlay: React.StatelessComponent = ({ children, className, onClose }) => ( - +
{children}
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 8552a7fb5..ce939c144 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -17,8 +17,6 @@ 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 & diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index e81694620..8a5d56927 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -1,6 +1,6 @@ import * as styledComponents from 'styled-components'; -const { default: styled, css, keyframes, ThemeProvider } = styledComponents; +const { default: styled, css, keyframes, withTheme, ThemeProvider } = styledComponents; export type Theme = { [key in ColorOption]: string }; @@ -31,4 +31,4 @@ export const theme: Theme = { export const transparentWhite = 'rgba(255,255,255,0.3)'; export const overlayBlack = 'rgba(0, 0, 0, 0.6)'; -export { styled, css, keyframes, ThemeProvider }; +export { styled, css, keyframes, withTheme, ThemeProvider }; -- cgit v1.2.3 From 7de33c5dd9842ef0e83eac64c6e42c69608e4ad0 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 16:52:31 -0700 Subject: feat: implement panel title and close --- packages/instant/src/components/sliding_panel.tsx | 20 +++++++++++++++----- .../src/components/zero_ex_instant_container.tsx | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index e83cf0fb5..678a60cea 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -5,16 +5,26 @@ import { zIndex } from '../style/z_index'; import { PositionAnimationSettings } from './animations/position_animation'; import { SlideAnimation, SlideAnimationState } from './animations/slide_animation'; -import { Container, Icon } from './ui'; +import { Container, Flex, Icon, Text } from './ui'; export interface PanelProps { + title?: string; onClose?: () => void; } -export const Panel: React.StatelessComponent = ({ children, onClose }) => ( - - - {children} +export const Panel: React.StatelessComponent = ({ title, children, onClose }) => ( + + + {title && ( + + + {title} + + + )} + + + {children} ); diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 850beb49c..f734dcbd7 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -43,6 +43,7 @@ export class ZeroExInstantContainer extends React.Component -- cgit v1.2.3 From ab245fe7dec88c509452dab75fff523c4c4a9461 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 17:52:15 -0700 Subject: feat: implement basic token selection UI --- .../src/components/erc20_token_selector.tsx | 37 +++++++++++++++++++--- .../instant/src/components/instant_heading.tsx | 2 +- packages/instant/src/components/ui/circle.tsx | 24 ++++++++++++++ packages/instant/src/components/ui/container.tsx | 9 ++++++ packages/instant/src/components/ui/index.ts | 1 + packages/instant/src/components/ui/text.tsx | 5 +-- 6 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 packages/instant/src/components/ui/circle.tsx (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 12051b382..a8bef3d61 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -1,9 +1,11 @@ import * as _ from 'lodash'; import * as React from 'react'; +import { ColorOption } from '../style/theme'; import { ERC20Asset } from '../types'; +import { assetUtils } from '../util/asset'; -import { Button, Container } from './ui'; +import { Circle, Container, Flex, Text } from './ui'; export interface ERC20TokenSelectorProps { tokens: ERC20Asset[]; @@ -12,7 +14,9 @@ export interface ERC20TokenSelectorProps { export const ERC20TokenSelector: React.StatelessComponent = ({ tokens, onTokenSelect }) => ( - {_.map(tokens, token => )} + + {_.map(tokens, token => )} + ); @@ -24,9 +28,34 @@ interface TokenSelectorRowProps { class TokenSelectorRow extends React.Component { public render(): React.ReactNode { const { token } = this.props; + const displaySymbol = assetUtils.bestNameForAsset(token); return ( - - + + + + + + + + {displaySymbol} + + + + + + {displaySymbol} + + + ); } diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 19c08db70..80d7a3ee2 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -22,7 +22,7 @@ export interface InstantHeadingProps { const PLACEHOLDER_COLOR = ColorOption.white; const ICON_WIDTH = 34; const ICON_HEIGHT = 34; -const ICON_COLOR = 'white'; +const ICON_COLOR = ColorOption.white; export class InstantHeading extends React.Component { public render(): React.ReactNode { diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx new file mode 100644 index 000000000..bd967d326 --- /dev/null +++ b/packages/instant/src/components/ui/circle.tsx @@ -0,0 +1,24 @@ + +import { styled } from '../../style/theme'; + +export interface CircleProps { + className?: string; + diameter: number; + fillColor?: string; +} + +export const Circle = + styled.div < + CircleProps > + ` + width: ${props => props.diameter}px; + height: ${props => props.diameter}px; + background-color: ${props => props.fillColor}; + border-radius: 50%; +`; + +Circle.displayName = 'Circle'; + +Circle.defaultProps = { + fillColor: 'white', +}; diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 7b8642761..e228a01b6 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -1,3 +1,5 @@ +import { darken } from 'polished'; + import { ColorOption, styled } from '../../style/theme'; import { cssRuleIfExists } from '../../style/util'; @@ -30,6 +32,7 @@ export interface ContainerProps { opacity?: number; cursor?: string; overflow?: string; + darkenOnHover?: boolean; } export const Container = @@ -64,6 +67,12 @@ export const Container = ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')}; background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; + &:hover { + ${props => + props.darkenOnHover + ? `background-color: ${darken(0.05, props.theme[props.backgroundColor || 'white'])}` + : ''}; + } `; Container.defaultProps = { diff --git a/packages/instant/src/components/ui/index.ts b/packages/instant/src/components/ui/index.ts index 0efabdb85..87f5c11a1 100644 --- a/packages/instant/src/components/ui/index.ts +++ b/packages/instant/src/components/ui/index.ts @@ -1,4 +1,5 @@ export { Text, TextProps, Title } from './text'; +export { Circle, CircleProps } from './circle'; export { Button, ButtonProps } from './button'; export { Flex, FlexProps } from './flex'; export { Container, ContainerProps } from './container'; diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index fd72f6cc8..cba6e7b20 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -18,7 +18,6 @@ export interface TextProps { fontWeight?: number | string; textDecorationLine?: string; onClick?: (event: React.MouseEvent) => void; - hoverColor?: string; noWrap?: boolean; display?: string; } @@ -46,9 +45,7 @@ export const Text = ${props => (props.textTransform ? `text-transform: ${props.textTransform}` : '')}; &:hover { ${props => - props.onClick - ? `color: ${props.hoverColor || darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` - : ''}; + props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''}; } `; -- cgit v1.2.3 From 92706a4b431e0023cf21adec62635447594d8ab3 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 17:59:51 -0700 Subject: feat: add name param to all ERC20AssetMetaData --- packages/instant/src/components/erc20_token_selector.tsx | 4 ++++ packages/instant/src/data/asset_meta_data_map.ts | 11 +++++++++++ packages/instant/src/types.ts | 1 + packages/instant/test/util/asset.test.ts | 1 + 4 files changed, 17 insertions(+) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index a8bef3d61..2f637a1a6 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -54,6 +54,10 @@ class TokenSelectorRow extends React.Component { {displaySymbol} + + - + + {token.metaData.name} diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index d7cf2c0d8..76df80540 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -10,65 +10,76 @@ export const assetMetaDataMap: ObjectMap = { decimals: 18, primaryColor: 'rgb(54, 50, 60)', symbol: 'zrx', + name: '0x', }, '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#ec3e6c', symbol: 'spank', + name: 'Spank', }, '0xf47261b0000000000000000000000000d26114cd6EE289AccF82350c8d8487fedB8A0C07': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#2e61ea', symbol: 'omg', + name: 'OmiseGo', }, '0xf47261b00000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: 'white', symbol: 'mkr', + name: 'Maker', }, '0xf47261b00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#9c326c', symbol: 'bat', + name: 'Basic Attention Token', }, '0xf47261b0000000000000000000000000744d70fdbe2ba4cf95131626614a1763df805b9e': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#5663b0', symbol: 'snt', + name: 'Status', }, '0xf47261b00000000000000000000000000f5d2fb29fb7d3cfee444a200298f468908cc942': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#f08839', symbol: 'mana', + name: 'Decentraland', }, '0xf47261b0000000000000000000000000a74476443119A942dE498590Fe1f2454d7D4aC0d': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#263469', symbol: 'gnt', + name: 'Golem', }, '0xf47261b000000000000000000000000012480e24eb5bec1a9d4369cab6a80cad3c0a377a': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#de5445', symbol: 'sub', + name: 'Substratum', }, '0xf47261b000000000000000000000000008d32b0da63e2C3bcF8019c9c5d849d7a9d791e6': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#000', symbol: 'dentacoin', + name: 'Dentacoin', }, '0xf47261b0000000000000000000000000e94327d07fc17907b4db788e5adf2ed424addff6': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#512D80', symbol: 'rep', + name: 'Augur', }, }; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 336465e43..963a5d656 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -39,6 +39,7 @@ export interface ERC20AssetMetaData { decimals: number; primaryColor?: string; symbol: string; + name: string; } export interface ERC721AssetMetaData { diff --git a/packages/instant/test/util/asset.test.ts b/packages/instant/test/util/asset.test.ts index c7db7eba7..4229b24ed 100644 --- a/packages/instant/test/util/asset.test.ts +++ b/packages/instant/test/util/asset.test.ts @@ -9,6 +9,7 @@ const ZRX_META_DATA: ERC20AssetMetaData = { assetProxyId: AssetProxyId.ERC20, symbol: 'zrx', decimals: 18, + name: '0x', }; const ZRX_ASSET: Asset = { assetData: ZRX_ASSET_DATA, -- cgit v1.2.3 From cdaa1407dacacc53e01a70b1e0ac46536342a4e0 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 18:36:34 -0700 Subject: feat: implement search bar UI --- packages/instant/src/components/erc20_token_selector.tsx | 6 ++++-- packages/instant/src/components/sliding_panel.tsx | 2 +- packages/instant/src/components/ui/icon.tsx | 8 ++++++++ packages/instant/src/components/ui/input.tsx | 1 - packages/instant/src/style/theme.ts | 4 +++- 5 files changed, 16 insertions(+), 5 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 2f637a1a6..a9728365b 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -5,6 +5,7 @@ import { ColorOption } from '../style/theme'; import { ERC20Asset } from '../types'; import { assetUtils } from '../util/asset'; +import { SearchInput } from './search_input'; import { Circle, Container, Flex, Text } from './ui'; export interface ERC20TokenSelectorProps { @@ -14,7 +15,8 @@ export interface ERC20TokenSelectorProps { export const ERC20TokenSelector: React.StatelessComponent = ({ tokens, onTokenSelect }) => ( - + + {_.map(tokens, token => )} @@ -40,7 +42,7 @@ class TokenSelectorRow extends React.Component { darkenOnHover={true} cursor="pointer" > - + diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 678a60cea..9064c220c 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -24,7 +24,7 @@ export const Panel: React.StatelessComponent = ({ title, children, o )} - {children} + {children} ); diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx index 9b83d962a..94ea26900 100644 --- a/packages/instant/src/components/ui/icon.tsx +++ b/packages/instant/src/components/ui/icon.tsx @@ -20,6 +20,7 @@ interface IconInfoMapping { failed: IconInfo; success: IconInfo; chevron: IconInfo; + search: IconInfo; } const ICONS: IconInfoMapping = { closeX: { @@ -52,6 +53,13 @@ const ICONS: IconInfoMapping = { strokeLinecap: 'round', strokeLinejoin: 'round', }, + search: { + viewBox: '0 0 14 14', + fillRule: 'evenodd', + clipRule: 'evenodd', + path: + 'M8.39404 5.19727C8.39404 6.96289 6.96265 8.39453 5.19702 8.39453C3.4314 8.39453 2 6.96289 2 5.19727C2 3.43164 3.4314 2 5.19702 2C6.96265 2 8.39404 3.43164 8.39404 5.19727ZM8.09668 9.51074C7.26855 10.0684 6.27075 10.3945 5.19702 10.3945C2.3269 10.3945 0 8.06738 0 5.19727C0 2.32715 2.3269 0 5.19702 0C8.06738 0 10.394 2.32715 10.394 5.19727C10.394 6.27051 10.0686 7.26855 9.51074 8.09668L13.6997 12.2861L12.2854 13.7002L8.09668 9.51074Z', + }, }; export interface IconProps { diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index a884ff7cb..65cf838b0 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -9,7 +9,6 @@ export interface InputProps { fontSize?: string; fontColor?: ColorOption; placeholder?: string; - onChange?: (event: React.ChangeEvent) => void; } export const Input = diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index 8a5d56927..d10c9b72c 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -10,6 +10,7 @@ export enum ColorOption { lightGrey = 'lightGrey', grey = 'grey', feintGrey = 'feintGrey', + lightestGrey = 'lightestGrey', darkGrey = 'darkGrey', white = 'white', lightOrange = 'lightOrange', @@ -17,11 +18,12 @@ export enum ColorOption { } export const theme: Theme = { - primaryColor: '#512D80', + primaryColor: '#333', black: 'black', lightGrey: '#999999', grey: '#666666', feintGrey: '#DEDEDE', + lightestGrey: '#EEEEEE', darkGrey: '#333333', white: 'white', lightOrange: '#F9F2ED', -- cgit v1.2.3 From 209b2c9dcb6e9e81011b64e7b8bad719dec35379 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 18:38:25 -0700 Subject: feat: improve position of close X in token selector --- packages/instant/src/components/sliding_panel.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 9064c220c..ea1d6b9a1 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -22,7 +22,9 @@ export const Panel: React.StatelessComponent = ({ title, children, o )} - + + + {children} -- cgit v1.2.3 From e2ff7b7c846fa97b56d6bd36192329dd8f485af0 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 18:55:37 -0700 Subject: feat: add basic token search functionality --- .../src/components/erc20_token_selector.tsx | 59 ++++++++++++++++++---- packages/instant/src/components/search_input.tsx | 26 ++++++++++ packages/instant/src/components/ui/input.tsx | 1 + 3 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 packages/instant/src/components/search_input.tsx (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index a9728365b..4a3724052 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -7,20 +7,57 @@ import { assetUtils } from '../util/asset'; import { SearchInput } from './search_input'; import { Circle, Container, Flex, Text } from './ui'; +import { bool } from 'prop-types'; export interface ERC20TokenSelectorProps { tokens: ERC20Asset[]; onTokenSelect: (token: ERC20Asset) => void; } -export const ERC20TokenSelector: React.StatelessComponent = ({ tokens, onTokenSelect }) => ( - - - - {_.map(tokens, token => )} - - -); +export interface ERC20TokenSelectorState { + searchQuery?: string; +} + +export class ERC20TokenSelector extends React.Component { + public state: ERC20TokenSelectorState = { + searchQuery: undefined, + }; + public render(): React.ReactNode { + const { tokens, onTokenSelect } = this.props; + return ( + + + + {_.map(tokens, token => { + if (!this._isTokenQueryMatch(token)) { + return null; + } + return ; + })} + + + ); + } + private readonly _handleSearchInputChange = (event: React.ChangeEvent): void => { + const searchQuery = event.target.value; + this.setState({ + searchQuery, + }); + }; + private readonly _isTokenQueryMatch = (token: ERC20Asset): boolean => { + const { searchQuery } = this.state; + if (_.isUndefined(searchQuery)) { + return true; + } + const stringToSearch = `${token.metaData.name} ${token.metaData.symbol}`; + return _.includes(stringToSearch.toLowerCase(), searchQuery.toLowerCase()); + }; +} interface TokenSelectorRowProps { token: ERC20Asset; @@ -53,13 +90,13 @@ class TokenSelectorRow extends React.Component { - + {displaySymbol} - - + - - {token.metaData.name} + {token.metaData.name} diff --git a/packages/instant/src/components/search_input.tsx b/packages/instant/src/components/search_input.tsx new file mode 100644 index 000000000..f082eaa16 --- /dev/null +++ b/packages/instant/src/components/search_input.tsx @@ -0,0 +1,26 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Container, Flex, Icon, Input, InputProps } from './ui'; + +export interface SearchInputProps extends InputProps { + backgroundColor?: ColorOption; +} + +export const SearchInput: React.StatelessComponent = props => ( + + + + + + +); + +SearchInput.displayName = 'SearchInput'; + +SearchInput.defaultProps = { + backgroundColor: ColorOption.lightestGrey, + fontColor: ColorOption.grey, +}; diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 65cf838b0..a884ff7cb 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -9,6 +9,7 @@ export interface InputProps { fontSize?: string; fontColor?: ColorOption; placeholder?: string; + onChange?: (event: React.ChangeEvent) => void; } export const Input = -- cgit v1.2.3 From 515b8712a11a5e9b7ea5264514f6ee8ecf25361c Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 18:59:28 -0700 Subject: chore: prettier and linter --- packages/instant/src/components/erc20_token_selector.tsx | 1 - packages/instant/src/components/ui/circle.tsx | 1 - 2 files changed, 2 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 4a3724052..481778495 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -7,7 +7,6 @@ import { assetUtils } from '../util/asset'; import { SearchInput } from './search_input'; import { Circle, Container, Flex, Text } from './ui'; -import { bool } from 'prop-types'; export interface ERC20TokenSelectorProps { tokens: ERC20Asset[]; diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx index bd967d326..e7a29d59c 100644 --- a/packages/instant/src/components/ui/circle.tsx +++ b/packages/instant/src/components/ui/circle.tsx @@ -1,4 +1,3 @@ - import { styled } from '../../style/theme'; export interface CircleProps { -- cgit v1.2.3 From 7619bc4f13bf22f3ec7caa9257a625331a9ff0ba Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 19:01:56 -0700 Subject: fix: dont include assetData in render options --- packages/instant/public/index.html | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/instant') diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html index e1f8432be..762369d9c 100644 --- a/packages/instant/public/index.html +++ b/packages/instant/public/index.html @@ -73,7 +73,6 @@ const queryParams = new Uri(window.location.search); const renderOptionsDefaults = { orderSource: 'https://api.radarrelay.com/0x/v2/', - assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498', onClose: () => { console.log('0x Instant Closed') } } const orderSourceOverride = queryParams.getQueryParamValue('orderSource'); -- cgit v1.2.3 From 1f3055c1bce264fb728190e7661f70db24ff6cee Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 2 Nov 2018 13:03:10 -0700 Subject: feat: reset input after token selection --- packages/instant/src/containers/available_erc20_token_selector.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/instant') diff --git a/packages/instant/src/containers/available_erc20_token_selector.ts b/packages/instant/src/containers/available_erc20_token_selector.ts index bb194cd6b..4d4218d22 100644 --- a/packages/instant/src/containers/available_erc20_token_selector.ts +++ b/packages/instant/src/containers/available_erc20_token_selector.ts @@ -31,10 +31,11 @@ const mapDispatchToProps = ( ownProps: AvailableERC20TokenSelectorProps, ): ConnectedDispatch => ({ onTokenSelect: (token: ERC20Asset) => { + dispatch(actions.updateSelectedAsset(token)); + dispatch(actions.resetAmount()); if (ownProps.onTokenSelect) { ownProps.onTokenSelect(token); } - dispatch(actions.updateSelectedAsset(token)); }, }); -- cgit v1.2.3 From 819ba1430337d330dec05be5a4bae5651419bf63 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 2 Nov 2018 13:26:59 -0700 Subject: fix: change assetdatas for OMG and REP to be all lower case, make MKR blue --- packages/instant/src/data/asset_data_network_mapping.ts | 4 ++-- packages/instant/src/data/asset_meta_data_map.ts | 6 +++--- packages/instant/src/util/asset.ts | 7 +++++-- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/data/asset_data_network_mapping.ts b/packages/instant/src/data/asset_data_network_mapping.ts index a7bc6a967..43bd34697 100644 --- a/packages/instant/src/data/asset_data_network_mapping.ts +++ b/packages/instant/src/data/asset_data_network_mapping.ts @@ -20,7 +20,7 @@ export const assetDataNetworkMapping: AssetDataByNetwork[] = [ }, // OMG { - [Network.Mainnet]: '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18', + [Network.Mainnet]: '0xf47261b0000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07', [Network.Kovan]: '0xf47261b000000000000000000000000046096d8ec059dbaae2950b30e01634ff0dc652ec', }, // MKR @@ -59,6 +59,6 @@ export const assetDataNetworkMapping: AssetDataByNetwork[] = [ // REP { [Network.Kovan]: '0xf47261b00000000000000000000000008cb3971b8eb709c14616bd556ff6683019e90d9c', - [Network.Mainnet]: '0xf47261b0000000000000000000000000e94327d07fc17907b4db788e5adf2ed424addff6', + [Network.Mainnet]: '0xf47261b00000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e862', }, ]; diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index 76df80540..8a0f29e21 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -19,7 +19,7 @@ export const assetMetaDataMap: ObjectMap = { symbol: 'spank', name: 'Spank', }, - '0xf47261b0000000000000000000000000d26114cd6EE289AccF82350c8d8487fedB8A0C07': { + '0xf47261b0000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#2e61ea', @@ -29,7 +29,7 @@ export const assetMetaDataMap: ObjectMap = { '0xf47261b00000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: 'white', + primaryColor: '#87e4ca', symbol: 'mkr', name: 'Maker', }, @@ -75,7 +75,7 @@ export const assetMetaDataMap: ObjectMap = { symbol: 'dentacoin', name: 'Dentacoin', }, - '0xf47261b0000000000000000000000000e94327d07fc17907b4db788e5adf2ed424addff6': { + '0xf47261b00000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e862': { assetProxyId: AssetProxyId.ERC20, decimals: 18, primaryColor: '#512D80', diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 2efaadbd2..fbfbb19f3 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -53,7 +53,10 @@ export const assetUtils = { ): AssetMetaData | undefined => { let mainnetAssetData: string | undefined = assetData; if (network !== Network.Mainnet) { - const mainnetAssetDataIfExists = assetUtils.getAssociatedAssetDataIfExists(assetData, network); + const mainnetAssetDataIfExists = assetUtils.getAssociatedAssetDataIfExists( + assetData.toLowerCase(), + network, + ); // Just so we don't fail in the case where we are on a non-mainnet network, // but pass in a valid mainnet assetData. mainnetAssetData = mainnetAssetDataIfExists || assetData; @@ -61,7 +64,7 @@ export const assetUtils = { if (_.isUndefined(mainnetAssetData)) { return; } - const metaData = metaDataMap[mainnetAssetData]; + const metaData = metaDataMap[mainnetAssetData.toLowerCase()]; if (_.isUndefined(metaData)) { return; } -- cgit v1.2.3 From cc4ccda6232af470b96950a37fa1d0f4b4ef7f3a Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 2 Nov 2018 14:21:04 -0700 Subject: chore: address PR comments --- .../src/components/erc20_asset_amount_input.tsx | 33 ++++++++++++---------- packages/instant/src/components/ui/circle.tsx | 1 - packages/instant/src/components/ui/container.tsx | 4 ++- packages/instant/src/redux/async_data.ts | 2 +- packages/instant/src/types.ts | 2 ++ 5 files changed, 24 insertions(+), 18 deletions(-) (limited to 'packages/instant') diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index b27f349c0..5e07dcf2f 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption, transparentWhite } from '../style/theme'; -import { ERC20Asset } from '../types'; +import { ERC20Asset, SimpleHandler } from '../types'; import { assetUtils } from '../util/asset'; import { BigNumberInput } from '../util/big_number_input'; import { util } from '../util/util'; @@ -41,7 +41,7 @@ export class ERC20AssetAmountInput extends React.Component - {_.isUndefined(asset) ? this._renderBackupContent() : this._renderContentForAsset(asset)} + {_.isUndefined(asset) ? this._renderTokenSelectionContent() : this._renderContentForAsset(asset)} ); } @@ -80,11 +80,11 @@ export class ERC20AssetAmountInput extends React.Component ); }; - private readonly _renderBackupContent = (): React.ReactNode => { + private readonly _renderTokenSelectionContent = (): React.ReactNode => { const { numberOfAssetsAvailable } = this.props; let text = 'Select Token'; if (_.isUndefined(numberOfAssetsAvailable)) { - text = '...Loading'; + text = 'Loading...'; } else if (numberOfAssetsAvailable === 0) { text = 'Assets Unavailable'; } @@ -104,13 +104,12 @@ export class ERC20AssetAmountInput extends React.Component { - const { numberOfAssetsAvailable } = this.props; - if (_.isUndefined(numberOfAssetsAvailable) || numberOfAssetsAvailable <= 1) { + if (!this._areMultipleAssetsAvailable()) { return null; } return ( - + ); }; @@ -122,19 +121,23 @@ export class ERC20AssetAmountInput extends React.Component void) | undefined => { + private readonly _generateSelectAssetClickHandler = (): SimpleHandler | 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) - ) { + if (!this._areMultipleAssetsAvailable() || _.isUndefined(this.props.onSelectAssetClick)) { return undefined; } - return () => onSelectAssetClick(this.props.asset); + return this._handleSelectAssetClick; + }; + private readonly _areMultipleAssetsAvailable = (): boolean => { + const { numberOfAssetsAvailable } = this.props; + return !_.isUndefined(numberOfAssetsAvailable) && numberOfAssetsAvailable > 1; + }; + private readonly _handleSelectAssetClick = (): void => { + if (this.props.onSelectAssetClick) { + this.props.onSelectAssetClick(); + } }; // For assets with symbols of different length, // start scaling the input at different character lengths diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx index e7a29d59c..eec2777d2 100644 --- a/packages/instant/src/components/ui/circle.tsx +++ b/packages/instant/src/components/ui/circle.tsx @@ -1,7 +1,6 @@ import { styled } from '../../style/theme'; export interface CircleProps { - className?: string; diameter: number; fillColor?: string; } diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index e228a01b6..a0a187e5f 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -70,7 +70,9 @@ export const Container = &:hover { ${props => props.darkenOnHover - ? `background-color: ${darken(0.05, props.theme[props.backgroundColor || 'white'])}` + ? `background-color: ${ + props.backgroundColor ? darken(0.05, props.theme[props.backgroundColor]) : 'none' + }` : ''}; } `; diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 716558409..0e05c13da 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -27,7 +27,7 @@ export const asyncData = { const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); store.dispatch(actions.setAvailableAssets(assets)); } catch (e) { - const errorMessage = 'Error fetching available assets'; + const errorMessage = 'Could not find any assets'; errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage); // On error, just specify that none are available store.dispatch(actions.setAvailableAssets([])); diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 963a5d656..b4a3aa7c3 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -75,3 +75,5 @@ export enum ZeroExInstantError { AssetMetaDataNotAvailable = 'ASSET_META_DATA_NOT_AVAILABLE', InsufficientETH = 'INSUFFICIENT_ETH', } + +export type SimpleHandler = () => void; -- cgit v1.2.3