From e51f9b3593c86c5ab4ec0ecb7e7ea8a9857a7c74 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 22 Apr 2018 13:02:47 -0400 Subject: Grab price information from crypto compare api --- packages/website/ts/components/wallet/wallet.tsx | 45 +++++++++++++++++++----- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index d1ae38550..44bf69455 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -6,7 +6,7 @@ import { Styles, utils as sharedUtils, } from '@0xproject/react-shared'; -import { BigNumber } from '@0xproject/utils'; +import { BigNumber, logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; import FlatButton from 'material-ui/FlatButton'; import { List, ListItem } from 'material-ui/List'; @@ -37,7 +37,9 @@ import { TokenStateByAddress, } from 'ts/types'; import { backendClient } from 'ts/utils/backend_client'; +import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; +import { errorReporter } from 'ts/utils/error_reporter'; import { utils } from 'ts/utils/utils'; import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles'; @@ -491,15 +493,42 @@ export class Wallet extends React.Component { if (_.isEmpty(tokenAddresses)) { return {}; } - try { - const websiteBackendPriceInfos = await backendClient.getPriceInfosAsync(tokenAddresses); - const addresses = _.map(websiteBackendPriceInfos, info => info.address); - const prices = _.map(websiteBackendPriceInfos, info => new BigNumber(info.price)); - const pricesByAddress = _.zipObject(addresses, prices); - return pricesByAddress; - } catch (err) { + // for each input token address, search for the corresponding symbol in this.props.tokenByAddress, if it exists + // create a mapping from existing symbols -> address + const tokenAddressBySymbol = _.fromPairs( + _.compact( + _.map(tokenAddresses, address => { + const tokenIfExists = _.get(this.props.tokenByAddress, address); + if (!_.isUndefined(tokenIfExists)) { + const symbol = tokenIfExists.symbol; + // the crypto compare api doesn't understand 'WETH' so we need to replace it with 'ETH' + const key = symbol === ETHER_TOKEN_SYMBOL ? ETHER_SYMBOL : symbol; + return [key, address]; + } else { + return undefined; + } + }), + ), + ); + const joinedTokenSymbols = _.keys(tokenAddressBySymbol).join(','); + const url = `${configs.CRYPTO_COMPARE_BASE_URL}/pricemulti?fsyms=${joinedTokenSymbols}&tsyms=USD`; + const response = await fetch(url); + if (response.status !== 200) { + const errorText = `Error requesting url: ${url}, ${response.status}: ${response.statusText}`; + logUtils.log(errorText); + const error = Error(errorText); + // tslint:disable-next-line:no-floating-promises + errorReporter.reportAsync(error); return {}; } + const priceInfoBySymbol = await response.json(); + const priceInfoByAddress = _.mapKeys(priceInfoBySymbol, (value, symbol) => _.get(tokenAddressBySymbol, symbol)); + const result = _.mapValues(priceInfoByAddress, priceInfo => { + const price = _.get(priceInfo, 'USD'); + const priceBigNumber = new BigNumber(price); + return priceBigNumber; + }); + return result; } private _openWrappedEtherActionRow(wrappedEtherDirection: Side) { this.setState({ -- cgit v1.2.3 From fb31c493176ec952f6c3621348e328e38ade2174 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 22 Apr 2018 13:27:16 -0400 Subject: Refactor common fetch logic into fetch_utils --- packages/website/ts/components/wallet/wallet.tsx | 39 ++++++++++++++---------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 44bf69455..3f0a4fdca 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -40,6 +40,7 @@ import { backendClient } from 'ts/utils/backend_client'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { errorReporter } from 'ts/utils/error_reporter'; +import { fetchUtils } from 'ts/utils/fetch_utils'; import { utils } from 'ts/utils/utils'; import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles'; @@ -130,6 +131,7 @@ const FOOTER_ITEM_KEY = 'FOOTER'; const DISCONNECTED_ITEM_KEY = 'DISCONNECTED'; const ETHER_ITEM_KEY = 'ETHER'; const USD_DECIMAL_PLACES = 2; +const CRYPTO_COMPARE_MULTI_ENDPOINT = '/pricemulti'; export class Wallet extends React.Component { private _isUnmounted: boolean; @@ -511,24 +513,29 @@ export class Wallet extends React.Component { ), ); const joinedTokenSymbols = _.keys(tokenAddressBySymbol).join(','); - const url = `${configs.CRYPTO_COMPARE_BASE_URL}/pricemulti?fsyms=${joinedTokenSymbols}&tsyms=USD`; - const response = await fetch(url); - if (response.status !== 200) { - const errorText = `Error requesting url: ${url}, ${response.status}: ${response.statusText}`; - logUtils.log(errorText); - const error = Error(errorText); - // tslint:disable-next-line:no-floating-promises - errorReporter.reportAsync(error); + const baseCurrency = 'USD'; + const queryParams = { + fsyms: joinedTokenSymbols, + tsyms: baseCurrency, + }; + try { + const priceInfoBySymbol = await fetchUtils.requestAsync( + configs.CRYPTO_COMPARE_BASE_URL, + CRYPTO_COMPARE_MULTI_ENDPOINT, + queryParams, + ); + const priceInfoByAddress = _.mapKeys(priceInfoBySymbol, (value, symbol) => + _.get(tokenAddressBySymbol, symbol), + ); + const result = _.mapValues(priceInfoByAddress, priceInfo => { + const price = _.get(priceInfo, baseCurrency); + const priceBigNumber = new BigNumber(price); + return priceBigNumber; + }); + return result; + } catch (err) { return {}; } - const priceInfoBySymbol = await response.json(); - const priceInfoByAddress = _.mapKeys(priceInfoBySymbol, (value, symbol) => _.get(tokenAddressBySymbol, symbol)); - const result = _.mapValues(priceInfoByAddress, priceInfo => { - const price = _.get(priceInfo, 'USD'); - const priceBigNumber = new BigNumber(price); - return priceBigNumber; - }); - return result; } private _openWrappedEtherActionRow(wrappedEtherDirection: Side) { this.setState({ -- cgit v1.2.3 From 121b6949a1e185c0cc9768c2b7042eb3daf124b7 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 22 Apr 2018 14:05:03 -0400 Subject: Rate limit crypto compare calls --- packages/website/ts/components/wallet/wallet.tsx | 28 +++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 3f0a4fdca..231045bc5 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -132,9 +132,12 @@ const DISCONNECTED_ITEM_KEY = 'DISCONNECTED'; const ETHER_ITEM_KEY = 'ETHER'; const USD_DECIMAL_PLACES = 2; const CRYPTO_COMPARE_MULTI_ENDPOINT = '/pricemulti'; +// Crypto compare recommends requesting no more than once every 10s: https://www.cryptocompare.com/api/?javascript#requests +const CRYPTO_COMPARE_UPDATE_INTERVAL_MS = 10 * 1000; export class Wallet extends React.Component { private _isUnmounted: boolean; + private _cryptoCompareLastFetchTimestampMs?: number; constructor(props: WalletProps) { super(props); this._isUnmounted = false; @@ -465,16 +468,27 @@ export class Wallet extends React.Component { ); balanceAndAllowanceTupleByAddress[tokenAddress] = balanceAndAllowanceTuple; } - const pricesByAddress = await this._getPricesByAddressAsync(tokenAddresses); + // if we are allowed to fetch prices do so, if not, keep the old price state + const canFetchPrices = this._canGetPrice(); + let priceByAddress: ItemByAddress = {}; + if (canFetchPrices) { + priceByAddress = await this._getPricesByAddressAsync(tokenAddresses); + } else { + const cachedPricesByAddress = _.mapValues( + this.state.trackedTokenStateByAddress, + tokenState => tokenState.price, + ); + priceByAddress = cachedPricesByAddress; + } const trackedTokenStateByAddress = _.reduce( tokenAddresses, (acc, address) => { const [balance, allowance] = balanceAndAllowanceTupleByAddress[address]; - const price = pricesByAddress[address]; + const priceIfExists = _.get(priceByAddress, address); acc[address] = { balance, allowance, - price, + price: priceIfExists, isLoaded: true, }; return acc; @@ -519,6 +533,7 @@ export class Wallet extends React.Component { tsyms: baseCurrency, }; try { + this._cryptoCompareLastFetchTimestampMs = Date.now(); const priceInfoBySymbol = await fetchUtils.requestAsync( configs.CRYPTO_COMPARE_BASE_URL, CRYPTO_COMPARE_MULTI_ENDPOINT, @@ -537,6 +552,13 @@ export class Wallet extends React.Component { return {}; } } + private _canGetPrice() { + const currentTimeStamp = Date.now(); + const result = + _.isUndefined(this._cryptoCompareLastFetchTimestampMs) || + this._cryptoCompareLastFetchTimestampMs + CRYPTO_COMPARE_UPDATE_INTERVAL_MS < currentTimeStamp; + return result; + } private _openWrappedEtherActionRow(wrappedEtherDirection: Side) { this.setState({ wrappedEtherDirection, -- cgit v1.2.3 From 96568957263858c6832ae972f9df5f02913549c6 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 22 Apr 2018 14:17:34 -0400 Subject: Remove some unused imports --- packages/website/ts/components/wallet/wallet.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 231045bc5..257ea8ac4 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -6,7 +6,7 @@ import { Styles, utils as sharedUtils, } from '@0xproject/react-shared'; -import { BigNumber, logUtils } from '@0xproject/utils'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import FlatButton from 'material-ui/FlatButton'; import { List, ListItem } from 'material-ui/List'; @@ -39,7 +39,6 @@ import { import { backendClient } from 'ts/utils/backend_client'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; -import { errorReporter } from 'ts/utils/error_reporter'; import { fetchUtils } from 'ts/utils/fetch_utils'; import { utils } from 'ts/utils/utils'; import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles'; -- cgit v1.2.3 From 9b535e3cec4073205c1343306829bcdec3168002 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Sun, 22 Apr 2018 14:20:42 -0400 Subject: Rename baseCurrency to quoteCurrency --- packages/website/ts/components/wallet/wallet.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 257ea8ac4..2097c0eab 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -526,10 +526,10 @@ export class Wallet extends React.Component { ), ); const joinedTokenSymbols = _.keys(tokenAddressBySymbol).join(','); - const baseCurrency = 'USD'; + const quoteCurrency = 'USD'; const queryParams = { fsyms: joinedTokenSymbols, - tsyms: baseCurrency, + tsyms: quoteCurrency, }; try { this._cryptoCompareLastFetchTimestampMs = Date.now(); @@ -542,7 +542,7 @@ export class Wallet extends React.Component { _.get(tokenAddressBySymbol, symbol), ); const result = _.mapValues(priceInfoByAddress, priceInfo => { - const price = _.get(priceInfo, baseCurrency); + const price = _.get(priceInfo, quoteCurrency); const priceBigNumber = new BigNumber(price); return priceBigNumber; }); -- cgit v1.2.3 From cc471dd127b3b2b30ebe32452f9dd03778845e7c Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 11:57:55 -0700 Subject: Rename Portal and PortalMenu components to LegacyPortal and LegacyPortalMenu --- .../ts/components/legacy_portal/legacy_portal.tsx | 442 ++++++++++++++++++++ .../legacy_portal/legacy_portal_menu.tsx | 94 +++++ packages/website/ts/components/portal.tsx | 444 --------------------- packages/website/ts/components/portal_menu.tsx | 94 ----- packages/website/ts/components/top_bar/top_bar.tsx | 4 +- 5 files changed, 538 insertions(+), 540 deletions(-) create mode 100644 packages/website/ts/components/legacy_portal/legacy_portal.tsx create mode 100644 packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx delete mode 100644 packages/website/ts/components/portal.tsx delete mode 100644 packages/website/ts/components/portal_menu.tsx (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/legacy_portal/legacy_portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx new file mode 100644 index 000000000..8942e4356 --- /dev/null +++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx @@ -0,0 +1,442 @@ +import { colors } from '@0xproject/react-shared'; +import { BigNumber, logUtils } from '@0xproject/utils'; +import * as _ from 'lodash'; +import CircularProgress from 'material-ui/CircularProgress'; +import Paper from 'material-ui/Paper'; +import * as React from 'react'; +import * as DocumentTitle from 'react-document-title'; +import { Route, Switch } from 'react-router-dom'; +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; +import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; +import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { WrappedEthSectionNoticeDialog } from 'ts/components/dialogs/wrapped_eth_section_notice_dialog'; +import { EthWrappers } from 'ts/components/eth_wrappers'; +import { FillOrder } from 'ts/components/fill_order'; +import { Footer } from 'ts/components/footer'; +import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu'; +import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; +import { TokenBalances } from 'ts/components/token_balances'; +import { TopBar } from 'ts/components/top_bar/top_bar'; +import { TradeHistory } from 'ts/components/trade_history/trade_history'; +import { FlashMessage } from 'ts/components/ui/flash_message'; +import { Wallet } from 'ts/components/wallet/wallet'; +import { GenerateOrderForm } from 'ts/containers/generate_order_form'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; +import { validator } from 'ts/schemas/validator'; +import { + BlockchainErrs, + Environments, + HashData, + Order, + ProviderType, + ScreenWidths, + TokenByAddress, + WebsitePaths, +} from 'ts/types'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; +import { utils } from 'ts/utils/utils'; + +const THROTTLE_TIMEOUT = 100; + +export interface LegacyPortalProps { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + dispatcher: Dispatcher; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + screenWidth: ScreenWidths; + tokenByAddress: TokenByAddress; + userEtherBalanceInWei: BigNumber; + userAddress: string; + shouldBlockchainErrDialogBeOpen: boolean; + userSuppliedOrderCache: Order; + location: Location; + flashMessage?: string | React.ReactNode; + lastForceTokenStateRefetch: number; + translate: Translate; +} + +interface LegacyPortalState { + prevNetworkId: number; + prevNodeVersion: string; + prevUserAddress: string; + prevPathname: string; + isDisclaimerDialogOpen: boolean; + isWethNoticeDialogOpen: boolean; + isLedgerDialogOpen: boolean; +} + +export class LegacyPortal extends React.Component { + private _blockchain: Blockchain; + private _sharedOrderIfExists: Order; + private _throttledScreenWidthUpdate: () => void; + public static hasAlreadyDismissedWethNotice() { + const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE); + const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) && !_.isEmpty(didDismissWethNotice); + return hasAlreadyDismissedWethNotice; + } + constructor(props: LegacyPortalProps) { + super(props); + this._sharedOrderIfExists = this._getSharedOrderIfExists(); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + + const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`); + const hasAlreadyDismissedWethNotice = LegacyPortal.hasAlreadyDismissedWethNotice(); + + const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); + const hasAcceptedDisclaimer = + !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); + this.state = { + prevNetworkId: this.props.networkId, + prevNodeVersion: this.props.nodeVersion, + prevUserAddress: this.props.userAddress, + prevPathname: this.props.location.pathname, + isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances, + isLedgerDialogOpen: false, + }; + } + public componentDidMount() { + window.addEventListener('resize', this._throttledScreenWidthUpdate); + window.scrollTo(0, 0); + } + public componentWillMount() { + this._blockchain = new Blockchain(this.props.dispatcher); + } + public componentWillUnmount() { + this._blockchain.destroy(); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); + // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered + // the initialization process always occurs from the same base state. This helps avoid + // initialization inconsistencies (i.e While the portal was unrendered, the user might have + // become disconnected from their backing Ethereum node, changes user accounts, etc...) + this.props.dispatcher.resetState(); + } + public componentWillReceiveProps(nextProps: LegacyPortalProps) { + if (nextProps.networkId !== this.state.prevNetworkId) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); + this.setState({ + prevNetworkId: nextProps.networkId, + }); + } + if (nextProps.userAddress !== this.state.prevUserAddress) { + const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; + // tslint:disable-next-line:no-floating-promises + this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); + this.setState({ + prevUserAddress: nextProps.userAddress, + }); + } + if (nextProps.nodeVersion !== this.state.prevNodeVersion) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + } + if (nextProps.location.pathname !== this.state.prevPathname) { + const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`); + const hasAlreadyDismissedWethNotice = LegacyPortal.hasAlreadyDismissedWethNotice(); + this.setState({ + prevPathname: nextProps.location.pathname, + isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances, + }); + } + } + public render() { + const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( + this.props.dispatcher, + ); + const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT; + const portalStyle: React.CSSProperties = { + minHeight: '100vh', + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + }; + const portalMenuContainerStyle: React.CSSProperties = { + overflow: 'hidden', + backgroundColor: colors.darkestGrey, + color: colors.white, + }; + return ( +
+ + +
+ + {!configs.IS_MAINNET_ENABLED && this.props.networkId === constants.NETWORK_ID_MAINNET ? ( +
+
Mainnet unavailable
+
+ +
+
+ 0x portal is currently unavailable on the Ethereum mainnet. +
To try it out, switch to the Kovan test network (networkId: 42).
+
Check back soon!
+
+
+ ) : ( +
+
+ +
+
+
+ {this.props.blockchainIsLoaded ? ( + + {isDevelopment && ( + + )} + {isDevelopment && ( + + )} + + + + + + + ) : ( +
+
+
+ +
+
+ Loading Portal... +
+
+
+ )} +
+
+
+ )} +
+ + + + + {this.props.blockchainIsLoaded && ( + + )} +
+
+
+ ); + } + public onToggleLedgerDialog() { + this.setState({ + isLedgerDialogOpen: !this.state.isLedgerDialogOpen, + }); + } + private _renderWallet() { + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( +
+
+ +
+
+ ); + } + private _renderRelayers() { + return ( +
+
+ +
+
+ ); + } + private _renderEthWrapper() { + return ( + + ); + } + private _renderTradeHistory() { + return ( + + ); + } + private _renderTokenBalances() { + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( + + ); + } + private _renderFillOrder(match: any, location: Location, history: History) { + const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) + ? this.props.userSuppliedOrderCache + : this._sharedOrderIfExists; + return ( + + ); + } + private _renderGenerateOrderForm(match: any, location: Location, history: History) { + return ( + + ); + } + private _onPortalDisclaimerAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); + this.setState({ + isDisclaimerDialogOpen: false, + }); + } + private _onWethNoticeAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set'); + this.setState({ + isWethNoticeDialogOpen: false, + }); + } + private _getSharedOrderIfExists(): Order | undefined { + const queryString = window.location.search; + if (queryString.length === 0) { + return undefined; + } + const queryParams = queryString.substring(1).split('&'); + const orderQueryParam = _.find(queryParams, queryParam => { + const queryPair = queryParam.split('='); + return queryPair[0] === 'order'; + }); + if (_.isUndefined(orderQueryParam)) { + return undefined; + } + const orderPair = orderQueryParam.split('='); + if (orderPair.length !== 2) { + return undefined; + } + + const order = JSON.parse(decodeURIComponent(orderPair[1])); + const validationResult = validator.validate(order, portalOrderSchema); + if (validationResult.errors.length > 0) { + logUtils.log(`Invalid shared order: ${validationResult.errors}`); + return undefined; + } + return order; + } + private _updateScreenWidth() { + const newScreenWidth = utils.getScreenWidth(); + this.props.dispatcher.updateScreenWidth(newScreenWidth); + } +} diff --git a/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx b/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx new file mode 100644 index 000000000..634d966ed --- /dev/null +++ b/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx @@ -0,0 +1,94 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { MenuItem } from 'ts/components/ui/menu_item'; +import { Environments, WebsitePaths } from 'ts/types'; +import { configs } from 'ts/utils/configs'; + +export interface LegacyPortalMenuProps { + menuItemStyle: React.CSSProperties; + onClick?: () => void; +} + +interface LegacyPortalMenuState {} + +export class LegacyPortalMenu extends React.Component { + public static defaultProps: Partial = { + onClick: _.noop, + }; + public render() { + return ( +
+ + {this._renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')} + + + {this._renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')} + + + {this._renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')} + + + {this._renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')} + + + {this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')} + + {configs.ENVIRONMENT === Environments.DEVELOPMENT && ( +
+ + {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')} + + + {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')} + +
+ )} +
+ ); + } + private _renderMenuItemWithIcon(title: string, iconName: string) { + return ( +
+
+ +
+
{title}
+
+ ); + } +} diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/portal.tsx deleted file mode 100644 index b79f5e288..000000000 --- a/packages/website/ts/components/portal.tsx +++ /dev/null @@ -1,444 +0,0 @@ -import { colors } from '@0xproject/react-shared'; -import { BigNumber, logUtils } from '@0xproject/utils'; -import * as _ from 'lodash'; -import CircularProgress from 'material-ui/CircularProgress'; -import Paper from 'material-ui/Paper'; -import * as React from 'react'; -import * as DocumentTitle from 'react-document-title'; -import { Route, Switch } from 'react-router-dom'; -import { Blockchain } from 'ts/blockchain'; -import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; -import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; -import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; -import { WrappedEthSectionNoticeDialog } from 'ts/components/dialogs/wrapped_eth_section_notice_dialog'; -import { EthWrappers } from 'ts/components/eth_wrappers'; -import { FillOrder } from 'ts/components/fill_order'; -import { Footer } from 'ts/components/footer'; -import { PortalMenu } from 'ts/components/portal_menu'; -import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; -import { TokenBalances } from 'ts/components/token_balances'; -import { TopBar } from 'ts/components/top_bar/top_bar'; -import { TradeHistory } from 'ts/components/trade_history/trade_history'; -import { FlashMessage } from 'ts/components/ui/flash_message'; -import { Wallet } from 'ts/components/wallet/wallet'; -import { GenerateOrderForm } from 'ts/containers/generate_order_form'; -import { localStorage } from 'ts/local_storage/local_storage'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { portalOrderSchema } from 'ts/schemas/portal_order_schema'; -import { validator } from 'ts/schemas/validator'; -import { - BlockchainErrs, - Environments, - HashData, - Order, - ProviderType, - ScreenWidths, - TokenByAddress, - WebsitePaths, -} from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; -import { utils } from 'ts/utils/utils'; - -const THROTTLE_TIMEOUT = 100; - -export interface PortalPassedProps {} - -export interface PortalAllProps { - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - dispatcher: Dispatcher; - hashData: HashData; - injectedProviderName: string; - networkId: number; - nodeVersion: string; - orderFillAmount: BigNumber; - providerType: ProviderType; - screenWidth: ScreenWidths; - tokenByAddress: TokenByAddress; - userEtherBalanceInWei: BigNumber; - userAddress: string; - shouldBlockchainErrDialogBeOpen: boolean; - userSuppliedOrderCache: Order; - location: Location; - flashMessage?: string | React.ReactNode; - lastForceTokenStateRefetch: number; - translate: Translate; -} - -interface PortalAllState { - prevNetworkId: number; - prevNodeVersion: string; - prevUserAddress: string; - prevPathname: string; - isDisclaimerDialogOpen: boolean; - isWethNoticeDialogOpen: boolean; - isLedgerDialogOpen: boolean; -} - -export class Portal extends React.Component { - private _blockchain: Blockchain; - private _sharedOrderIfExists: Order; - private _throttledScreenWidthUpdate: () => void; - public static hasAlreadyDismissedWethNotice() { - const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE); - const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) && !_.isEmpty(didDismissWethNotice); - return hasAlreadyDismissedWethNotice; - } - constructor(props: PortalAllProps) { - super(props); - this._sharedOrderIfExists = this._getSharedOrderIfExists(); - this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); - - const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`); - const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice(); - - const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); - const hasAcceptedDisclaimer = - !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); - this.state = { - prevNetworkId: this.props.networkId, - prevNodeVersion: this.props.nodeVersion, - prevUserAddress: this.props.userAddress, - prevPathname: this.props.location.pathname, - isDisclaimerDialogOpen: !hasAcceptedDisclaimer, - isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances, - isLedgerDialogOpen: false, - }; - } - public componentDidMount() { - window.addEventListener('resize', this._throttledScreenWidthUpdate); - window.scrollTo(0, 0); - } - public componentWillMount() { - this._blockchain = new Blockchain(this.props.dispatcher); - } - public componentWillUnmount() { - this._blockchain.destroy(); - window.removeEventListener('resize', this._throttledScreenWidthUpdate); - // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered - // the initialization process always occurs from the same base state. This helps avoid - // initialization inconsistencies (i.e While the portal was unrendered, the user might have - // become disconnected from their backing Ethereum node, changes user accounts, etc...) - this.props.dispatcher.resetState(); - } - public componentWillReceiveProps(nextProps: PortalAllProps) { - if (nextProps.networkId !== this.state.prevNetworkId) { - // tslint:disable-next-line:no-floating-promises - this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); - this.setState({ - prevNetworkId: nextProps.networkId, - }); - } - if (nextProps.userAddress !== this.state.prevUserAddress) { - const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; - // tslint:disable-next-line:no-floating-promises - this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); - this.setState({ - prevUserAddress: nextProps.userAddress, - }); - } - if (nextProps.nodeVersion !== this.state.prevNodeVersion) { - // tslint:disable-next-line:no-floating-promises - this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); - } - if (nextProps.location.pathname !== this.state.prevPathname) { - const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`); - const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice(); - this.setState({ - prevPathname: nextProps.location.pathname, - isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances, - }); - } - } - public render() { - const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( - this.props.dispatcher, - ); - const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT; - const portalStyle: React.CSSProperties = { - minHeight: '100vh', - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - }; - const portalMenuContainerStyle: React.CSSProperties = { - overflow: 'hidden', - backgroundColor: colors.darkestGrey, - color: colors.white, - }; - return ( -
- - -
- - {!configs.IS_MAINNET_ENABLED && this.props.networkId === constants.NETWORK_ID_MAINNET ? ( -
-
Mainnet unavailable
-
- -
-
- 0x portal is currently unavailable on the Ethereum mainnet. -
To try it out, switch to the Kovan test network (networkId: 42).
-
Check back soon!
-
-
- ) : ( -
-
- -
-
-
- {this.props.blockchainIsLoaded ? ( - - {isDevelopment && ( - - )} - {isDevelopment && ( - - )} - - - - - - - ) : ( -
-
-
- -
-
- Loading Portal... -
-
-
- )} -
-
-
- )} -
- - - - - {this.props.blockchainIsLoaded && ( - - )} -
-
-
- ); - } - public onToggleLedgerDialog() { - this.setState({ - isLedgerDialogOpen: !this.state.isLedgerDialogOpen, - }); - } - private _renderWallet() { - const allTokens = _.values(this.props.tokenByAddress); - const trackedTokens = _.filter(allTokens, t => t.isTracked); - return ( -
-
- -
-
- ); - } - private _renderRelayers() { - return ( -
-
- -
-
- ); - } - private _renderEthWrapper() { - return ( - - ); - } - private _renderTradeHistory() { - return ( - - ); - } - private _renderTokenBalances() { - const allTokens = _.values(this.props.tokenByAddress); - const trackedTokens = _.filter(allTokens, t => t.isTracked); - return ( - - ); - } - private _renderFillOrder(match: any, location: Location, history: History) { - const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) - ? this.props.userSuppliedOrderCache - : this._sharedOrderIfExists; - return ( - - ); - } - private _renderGenerateOrderForm(match: any, location: Location, history: History) { - return ( - - ); - } - private _onPortalDisclaimerAccepted() { - localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); - this.setState({ - isDisclaimerDialogOpen: false, - }); - } - private _onWethNoticeAccepted() { - localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set'); - this.setState({ - isWethNoticeDialogOpen: false, - }); - } - private _getSharedOrderIfExists(): Order | undefined { - const queryString = window.location.search; - if (queryString.length === 0) { - return undefined; - } - const queryParams = queryString.substring(1).split('&'); - const orderQueryParam = _.find(queryParams, queryParam => { - const queryPair = queryParam.split('='); - return queryPair[0] === 'order'; - }); - if (_.isUndefined(orderQueryParam)) { - return undefined; - } - const orderPair = orderQueryParam.split('='); - if (orderPair.length !== 2) { - return undefined; - } - - const order = JSON.parse(decodeURIComponent(orderPair[1])); - const validationResult = validator.validate(order, portalOrderSchema); - if (validationResult.errors.length > 0) { - logUtils.log(`Invalid shared order: ${validationResult.errors}`); - return undefined; - } - return order; - } - private _updateScreenWidth() { - const newScreenWidth = utils.getScreenWidth(); - this.props.dispatcher.updateScreenWidth(newScreenWidth); - } -} diff --git a/packages/website/ts/components/portal_menu.tsx b/packages/website/ts/components/portal_menu.tsx deleted file mode 100644 index 2b4d7eea2..000000000 --- a/packages/website/ts/components/portal_menu.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import * as _ from 'lodash'; -import * as React from 'react'; -import { MenuItem } from 'ts/components/ui/menu_item'; -import { Environments, WebsitePaths } from 'ts/types'; -import { configs } from 'ts/utils/configs'; - -export interface PortalMenuProps { - menuItemStyle: React.CSSProperties; - onClick?: () => void; -} - -interface PortalMenuState {} - -export class PortalMenu extends React.Component { - public static defaultProps: Partial = { - onClick: _.noop, - }; - public render() { - return ( -
- - {this._renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')} - - - {this._renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')} - - - {this._renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')} - - - {this._renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')} - - - {this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')} - - {configs.ENVIRONMENT === Environments.DEVELOPMENT && ( -
- - {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')} - - - {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')} - -
- )} -
- ); - } - private _renderMenuItemWithIcon(title: string, iconName: string) { - return ( -
-
- -
-
{title}
-
- ); - } -} diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 13351dcdc..0c32f4c62 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import { Link } from 'react-router-dom'; import ReactTooltip = require('react-tooltip'); import { Blockchain } from 'ts/blockchain'; -import { PortalMenu } from 'ts/components/portal_menu'; +import { LegacyPortalMenu } from 'ts/components/legacy_portal/legacy_portal_menu'; import { SidebarHeader } from 'ts/components/sidebar_header'; import { ProviderDisplay } from 'ts/components/top_bar/provider_display'; import { TopBarMenuItem } from 'ts/components/top_bar/top_bar_menu_item'; @@ -431,7 +431,7 @@ export class TopBar extends React.Component {
{this.props.translate.get(Key.PortalDApp, Deco.CapWords)}
- + ); } -- cgit v1.2.3 From 11f1ccf3ff92d5d1e32e0451ffd5069615e29867 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:07:48 -0700 Subject: Lay out wallet and relayers --- packages/website/ts/components/portal/portal.tsx | 214 +++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 packages/website/ts/components/portal/portal.tsx (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx new file mode 100644 index 000000000..8a9e89a72 --- /dev/null +++ b/packages/website/ts/components/portal/portal.tsx @@ -0,0 +1,214 @@ +import { colors, Styles } from '@0xproject/react-shared'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as DocumentTitle from 'react-document-title'; + +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; +import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; +import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; +import { TopBar } from 'ts/components/top_bar/top_bar'; +import { FlashMessage } from 'ts/components/ui/flash_message'; +import { Wallet } from 'ts/components/wallet/wallet'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; +import { utils } from 'ts/utils/utils'; + +export interface PortalProps { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + dispatcher: Dispatcher; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + screenWidth: ScreenWidths; + tokenByAddress: TokenByAddress; + userEtherBalanceInWei: BigNumber; + userAddress: string; + shouldBlockchainErrDialogBeOpen: boolean; + userSuppliedOrderCache: Order; + location: Location; + flashMessage?: string | React.ReactNode; + lastForceTokenStateRefetch: number; + translate: Translate; +} + +interface PortalState { + prevNetworkId: number; + prevNodeVersion: string; + prevUserAddress: string; + prevPathname: string; + isDisclaimerDialogOpen: boolean; + isLedgerDialogOpen: boolean; +} + +const THROTTLE_TIMEOUT = 100; +const TOP_BAR_HEIGHT = 60; + +const styles: Styles = { + root: { + width: '100%', + height: '100%', + backgroundColor: colors.lightestGrey, + }, + body: { + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + }, +}; + +export class Portal extends React.Component { + private _blockchain: Blockchain; + private _throttledScreenWidthUpdate: () => void; + constructor(props: PortalProps) { + super(props); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); + const hasAcceptedDisclaimer = + !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); + this.state = { + prevNetworkId: this.props.networkId, + prevNodeVersion: this.props.nodeVersion, + prevUserAddress: this.props.userAddress, + prevPathname: this.props.location.pathname, + isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isLedgerDialogOpen: false, + }; + } + public componentDidMount() { + window.addEventListener('resize', this._throttledScreenWidthUpdate); + window.scrollTo(0, 0); + } + public componentWillMount() { + this._blockchain = new Blockchain(this.props.dispatcher); + } + public componentWillUnmount() { + this._blockchain.destroy(); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); + // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered + // the initialization process always occurs from the same base state. This helps avoid + // initialization inconsistencies (i.e While the portal was unrendered, the user might have + // become disconnected from their backing Ethereum node, changes user accounts, etc...) + this.props.dispatcher.resetState(); + } + public componentWillReceiveProps(nextProps: PortalProps) { + if (nextProps.networkId !== this.state.prevNetworkId) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); + this.setState({ + prevNetworkId: nextProps.networkId, + }); + } + if (nextProps.userAddress !== this.state.prevUserAddress) { + const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; + // tslint:disable-next-line:no-floating-promises + this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); + this.setState({ + prevUserAddress: nextProps.userAddress, + }); + } + if (nextProps.nodeVersion !== this.state.prevNodeVersion) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + } + if (nextProps.location.pathname !== this.state.prevPathname) { + this.setState({ + prevPathname: nextProps.location.pathname, + }); + } + } + public render() { + const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( + this.props.dispatcher, + ); + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( +
+ + +
+
+
+ +
+
+ +
+
+ + + + {this.props.blockchainIsLoaded && ( + + )} +
+
+ ); + } + private _onToggleLedgerDialog() { + this.setState({ + isLedgerDialogOpen: !this.state.isLedgerDialogOpen, + }); + } + private _onPortalDisclaimerAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); + this.setState({ + isDisclaimerDialogOpen: false, + }); + } + private _updateScreenWidth() { + const newScreenWidth = utils.getScreenWidth(); + this.props.dispatcher.updateScreenWidth(newScreenWidth); + } +} -- cgit v1.2.3 From deaa5f3211d75e81dd7e0820686a5f6a9b26f9d4 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:45:05 -0700 Subject: Add scrolling to relayer index --- packages/website/ts/components/portal/portal.tsx | 8 +++++++- packages/website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 8a9e89a72..6939d8905 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -62,6 +62,12 @@ const styles: Styles = { body: { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, + scrollContainer: { + overflowZ: 'hidden', + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + WebkitOverflowScrolling: 'touch', + overflow: 'auto', + }, }; export class Portal extends React.Component { @@ -165,7 +171,7 @@ export class Portal extends React.Component { onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} /> -
+
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index 50760c32d..ba0db7c47 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Mon, 23 Apr 2018 22:17:26 -0700 Subject: Add headers to wallet and relayer index --- packages/website/ts/components/portal/portal.tsx | 12 +++++++++++- .../website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 6939d8905..507860ee6 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -68,6 +68,10 @@ const styles: Styles = { WebkitOverflowScrolling: 'touch', overflow: 'auto', }, + title: { + fontWeight: 'bold', + fontSize: 20, + }, }; export class Portal extends React.Component { @@ -154,7 +158,10 @@ export class Portal extends React.Component { />
-
+
+
+ Your Account +
{ />
+
+ Explore 0x Ecosystem +
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index ba0db7c47..50760c32d 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Mon, 23 Apr 2018 23:47:04 -0700 Subject: Relayer grid spacing tweaks --- packages/website/ts/components/relayer_index/relayer_index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index 50760c32d..1e92dba85 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -32,9 +32,9 @@ const styles: Styles = { }, }; -const CELL_HEIGHT = 260; +const CELL_HEIGHT = 290; const NUMBER_OF_COLUMNS = 4; -const GRID_PADDING = 16; +const GRID_PADDING = 20; export class RelayerIndex extends React.Component { private _isUnmounted: boolean; -- cgit v1.2.3 From 9c827a0298df3e54e8b18e9f38b1d4027d2b5d83 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 23:47:37 -0700 Subject: Top bar expanded display type --- packages/website/ts/components/portal/portal.tsx | 5 ++- packages/website/ts/components/top_bar/top_bar.tsx | 45 ++++++++++++++-------- 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 507860ee6..bf12c924f 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -9,7 +9,7 @@ import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; -import { TopBar } from 'ts/components/top_bar/top_bar'; +import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar'; import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; @@ -51,7 +51,7 @@ interface PortalState { } const THROTTLE_TIMEOUT = 100; -const TOP_BAR_HEIGHT = 60; +const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); const styles: Styles = { root: { @@ -154,6 +154,7 @@ export class Portal extends React.Component { location={this.props.location} blockchain={this._blockchain} translate={this.props.translate} + displayType={TopBarDisplayType.Expanded} style={{ backgroundColor: colors.lightestGrey }} />
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 0c32f4c62..eecec92fb 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -19,7 +19,12 @@ import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/ty import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; -interface TopBarProps { +export enum TopBarDisplayType { + Default, + Expanded, +} + +export interface TopBarProps { userAddress?: string; networkId?: number; injectedProviderName?: string; @@ -34,7 +39,7 @@ interface TopBarProps { availableDocVersions?: string[]; menu?: DocsMenu; menuSubsectionsBySection?: MenuSubsectionsBySection; - shouldFullWidth?: boolean; + displayType?: TopBarDisplayType; docsInfo?: DocsInfo; style?: React.CSSProperties; isNightVersion?: boolean; @@ -56,8 +61,7 @@ const styles: Styles = { width: 70, }, topBar: { - backgroundcolor: colors.white, - height: 59, + backgroundColor: colors.white, width: '100%', position: 'relative', top: 0, @@ -78,12 +82,19 @@ const styles: Styles = { }, }; +const DEFAULT_HEIGHT = 59; +const EXPANDED_HEIGHT = 75; + export class TopBar extends React.Component { public static defaultProps: Partial = { - shouldFullWidth: false, + displayType: TopBarDisplayType.Default, style: {}, isNightVersion: false, }; + public static heightForDisplayType(displayType: TopBarDisplayType) { + const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT; + return result + 1; + } constructor(props: TopBarProps) { super(props); this.state = { @@ -92,8 +103,9 @@ export class TopBar extends React.Component { } public render() { const isNightVersion = this.props.isNightVersion; - const isFullWidthPage = this.props.shouldFullWidth; - const parentClassNames = `flex mx-auto ${isFullWidthPage ? 'pl2' : 'max-width-4'}`; + const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded; + const parentClassNames = `flex mx-auto ${isExpandedDisplayType ? 'pl3 py1' : 'max-width-4'}`; + const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT; const developerSectionMenuItems = [ @@ -172,9 +184,11 @@ export class TopBar extends React.Component { , ]; const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {}; - const fullWidthClasses = isFullWidthPage ? 'pr4' : ''; + const fullWidthClasses = isExpandedDisplayType ? 'pr4' : ''; const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png'; - const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`; + const menuClasses = `col col-${ + isExpandedDisplayType ? '4' : '5' + } ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`; const menuIconStyle = { fontSize: 25, color: isNightVersion ? 'white' : 'black', @@ -191,15 +205,15 @@ export class TopBar extends React.Component { ); const popoverContent = {developerSectionMenuItems}; return ( -
+
-
-
+
+
{!this._isViewingPortal() && (
@@ -236,7 +250,7 @@ export class TopBar extends React.Component { path={`${WebsitePaths.Portal}`} isPrimary={true} style={styles.menuItem} - className={`${isFullWidthPage && 'md-hide'}`} + className={`${isExpandedDisplayType && 'md-hide'}`} isNightVersion={isNightVersion} isExternal={false} /> @@ -256,7 +270,7 @@ export class TopBar extends React.Component { />
)} -
+
@@ -505,7 +519,8 @@ export class TopBar extends React.Component { this._isViewingJsonSchemasDocs() || this._isViewingSolCovDocs() || this._isViewingSubprovidersDocs() || - this._isViewingConnectDocs() + this._isViewingConnectDocs() || + this._isViewingPortal() ); } } // tslint:disable:max-file-line-count -- cgit v1.2.3 From b8c611de2b82657a274c55007ffc5d72807eae7f Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 24 Apr 2018 01:04:57 -0700 Subject: ProviderDisplay changes --- .../ts/components/top_bar/provider_display.tsx | 40 +++++++++++++++------- packages/website/ts/components/top_bar/top_bar.tsx | 25 +------------- 2 files changed, 28 insertions(+), 37 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index 221c34f8c..fa5609014 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -1,4 +1,4 @@ -import { colors } from '@0xproject/react-shared'; +import { colors, Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; @@ -11,9 +11,9 @@ import { ProviderType } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; -const IDENTICON_DIAMETER = 32; +const IDENTICON_DIAMETER = 24; -interface ProviderDisplayProps { +export interface ProviderDisplayProps { dispatcher: Dispatcher; userAddress: string; networkId: number; @@ -25,6 +25,18 @@ interface ProviderDisplayProps { interface ProviderDisplayState {} +const styles: Styles = { + root: { + height: 24, + backgroundColor: colors.white, + borderBottomRightRadius: 24, + borderBottomLeftRadius: 24, + borderTopRightRadius: 24, + borderTopLeftRadius: 24, + boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`, + }, +}; + export class ProviderDisplay extends React.Component { public render() { const isAddressAvailable = !_.isEmpty(this.props.userAddress); @@ -40,21 +52,23 @@ export class ProviderDisplay extends React.Component +
-
-
{providerTitle}
-
{displayAddress}
-
-
- +
+
{displayAddress}
+ {isProviderMetamask && ( +
+ +
+ )}
); const hasInjectedProvider = diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index eecec92fb..8c842d2a5 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -52,14 +52,6 @@ interface TopBarState { } const styles: Styles = { - address: { - marginRight: 12, - overflow: 'hidden', - paddingTop: 4, - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - width: 70, - }, topBar: { backgroundColor: colors.white, width: '100%', @@ -258,7 +250,7 @@ export class TopBar extends React.Component {
)} {this.props.blockchainIsLoaded && ( -
+
{
); } - private _renderUser() { - const userAddress = this.props.userAddress; - const identiconDiameter = 26; - return ( -
-
- {!_.isEmpty(userAddress) ? userAddress : ''} -
- {userAddress} -
- -
-
- ); - } private _onMenuButtonClick() { this.setState({ isDrawerOpen: !this.state.isDrawerOpen, -- cgit v1.2.3 From feb7dfffa107211e76b87d2028b8c821e914f0d6 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 27 Apr 2018 14:59:22 -0700 Subject: Move quote currency string into config --- packages/website/ts/components/wallet/wallet.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 2097c0eab..33b8bbffb 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -526,10 +526,9 @@ export class Wallet extends React.Component { ), ); const joinedTokenSymbols = _.keys(tokenAddressBySymbol).join(','); - const quoteCurrency = 'USD'; const queryParams = { fsyms: joinedTokenSymbols, - tsyms: quoteCurrency, + tsyms: configs.FIAT_QUOTE_CURRENCY_SYMBOL, }; try { this._cryptoCompareLastFetchTimestampMs = Date.now(); @@ -542,7 +541,7 @@ export class Wallet extends React.Component { _.get(tokenAddressBySymbol, symbol), ); const result = _.mapValues(priceInfoByAddress, priceInfo => { - const price = _.get(priceInfo, quoteCurrency); + const price = _.get(priceInfo, configs.FIAT_QUOTE_CURRENCY_SYMBOL); const priceBigNumber = new BigNumber(price); return priceBigNumber; }); -- cgit v1.2.3 From 2403323463be66166dae9f8ca7903caab2546717 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 27 Apr 2018 15:01:19 -0700 Subject: Style suggestions --- packages/website/ts/components/wallet/wallet.tsx | 25 ++++++++++-------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 33b8bbffb..51399ae0b 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -510,21 +510,16 @@ export class Wallet extends React.Component { } // for each input token address, search for the corresponding symbol in this.props.tokenByAddress, if it exists // create a mapping from existing symbols -> address - const tokenAddressBySymbol = _.fromPairs( - _.compact( - _.map(tokenAddresses, address => { - const tokenIfExists = _.get(this.props.tokenByAddress, address); - if (!_.isUndefined(tokenIfExists)) { - const symbol = tokenIfExists.symbol; - // the crypto compare api doesn't understand 'WETH' so we need to replace it with 'ETH' - const key = symbol === ETHER_TOKEN_SYMBOL ? ETHER_SYMBOL : symbol; - return [key, address]; - } else { - return undefined; - } - }), - ), - ); + const tokenAddressBySymbol: { [symbol: string]: string } = {}; + _.each(tokenAddresses, address => { + const tokenIfExists = _.get(this.props.tokenByAddress, address); + if (!_.isUndefined(tokenIfExists)) { + const symbol = tokenIfExists.symbol; + // the crypto compare api doesn't understand 'WETH' so we need to replace it with 'ETH' + const key = symbol === ETHER_TOKEN_SYMBOL ? ETHER_SYMBOL : symbol; + tokenAddressBySymbol[key] = address; + } + }); const joinedTokenSymbols = _.keys(tokenAddressBySymbol).join(','); const queryParams = { fsyms: joinedTokenSymbols, -- cgit v1.2.3 From 1131d66b3db2bde04b5108d710801fab7eaf0ede Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 30 Apr 2018 16:36:42 -0700 Subject: Hit website backend for price information --- packages/website/ts/components/wallet/wallet.tsx | 46 ++++-------------------- 1 file changed, 6 insertions(+), 40 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 51399ae0b..9022eb1c9 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -37,9 +37,7 @@ import { TokenStateByAddress, } from 'ts/types'; import { backendClient } from 'ts/utils/backend_client'; -import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; -import { fetchUtils } from 'ts/utils/fetch_utils'; import { utils } from 'ts/utils/utils'; import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles'; @@ -130,13 +128,9 @@ const FOOTER_ITEM_KEY = 'FOOTER'; const DISCONNECTED_ITEM_KEY = 'DISCONNECTED'; const ETHER_ITEM_KEY = 'ETHER'; const USD_DECIMAL_PLACES = 2; -const CRYPTO_COMPARE_MULTI_ENDPOINT = '/pricemulti'; -// Crypto compare recommends requesting no more than once every 10s: https://www.cryptocompare.com/api/?javascript#requests -const CRYPTO_COMPARE_UPDATE_INTERVAL_MS = 10 * 1000; export class Wallet extends React.Component { private _isUnmounted: boolean; - private _cryptoCompareLastFetchTimestampMs?: number; constructor(props: WalletProps) { super(props); this._isUnmounted = false; @@ -467,18 +461,7 @@ export class Wallet extends React.Component { ); balanceAndAllowanceTupleByAddress[tokenAddress] = balanceAndAllowanceTuple; } - // if we are allowed to fetch prices do so, if not, keep the old price state - const canFetchPrices = this._canGetPrice(); - let priceByAddress: ItemByAddress = {}; - if (canFetchPrices) { - priceByAddress = await this._getPricesByAddressAsync(tokenAddresses); - } else { - const cachedPricesByAddress = _.mapValues( - this.state.trackedTokenStateByAddress, - tokenState => tokenState.price, - ); - priceByAddress = cachedPricesByAddress; - } + const priceByAddress = await this._getPriceByAddressAsync(tokenAddresses); const trackedTokenStateByAddress = _.reduce( tokenAddresses, (acc, address) => { @@ -504,7 +487,7 @@ export class Wallet extends React.Component { private async _refetchTokenStateAsync(tokenAddress: string) { await this._fetchBalancesAndAllowancesAsync([tokenAddress]); } - private async _getPricesByAddressAsync(tokenAddresses: string[]): Promise> { + private async _getPriceByAddressAsync(tokenAddresses: string[]): Promise> { if (_.isEmpty(tokenAddresses)) { return {}; } @@ -520,23 +503,13 @@ export class Wallet extends React.Component { tokenAddressBySymbol[key] = address; } }); - const joinedTokenSymbols = _.keys(tokenAddressBySymbol).join(','); - const queryParams = { - fsyms: joinedTokenSymbols, - tsyms: configs.FIAT_QUOTE_CURRENCY_SYMBOL, - }; + const tokenSymbols = _.keys(tokenAddressBySymbol); try { - this._cryptoCompareLastFetchTimestampMs = Date.now(); - const priceInfoBySymbol = await fetchUtils.requestAsync( - configs.CRYPTO_COMPARE_BASE_URL, - CRYPTO_COMPARE_MULTI_ENDPOINT, - queryParams, - ); - const priceInfoByAddress = _.mapKeys(priceInfoBySymbol, (value, symbol) => + const priceBySymbol = await backendClient.getPriceInfoAsync(tokenSymbols); + const priceByAddress = _.mapKeys(priceBySymbol, (value, symbol) => _.get(tokenAddressBySymbol, symbol), ); - const result = _.mapValues(priceInfoByAddress, priceInfo => { - const price = _.get(priceInfo, configs.FIAT_QUOTE_CURRENCY_SYMBOL); + const result = _.mapValues(priceByAddress, price => { const priceBigNumber = new BigNumber(price); return priceBigNumber; }); @@ -545,13 +518,6 @@ export class Wallet extends React.Component { return {}; } } - private _canGetPrice() { - const currentTimeStamp = Date.now(); - const result = - _.isUndefined(this._cryptoCompareLastFetchTimestampMs) || - this._cryptoCompareLastFetchTimestampMs + CRYPTO_COMPARE_UPDATE_INTERVAL_MS < currentTimeStamp; - return result; - } private _openWrappedEtherActionRow(wrappedEtherDirection: Side) { this.setState({ wrappedEtherDirection, -- cgit v1.2.3 From 3a1f9d01e8cdb40fbb293de10046fa654434dde4 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 30 Apr 2018 16:49:47 -0700 Subject: Remove WETH special case, website backend handles this now --- packages/website/ts/components/wallet/wallet.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 9022eb1c9..057c712e5 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -498,17 +498,13 @@ export class Wallet extends React.Component { const tokenIfExists = _.get(this.props.tokenByAddress, address); if (!_.isUndefined(tokenIfExists)) { const symbol = tokenIfExists.symbol; - // the crypto compare api doesn't understand 'WETH' so we need to replace it with 'ETH' - const key = symbol === ETHER_TOKEN_SYMBOL ? ETHER_SYMBOL : symbol; - tokenAddressBySymbol[key] = address; + tokenAddressBySymbol[symbol] = address; } }); const tokenSymbols = _.keys(tokenAddressBySymbol); try { const priceBySymbol = await backendClient.getPriceInfoAsync(tokenSymbols); - const priceByAddress = _.mapKeys(priceBySymbol, (value, symbol) => - _.get(tokenAddressBySymbol, symbol), - ); + const priceByAddress = _.mapKeys(priceBySymbol, (value, symbol) => _.get(tokenAddressBySymbol, symbol)); const result = _.mapValues(priceByAddress, price => { const priceBigNumber = new BigNumber(price); return priceBigNumber; -- cgit v1.2.3 From 5e3576ed695ce0aaff7d7b59d77380f68e334df1 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 2 May 2018 17:03:36 -0700 Subject: Remove id property from WebsiteBackendRelayerInfo --- packages/website/ts/components/relayer_index/relayer_index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index 50760c32d..c1ab4227a 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -66,7 +66,7 @@ export class RelayerIndex extends React.Component {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo) => ( -- cgit v1.2.3 From cf9555debc445f6645cfdf4e9835247abc084638 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 3 May 2018 12:35:21 +0200 Subject: Fix logo left padding on mobile --- packages/website/ts/components/top_bar/top_bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 0c32f4c62..95e6276bf 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -193,7 +193,7 @@ export class TopBar extends React.Component { return (
-
+
-- cgit v1.2.3 From fe0f4ae25759eb6b6cad8c6608ebff526366c059 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 2 May 2018 20:42:17 -0700 Subject: Add header images to relayer grid tiles --- .../website/ts/components/relayer_index/relayer_grid_tile.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 0c4b2841c..7d0551581 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -12,8 +12,7 @@ export interface RelayerGridTileProps { networkId: number; } -// TODO: Get top tokens and headerurl from remote -const headerUrl = '/images/og_image.png'; +// TODO: Get top tokens from remote const topTokens = [ { address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba', @@ -68,6 +67,9 @@ const styles: Styles = { borderBottomLeftRadius: 4, borderTopRightRadius: 4, borderTopLeftRadius: 4, + borderWidth: 1, + borderStyle: 'solid', + borderColor: colors.walletBorder, }, body: { paddingLeft: 6, @@ -95,7 +97,7 @@ export const RelayerGridTile: React.StatelessComponent = ( return (
- +
{props.relayerInfo.name} -- cgit v1.2.3 From 6b92ef733c6f1cfd1772433abfdc9fd82227fa8b Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 3 May 2018 13:06:39 -0700 Subject: Open relayer app when clicking on grid tile --- .../components/relayer_index/relayer_grid_tile.tsx | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 7d0551581..0b9b8165e 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -94,24 +94,27 @@ const styles: Styles = { }; export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { + const link = props.relayerInfo.appUrl || props.relayerInfo.url; return ( - -
- -
-
- {props.relayerInfo.name} -
-
{props.relayerInfo.dailyTxnVolume}
-
- Daily Trade Volume -
- - - + + ); }; -- cgit v1.2.3 From 01dd84dced8d885f6b164cab714ecfde4d0a363e Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Fri, 4 May 2018 11:57:34 +0200 Subject: Add order utils docs to the menu --- packages/website/ts/components/top_bar/top_bar.tsx | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 95e6276bf..8bea58b0a 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -139,6 +139,12 @@ export class TopBar extends React.Component { primaryText={this.props.translate.get(Key.Web3Wrapper, Deco.CapWords)} /> , + + + , Date: Mon, 23 Apr 2018 21:07:48 -0700 Subject: Lay out wallet and relayers --- packages/website/ts/components/portal/portal.tsx | 214 +++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 packages/website/ts/components/portal/portal.tsx (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx new file mode 100644 index 000000000..8a9e89a72 --- /dev/null +++ b/packages/website/ts/components/portal/portal.tsx @@ -0,0 +1,214 @@ +import { colors, Styles } from '@0xproject/react-shared'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as DocumentTitle from 'react-document-title'; + +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; +import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; +import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; +import { TopBar } from 'ts/components/top_bar/top_bar'; +import { FlashMessage } from 'ts/components/ui/flash_message'; +import { Wallet } from 'ts/components/wallet/wallet'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; +import { utils } from 'ts/utils/utils'; + +export interface PortalProps { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + dispatcher: Dispatcher; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + screenWidth: ScreenWidths; + tokenByAddress: TokenByAddress; + userEtherBalanceInWei: BigNumber; + userAddress: string; + shouldBlockchainErrDialogBeOpen: boolean; + userSuppliedOrderCache: Order; + location: Location; + flashMessage?: string | React.ReactNode; + lastForceTokenStateRefetch: number; + translate: Translate; +} + +interface PortalState { + prevNetworkId: number; + prevNodeVersion: string; + prevUserAddress: string; + prevPathname: string; + isDisclaimerDialogOpen: boolean; + isLedgerDialogOpen: boolean; +} + +const THROTTLE_TIMEOUT = 100; +const TOP_BAR_HEIGHT = 60; + +const styles: Styles = { + root: { + width: '100%', + height: '100%', + backgroundColor: colors.lightestGrey, + }, + body: { + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + }, +}; + +export class Portal extends React.Component { + private _blockchain: Blockchain; + private _throttledScreenWidthUpdate: () => void; + constructor(props: PortalProps) { + super(props); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); + const hasAcceptedDisclaimer = + !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); + this.state = { + prevNetworkId: this.props.networkId, + prevNodeVersion: this.props.nodeVersion, + prevUserAddress: this.props.userAddress, + prevPathname: this.props.location.pathname, + isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isLedgerDialogOpen: false, + }; + } + public componentDidMount() { + window.addEventListener('resize', this._throttledScreenWidthUpdate); + window.scrollTo(0, 0); + } + public componentWillMount() { + this._blockchain = new Blockchain(this.props.dispatcher); + } + public componentWillUnmount() { + this._blockchain.destroy(); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); + // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered + // the initialization process always occurs from the same base state. This helps avoid + // initialization inconsistencies (i.e While the portal was unrendered, the user might have + // become disconnected from their backing Ethereum node, changes user accounts, etc...) + this.props.dispatcher.resetState(); + } + public componentWillReceiveProps(nextProps: PortalProps) { + if (nextProps.networkId !== this.state.prevNetworkId) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); + this.setState({ + prevNetworkId: nextProps.networkId, + }); + } + if (nextProps.userAddress !== this.state.prevUserAddress) { + const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress; + // tslint:disable-next-line:no-floating-promises + this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress); + this.setState({ + prevUserAddress: nextProps.userAddress, + }); + } + if (nextProps.nodeVersion !== this.state.prevNodeVersion) { + // tslint:disable-next-line:no-floating-promises + this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + } + if (nextProps.location.pathname !== this.state.prevPathname) { + this.setState({ + prevPathname: nextProps.location.pathname, + }); + } + } + public render() { + const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( + this.props.dispatcher, + ); + const allTokens = _.values(this.props.tokenByAddress); + const trackedTokens = _.filter(allTokens, t => t.isTracked); + return ( +
+ + +
+
+
+ +
+
+ +
+
+ + + + {this.props.blockchainIsLoaded && ( + + )} +
+
+ ); + } + private _onToggleLedgerDialog() { + this.setState({ + isLedgerDialogOpen: !this.state.isLedgerDialogOpen, + }); + } + private _onPortalDisclaimerAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); + this.setState({ + isDisclaimerDialogOpen: false, + }); + } + private _updateScreenWidth() { + const newScreenWidth = utils.getScreenWidth(); + this.props.dispatcher.updateScreenWidth(newScreenWidth); + } +} -- cgit v1.2.3 From 14b29172b1713610c80ccf5b7390f7b445b0eb75 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 21:45:05 -0700 Subject: Add scrolling to relayer index --- packages/website/ts/components/portal/portal.tsx | 8 +++++++- packages/website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 8a9e89a72..6939d8905 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -62,6 +62,12 @@ const styles: Styles = { body: { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, + scrollContainer: { + overflowZ: 'hidden', + height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, + WebkitOverflowScrolling: 'touch', + overflow: 'auto', + }, }; export class Portal extends React.Component { @@ -165,7 +171,7 @@ export class Portal extends React.Component { onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} />
-
+
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index c1ab4227a..e8775e1a5 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Mon, 23 Apr 2018 22:17:26 -0700 Subject: Add headers to wallet and relayer index --- packages/website/ts/components/portal/portal.tsx | 12 +++++++++++- .../website/ts/components/relayer_index/relayer_index.tsx | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 6939d8905..507860ee6 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -68,6 +68,10 @@ const styles: Styles = { WebkitOverflowScrolling: 'touch', overflow: 'auto', }, + title: { + fontWeight: 'bold', + fontSize: 20, + }, }; export class Portal extends React.Component { @@ -154,7 +158,10 @@ export class Portal extends React.Component { />
-
+
+
+ Your Account +
{ />
+
+ Explore 0x Ecosystem +
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index e8775e1a5..c1ab4227a 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -57,7 +57,7 @@ export class RelayerIndex extends React.Component +
Date: Sat, 5 May 2018 01:26:02 +0200 Subject: Fix type errors in CSS properties --- packages/website/ts/components/top_bar/top_bar.tsx | 2 +- packages/website/ts/components/ui/input_label.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 8bea58b0a..7fb476ba0 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -56,7 +56,7 @@ const styles: Styles = { width: 70, }, topBar: { - backgroundcolor: colors.white, + backgroundColor: colors.white, height: 59, width: '100%', position: 'relative', diff --git a/packages/website/ts/components/ui/input_label.tsx b/packages/website/ts/components/ui/input_label.tsx index 6a3f26155..8137c0db6 100644 --- a/packages/website/ts/components/ui/input_label.tsx +++ b/packages/website/ts/components/ui/input_label.tsx @@ -17,7 +17,7 @@ const styles = { userSelect: 'none', width: 240, zIndex: 1, - }, + } as React.CSSProperties, }; export const InputLabel = (props: InputLabelProps) => { -- cgit v1.2.3 From a44874d2eb1dd9bf721c3d86f65c2e2078210049 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 25 Apr 2018 11:16:07 -0700 Subject: Add token flow --- .../ts/components/legacy_portal/legacy_portal.tsx | 47 ---------------------- .../legacy_portal/legacy_portal_menu.tsx | 20 --------- packages/website/ts/components/portal/portal.tsx | 35 +++++++++++++++- packages/website/ts/components/wallet/wallet.tsx | 10 ++++- 4 files changed, 43 insertions(+), 69 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/legacy_portal/legacy_portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx index 8942e4356..c45b20365 100644 --- a/packages/website/ts/components/legacy_portal/legacy_portal.tsx +++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx @@ -154,7 +154,6 @@ export class LegacyPortal extends React.Component {this.props.blockchainIsLoaded ? ( - {isDevelopment && ( - - )} - {isDevelopment && ( - - )} t.isTracked); - return ( -
-
- -
-
- ); - } - private _renderRelayers() { - return ( -
-
- -
-
- ); - } private _renderEthWrapper() { return ( {this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')} - {configs.ENVIRONMENT === Environments.DEVELOPMENT && ( -
- - {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')} - - - {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')} - -
- )}
); } diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 507860ee6..bee2cf95d 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -8,13 +8,14 @@ import { Blockchain } from 'ts/blockchain'; import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { AssetPicker } from 'ts/components/generate_order/asset_picker'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; import { TopBar } from 'ts/components/top_bar/top_bar'; import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; import { Dispatcher } from 'ts/redux/dispatcher'; -import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress } from 'ts/types'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, TokenVisibility } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; @@ -48,6 +49,7 @@ interface PortalState { prevPathname: string; isDisclaimerDialogOpen: boolean; isLedgerDialogOpen: boolean; + isAssetPickerDialogOpen: boolean; } const THROTTLE_TIMEOUT = 100; @@ -89,6 +91,7 @@ export class Portal extends React.Component { prevUserAddress: this.props.userAddress, prevPathname: this.props.location.pathname, isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isAssetPickerDialogOpen: false, isLedgerDialogOpen: false, }; } @@ -176,6 +179,7 @@ export class Portal extends React.Component { injectedProviderName={this.props.injectedProviderName} providerType={this.props.providerType} onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} + onAddToken={this._onAddToken.bind(this)} />
@@ -208,15 +212,44 @@ export class Portal extends React.Component { isOpen={this.state.isLedgerDialogOpen} /> )} +
); } + private _onTokenChosen(tokenAddress: string) { + if (_.isEmpty(tokenAddress)) { + this.setState({ + isAssetPickerDialogOpen: false, + }); + return; + } + const token = this.props.tokenByAddress[tokenAddress]; + this.props.dispatcher.updateTokenByAddress([token]); + this.setState({ + isAssetPickerDialogOpen: false, + }); + } private _onToggleLedgerDialog() { this.setState({ isLedgerDialogOpen: !this.state.isLedgerDialogOpen, }); } + private _onAddToken() { + this.setState({ + isAssetPickerDialogOpen: !this.state.isAssetPickerDialogOpen, + }); + } private _onPortalDisclaimerAccepted() { localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); this.setState({ diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 057c712e5..068764027 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -55,6 +55,7 @@ export interface WalletProps { injectedProviderName: string; providerType: ProviderType; onToggleLedgerDialog: () => void; + onAddToken: () => void; } interface WalletState { @@ -232,7 +233,14 @@ export class Wallet extends React.Component { } private _renderFooterRows() { const primaryText = '+ other tokens'; - return ; + return ( + + ); } private _renderEthRows() { const primaryText = this._renderAmount( -- cgit v1.2.3 From 419b670aa35eb35a767137121b5e594a04793eb7 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 3 May 2018 15:15:13 -0700 Subject: Make wallet scrollable --- packages/website/ts/components/wallet/wallet.tsx | 57 ++++++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index 068764027..a28012aaf 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -61,6 +61,7 @@ export interface WalletProps { interface WalletState { trackedTokenStateByAddress: TokenStateByAddress; wrappedEtherDirection?: Side; + isHoveringSidebar: boolean; } interface AllowanceToggleConfig { @@ -95,6 +96,9 @@ const styles: Styles = { }, footerItemInnerDiv: { paddingLeft: 24, + borderTopColor: colors.walletBorder, + borderTopStyle: 'solid', + borderWidth: 1, }, borderedItem: { borderBottomColor: colors.walletBorder, @@ -115,7 +119,17 @@ const styles: Styles = { paddingTop: 8, paddingBottom: 8, }, - accessoryItemsContainer: { width: 150, right: 8 }, + accessoryItemsContainer: { + width: 150, + right: 8, + }, + bodyInnerDiv: { + padding: 0, + // TODO: make this completely responsive + maxHeight: 475, + overflow: 'auto', + WebkitOverflowScrolling: 'touch', + }, }; const ETHER_ICON_PATH = '/images/ether.png'; @@ -140,6 +154,7 @@ export class Wallet extends React.Component { this.state = { trackedTokenStateByAddress: initialTrackedTokenStateByAddress, wrappedEtherDirection: undefined, + isHoveringSidebar: false, }; } public componentWillMount() { @@ -185,12 +200,7 @@ export class Wallet extends React.Component { return ( {isAddressAvailable - ? _.concat( - this._renderConnectedHeaderRows(), - this._renderEthRows(), - this._renderTokenRows(), - this._renderFooterRows(), - ) + ? _.concat(this._renderConnectedHeaderRows(), this._renderBody(), this._renderFooterRows()) : _.concat(this._renderDisconnectedHeaderRows(), this._renderDisconnectedRows())} ); @@ -231,6 +241,33 @@ export class Wallet extends React.Component { /> ); } + private _renderBody() { + const bodyStyle: React.CSSProperties = { + ...styles.bodyInnerDiv, + overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden', + }; + return ( + + {this._renderEthRows()} + {this._renderTokenRows()} + + ); + } + private _onSidebarHover(event: React.FormEvent) { + this.setState({ + isHoveringSidebar: true, + }); + } + private _onSidebarHoverOff() { + this.setState({ + isHoveringSidebar: false, + }); + } private _renderFooterRows() { const primaryText = '+ other tokens'; return ( @@ -301,7 +338,7 @@ export class Wallet extends React.Component { ); return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this)); } - private _renderTokenRow(token: Token) { + private _renderTokenRow(token: Token, index: number) { const tokenState = this.state.trackedTokenStateByAddress[token.address]; const tokenLink = sharedUtils.getEtherScanLinkIfExists( token.address, @@ -318,12 +355,14 @@ export class Wallet extends React.Component { tokenState, }, }; + // if this is the last item in the list, do not render the border, it is rendered by the footer + const borderedStyle = index !== this.props.trackedTokens.length - 1 ? styles.borderedItem : {}; const shouldShowWrapEtherItem = !_.isUndefined(this.state.wrappedEtherDirection) && this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection; const style = shouldShowWrapEtherItem ? { ...walletItemStyles.focusedItem, ...styles.paddedItem } - : { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem }; + : { ...styles.tokenItem, ...borderedStyle, ...styles.paddedItem }; const etherToken = this._getEthToken(); return (
-- cgit v1.2.3 From 9cbd1516586fd5514cce8d216881bad3871c58fa Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 3 May 2018 15:26:30 -0700 Subject: Only show untracked tokens --- packages/website/ts/components/portal/portal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index bee2cf95d..f6077edf8 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -221,7 +221,7 @@ export class Portal extends React.Component { currentTokenAddress={''} onTokenChosen={this._onTokenChosen.bind(this)} tokenByAddress={this.props.tokenByAddress} - tokenVisibility={TokenVisibility.ALL} + tokenVisibility={TokenVisibility.UNTRACKED} />
-- cgit v1.2.3 From 6c38481550d3bc57413ffb013d1b94a53672202b Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 10:17:01 -0700 Subject: Fix typo --- packages/website/ts/components/portal/portal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index f6077edf8..e198a9f03 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -108,7 +108,7 @@ export class Portal extends React.Component { // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered // the initialization process always occurs from the same base state. This helps avoid // initialization inconsistencies (i.e While the portal was unrendered, the user might have - // become disconnected from their backing Ethereum node, changes user accounts, etc...) + // become disconnected from their backing Ethereum node, changed user accounts, etc...) this.props.dispatcher.resetState(); } public componentWillReceiveProps(nextProps: PortalProps) { -- cgit v1.2.3 From 17f3d5f6bac178ffda6060eea227ef8deaaf73aa Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 11:12:46 -0700 Subject: Suggestions and fix bad merge --- packages/website/ts/components/portal/portal.tsx | 9 --------- .../website/ts/components/top_bar/provider_display.tsx | 18 ++++++------------ 2 files changed, 6 insertions(+), 21 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 88003a94e..d359219cd 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -9,11 +9,7 @@ import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog'; import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; import { RelayerIndex } from 'ts/components/relayer_index/relayer_index'; -<<<<<<< HEAD import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar'; -======= -import { TopBar } from 'ts/components/top_bar/top_bar'; ->>>>>>> development import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; @@ -55,11 +51,7 @@ interface PortalState { } const THROTTLE_TIMEOUT = 100; -<<<<<<< HEAD const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded); -======= -const TOP_BAR_HEIGHT = 60; ->>>>>>> development const styles: Styles = { root: { @@ -71,7 +63,6 @@ const styles: Styles = { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, scrollContainer: { - overflowZ: 'hidden', height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', overflow: 'auto', diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx index fa5609014..4cd50dba9 100644 --- a/packages/website/ts/components/top_bar/provider_display.tsx +++ b/packages/website/ts/components/top_bar/provider_display.tsx @@ -11,7 +11,7 @@ import { ProviderType } from 'ts/types'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; -const IDENTICON_DIAMETER = 24; +const ROOT_HEIGHT = 24; export interface ProviderDisplayProps { dispatcher: Dispatcher; @@ -27,12 +27,9 @@ interface ProviderDisplayState {} const styles: Styles = { root: { - height: 24, + height: ROOT_HEIGHT, backgroundColor: colors.white, - borderBottomRightRadius: 24, - borderBottomLeftRadius: 24, - borderTopRightRadius: 24, - borderTopLeftRadius: 24, + borderRadius: ROOT_HEIGHT, boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`, }, }; @@ -52,21 +49,18 @@ export class ProviderDisplay extends React.Component
- +
{displayAddress}
{isProviderMetamask && (
- +
)}
-- cgit v1.2.3 From 5ed9b8b1dc042319fd9ddbdb886c93a660a96769 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 11:16:12 -0700 Subject: Remove overflowZ property from portal --- packages/website/ts/components/portal/portal.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index e198a9f03..1038d0dc2 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -65,7 +65,6 @@ const styles: Styles = { height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, }, scrollContainer: { - overflowZ: 'hidden', height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', overflow: 'auto', -- cgit v1.2.3 From f94d4b492dc0a2bfdd8bfa8d9a1376ed33b03060 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Tue, 8 May 2018 11:32:44 -0700 Subject: Display top tokens from backend --- .../components/relayer_index/relayer_grid_tile.tsx | 33 +--------------------- .../relayer_index/relayer_top_tokens.tsx | 16 +++++------ 2 files changed, 9 insertions(+), 40 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 0b9b8165e..677c66695 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -12,37 +12,6 @@ export interface RelayerGridTileProps { networkId: number; } -// TODO: Get top tokens from remote -const topTokens = [ - { - address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba', - decimals: 18, - iconUrl: '/images/token_icons/makerdao.png', - isRegistered: true, - isTracked: true, - name: 'Maker DAO', - symbol: 'MKR', - }, - { - address: '0x323b5d4c32345ced77393b3530b1eed0f346429d', - decimals: 18, - iconUrl: '/images/token_icons/melon.png', - isRegistered: true, - isTracked: true, - name: 'Melon Token', - symbol: 'MLN', - }, - { - address: '0xb18845c260f680d5b9d84649638813e342e4f8c9', - decimals: 18, - iconUrl: '/images/token_icons/augur.png', - isRegistered: true, - isTracked: true, - name: 'Augur Reputation Token', - symbol: 'REP', - }, -]; - const styles: Styles = { root: { backgroundColor: colors.white, @@ -108,7 +77,7 @@ export const RelayerGridTile: React.StatelessComponent = (
Daily Trade Volume
- +
Top tokens
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx index 233590b78..db4d3a211 100644 --- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx +++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx @@ -3,10 +3,10 @@ import * as _ from 'lodash'; import * as React from 'react'; import { TokenIcon } from 'ts/components/ui/token_icon'; -import { Token } from 'ts/types'; +import { WebsiteBackendTokenInfo } from 'ts/types'; export interface TopTokensProps { - tokens: Token[]; + tokens: WebsiteBackendTokenInfo[]; networkId: number; } @@ -23,17 +23,17 @@ const styles: Styles = { export const TopTokens: React.StatelessComponent = (props: TopTokensProps) => { return (
- {_.map(props.tokens, (token: Token, index: number) => { + {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo, index: number) => { const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel }; const style = index !== 0 ? firstItemStyle : styles.tokenLabel; return ( - {token.symbol} + {tokenInfo.symbol} ); })} @@ -41,6 +41,6 @@ export const TopTokens: React.StatelessComponent = (props: TopTo ); }; -function tokenLinkFromToken(token: Token, networkId: number) { - return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address); +function tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number) { + return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address); } -- cgit v1.2.3 From 9f2258ebd962f60dfaa277814a3ead93d1b19ac7 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 09:28:57 -0700 Subject: Change relayer grid tile to link on header --- .../components/relayer_index/relayer_grid_tile.tsx | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 677c66695..cf2a1f66d 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -65,25 +65,25 @@ const styles: Styles = { export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { const link = props.relayerInfo.appUrl || props.relayerInfo.url; return ( - - -
+ +
+ -
-
- {props.relayerInfo.name} -
-
{props.relayerInfo.dailyTxnVolume}
-
- Daily Trade Volume -
- -
- Top tokens -
+
+
+
+ {props.relayerInfo.name} +
+
{props.relayerInfo.dailyTxnVolume}
+
+ Daily Trade Volume +
+ +
+ Top tokens
- - +
+ ); }; -- cgit v1.2.3 From 09b26645eebb53e8a730f60998fd689c6bb15528 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 10:04:28 -0700 Subject: Fallback image for relayer grid tile --- packages/website/ts/components/relayer_index/relayer_grid_tile.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index cf2a1f66d..23c5da50b 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -64,11 +64,12 @@ const styles: Styles = { export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { const link = props.relayerInfo.appUrl || props.relayerInfo.url; + const headerImgUrl = props.relayerInfo.headerImgUrl || '/images/landing/hero_chip_image.png'; return (
- +
-- cgit v1.2.3 From 20f6d8d3d0d7452bd4dc35c7c55b2cfc169216ca Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 10:57:02 -0700 Subject: Implement loading and error state for relayer grid --- .../ts/components/relayer_index/relayer_index.tsx | 60 ++++++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index bc84cf9e8..df208753b 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -1,5 +1,7 @@ import { colors, Styles } from '@0xproject/react-shared'; import * as _ from 'lodash'; +import CircularProgress from 'material-ui/CircularProgress'; +import FlatButton from 'material-ui/FlatButton'; import { GridList } from 'material-ui/GridList'; import * as React from 'react'; @@ -55,7 +57,24 @@ export class RelayerIndex extends React.Component +
+
+ {_.isUndefined(this.state.error) ? ( + + ) : ( + + )} +
+
+
+ ); + } else { return (
- {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo) => ( - + {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => ( + ))}
); - } else { - // TODO: loading and error states with a scrolling container - return null; } } private async _fetchRelayerInfosAsync(): Promise { @@ -96,3 +108,31 @@ export class RelayerIndex extends React.Component void; +} +const Retry = (props: RetryProps) => ( +
+
+
+ Something went wrong. +
+
+ +
+
+
+); -- cgit v1.2.3 From eba6dcc49741e7c036189220e01090a952efb8b5 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 15:45:46 -0700 Subject: Update wallet footer and add remove token functionality --- packages/website/ts/components/portal/portal.tsx | 50 ++++++++++++++++++++---- packages/website/ts/components/wallet/wallet.tsx | 31 +++++++++++++-- 2 files changed, 69 insertions(+), 12 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index b5e8150c4..4cbc65ce4 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -14,8 +14,10 @@ import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar'; import { FlashMessage } from 'ts/components/ui/flash_message'; import { Wallet } from 'ts/components/wallet/wallet'; import { localStorage } from 'ts/local_storage/local_storage'; +import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; import { Dispatcher } from 'ts/redux/dispatcher'; import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, TokenVisibility } from 'ts/types'; +import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; @@ -49,7 +51,13 @@ interface PortalState { prevPathname: string; isDisclaimerDialogOpen: boolean; isLedgerDialogOpen: boolean; - isAssetPickerDialogOpen: boolean; + tokenManagementState: TokenManagementState; +} + +enum TokenManagementState { + Add = 'Add', + Remove = 'Remove', + None = 'None', } const THROTTLE_TIMEOUT = 100; @@ -90,7 +98,7 @@ export class Portal extends React.Component { prevUserAddress: this.props.userAddress, prevPathname: this.props.location.pathname, isDisclaimerDialogOpen: !hasAcceptedDisclaimer, - isAssetPickerDialogOpen: false, + tokenManagementState: TokenManagementState.None, isLedgerDialogOpen: false, }; } @@ -142,6 +150,11 @@ export class Portal extends React.Component { ); const allTokens = _.values(this.props.tokenByAddress); const trackedTokens = _.filter(allTokens, t => t.isTracked); + const isAssetPickerDialogOpen = this.state.tokenManagementState !== TokenManagementState.None; + const tokenVisibility = + this.state.tokenManagementState === TokenManagementState.Add + ? TokenVisibility.UNTRACKED + : TokenVisibility.TRACKED; return (
@@ -180,6 +193,7 @@ export class Portal extends React.Component { providerType={this.props.providerType} onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)} onAddToken={this._onAddToken.bind(this)} + onRemoveToken={this._onRemoveToken.bind(this)} />
@@ -217,11 +231,11 @@ export class Portal extends React.Component { networkId={this.props.networkId} blockchain={this._blockchain} dispatcher={this.props.dispatcher} - isOpen={this.state.isAssetPickerDialogOpen} + isOpen={isAssetPickerDialogOpen} currentTokenAddress={''} onTokenChosen={this._onTokenChosen.bind(this)} tokenByAddress={this.props.tokenByAddress} - tokenVisibility={TokenVisibility.UNTRACKED} + tokenVisibility={tokenVisibility} />
@@ -230,14 +244,29 @@ export class Portal extends React.Component { private _onTokenChosen(tokenAddress: string) { if (_.isEmpty(tokenAddress)) { this.setState({ - isAssetPickerDialogOpen: false, + tokenManagementState: TokenManagementState.None, }); return; } const token = this.props.tokenByAddress[tokenAddress]; - this.props.dispatcher.updateTokenByAddress([token]); + const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol); + if (this.state.tokenManagementState === TokenManagementState.Remove && !isDefaultTrackedToken) { + if (token.isRegistered) { + // Remove the token from tracked tokens + const newToken = { + ...token, + isTracked: false, + }; + this.props.dispatcher.updateTokenByAddress([newToken]); + } else { + this.props.dispatcher.removeTokenToTokenByAddress(token); + } + trackedTokenStorage.removeTrackedToken(this.props.userAddress, this.props.networkId, tokenAddress); + } else if (isDefaultTrackedToken) { + this.props.dispatcher.showFlashMessage(`Cannot remove ${token.name} because it's a default token`); + } this.setState({ - isAssetPickerDialogOpen: false, + tokenManagementState: TokenManagementState.None, }); } private _onToggleLedgerDialog() { @@ -247,7 +276,12 @@ export class Portal extends React.Component { } private _onAddToken() { this.setState({ - isAssetPickerDialogOpen: !this.state.isAssetPickerDialogOpen, + tokenManagementState: TokenManagementState.Add, + }); + } + private _onRemoveToken() { + this.setState({ + tokenManagementState: TokenManagementState.Remove, }); } private _onPortalDisclaimerAccepted() { diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx index a28012aaf..079c0e3b3 100644 --- a/packages/website/ts/components/wallet/wallet.tsx +++ b/packages/website/ts/components/wallet/wallet.tsx @@ -9,8 +9,11 @@ import { import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import FlatButton from 'material-ui/FlatButton'; +import FloatingActionButton from 'material-ui/FloatingActionButton'; import { List, ListItem } from 'material-ui/List'; import ActionAccountBalanceWallet from 'material-ui/svg-icons/action/account-balance-wallet'; +import ContentAdd from 'material-ui/svg-icons/content/add'; +import ContentRemove from 'material-ui/svg-icons/content/remove'; import NavigationArrowDownward from 'material-ui/svg-icons/navigation/arrow-downward'; import NavigationArrowUpward from 'material-ui/svg-icons/navigation/arrow-upward'; import Close from 'material-ui/svg-icons/navigation/close'; @@ -56,6 +59,7 @@ export interface WalletProps { providerType: ProviderType; onToggleLedgerDialog: () => void; onAddToken: () => void; + onRemoveToken: () => void; } interface WalletState { @@ -138,6 +142,7 @@ const ZRX_TOKEN_SYMBOL = 'ZRX'; const ETHER_SYMBOL = 'ETH'; const ICON_DIMENSION = 24; const TOKEN_AMOUNT_DISPLAY_PRECISION = 3; +const BODY_ITEM_KEY = 'BODY'; const HEADER_ITEM_KEY = 'HEADER'; const FOOTER_ITEM_KEY = 'FOOTER'; const DISCONNECTED_ITEM_KEY = 'DISCONNECTED'; @@ -248,7 +253,7 @@ export class Wallet extends React.Component { }; return ( { }); } private _renderFooterRows() { - const primaryText = '+ other tokens'; return ( + + + + + + +
+ add/remove tokens +
+
+ } + disabled={true} innerDivStyle={styles.footerItemInnerDiv} - onClick={this.props.onAddToken} /> ); } -- cgit v1.2.3 From e83b056bd494e0e6a16fd0b9bfdb84bac2ab271d Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 15:59:10 -0700 Subject: Clear relayer grid state when fetching --- packages/website/ts/components/relayer_index/relayer_index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx index df208753b..dffd0f83f 100644 --- a/packages/website/ts/components/relayer_index/relayer_index.tsx +++ b/packages/website/ts/components/relayer_index/relayer_index.tsx @@ -93,6 +93,12 @@ export class RelayerIndex extends React.Component { try { + if (!this._isUnmounted) { + this.setState({ + relayerInfos: undefined, + error: undefined, + }); + } const relayerInfos = await backendClient.getRelayerInfosAsync(); if (!this._isUnmounted) { this.setState({ -- cgit v1.2.3 From c64ad1af28ef116e210aafb3ea6ad2138361cd7c Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 9 May 2018 17:29:02 -0700 Subject: Add fallback image support to relayer grid tile --- .../components/relayer_index/relayer_grid_tile.tsx | 38 ++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx index 23c5da50b..d88a59d15 100644 --- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx +++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx @@ -62,14 +62,19 @@ const styles: Styles = { }, }; +const FALLBACK_IMG_SRC = '/images/landing/hero_chip_image.png'; + export const RelayerGridTile: React.StatelessComponent = (props: RelayerGridTileProps) => { const link = props.relayerInfo.appUrl || props.relayerInfo.url; - const headerImgUrl = props.relayerInfo.headerImgUrl || '/images/landing/hero_chip_image.png'; return (
- +
@@ -88,3 +93,32 @@ export const RelayerGridTile: React.StatelessComponent = ( ); }; + +interface ImgWithFallbackProps { + src?: string; + fallbackSrc: string; + style: React.CSSProperties; +} +interface ImgWithFallbackState { + imageLoadFailed: boolean; +} +class ImgWithFallback extends React.Component { + constructor(props: ImgWithFallbackProps) { + super(props); + this.state = { + imageLoadFailed: false, + }; + } + public render() { + if (this.state.imageLoadFailed || _.isUndefined(this.props.src)) { + return ; + } else { + return ; + } + } + private _onError() { + this.setState({ + imageLoadFailed: true, + }); + } +} -- cgit v1.2.3 From a6f72de09d7b2c9738b78d2097baa9906838fbe9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 8 May 2018 15:42:07 +0200 Subject: Rename deployer to sol-compiler --- packages/website/ts/components/top_bar/top_bar.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 2502bea6d..23130853c 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -149,10 +149,10 @@ export class TopBar extends React.Component { primaryText={this.props.translate.get(Key.OrderUtils, Deco.CapWords)} /> , - + , @@ -328,10 +328,10 @@ export class TopBar extends React.Component { )} - {!this._isViewingDeployerDocs() && ( - + {!this._isViewingSolCompilerDocs() && ( + - {this.props.translate.get(Key.Deployer, Deco.Cap)}{' '} + {this.props.translate.get(Key.SolCompiler, Deco.Cap)}{' '} {this.props.translate.get(Key.Docs, Deco.Cap)} @@ -476,8 +476,8 @@ export class TopBar extends React.Component { _.includes(this.props.location.pathname, WebsiteLegacyPaths.Web3Wrapper) ); } - private _isViewingDeployerDocs() { - return _.includes(this.props.location.pathname, WebsitePaths.Deployer); + private _isViewingSolCompilerDocs() { + return _.includes(this.props.location.pathname, WebsitePaths.SolCompiler); } private _isViewingJsonSchemasDocs() { return _.includes(this.props.location.pathname, WebsitePaths.JSONSchemas); @@ -498,7 +498,7 @@ export class TopBar extends React.Component { this._isViewingFAQ() || this._isViewingSmartContractsDocs() || this._isViewingWeb3WrapperDocs() || - this._isViewingDeployerDocs() || + this._isViewingSolCompilerDocs() || this._isViewingJsonSchemasDocs() || this._isViewingSolCovDocs() || this._isViewingSubprovidersDocs() || -- cgit v1.2.3 From 2e1c2d9dfeca4439435fdf1ed58504142963585a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 10 May 2018 16:57:51 +0200 Subject: Fix templates --- packages/website/ts/components/top_bar/top_bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/website/ts/components') diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index 23130853c..5a1b50310 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -390,7 +390,7 @@ export class TopBar extends React.Component { (!this._isViewing0xjsDocs() && !this._isViewingSmartContractsDocs() && !this._isViewingWeb3WrapperDocs() && - !this._isViewingDeployerDocs() && + !this._isViewingSolCompilerDocs() && !this._isViewingJsonSchemasDocs() && !this._isViewingSolCovDocs() && !this._isViewingSubprovidersDocs() && -- cgit v1.2.3