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 +++++++++++++++++++----- packages/website/ts/utils/configs.ts | 1 + 2 files changed, 38 insertions(+), 8 deletions(-) (limited to 'packages/website/ts') 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({ diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts index a54fc56a8..edfd04291 100644 --- a/packages/website/ts/utils/configs.ts +++ b/packages/website/ts/utils/configs.ts @@ -13,6 +13,7 @@ export const configs = { BACKEND_BASE_URL: 'https://website-api.0xproject.com', BASE_URL, BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', + CRYPTO_COMPARE_BASE_URL: 'https://min-api.cryptocompare.com/data', DEFAULT_DERIVATION_PATH: `44'/60'/0'`, // WARNING: ZRX & WETH MUST always be default trackedTokens DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'], -- cgit 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 +++++++++++--------- packages/website/ts/utils/backend_client.ts | 46 ++++-------------------- packages/website/ts/utils/fetch_utils.ts | 33 +++++++++++++++++ 3 files changed, 62 insertions(+), 56 deletions(-) create mode 100644 packages/website/ts/utils/fetch_utils.ts (limited to 'packages/website/ts') 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({ diff --git a/packages/website/ts/utils/backend_client.ts b/packages/website/ts/utils/backend_client.ts index fdbb3e03a..ab0fb4f32 100644 --- a/packages/website/ts/utils/backend_client.ts +++ b/packages/website/ts/utils/backend_client.ts @@ -1,16 +1,8 @@ -import { BigNumber, logUtils } from '@0xproject/utils'; import * as _ from 'lodash'; -import * as queryString from 'query-string'; -import { - ArticlesBySection, - ItemByAddress, - WebsiteBackendGasInfo, - WebsiteBackendPriceInfo, - WebsiteBackendRelayerInfo, -} from 'ts/types'; +import { ArticlesBySection, WebsiteBackendGasInfo, WebsiteBackendPriceInfo, WebsiteBackendRelayerInfo } from 'ts/types'; import { configs } from 'ts/utils/configs'; -import { errorReporter } from 'ts/utils/error_reporter'; +import { fetchUtils } from 'ts/utils/fetch_utils'; const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station'; const PRICES_ENDPOINT = '/prices'; @@ -19,7 +11,7 @@ const WIKI_ENDPOINT = '/wiki'; export const backendClient = { async getGasInfoAsync(): Promise { - const result = await requestAsync(ETH_GAS_STATION_ENDPOINT); + const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, ETH_GAS_STATION_ENDPOINT); return result; }, async getPriceInfosAsync(tokenAddresses: string[]): Promise { @@ -30,41 +22,15 @@ export const backendClient = { const queryParams = { tokens: joinedTokenAddresses, }; - const result = await requestAsync(PRICES_ENDPOINT, queryParams); + const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, PRICES_ENDPOINT, queryParams); return result; }, async getRelayerInfosAsync(): Promise { - const result = await requestAsync(RELAYERS_ENDPOINT); + const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, RELAYERS_ENDPOINT); return result; }, async getWikiArticlesBySectionAsync(): Promise { - const result = await requestAsync(WIKI_ENDPOINT); + const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, WIKI_ENDPOINT); return result; }, }; - -async function requestAsync(endpoint: string, queryParams?: object): Promise { - const query = queryStringFromQueryParams(queryParams); - const url = `${configs.BACKEND_BASE_URL}${endpoint}${query}`; - 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); - throw error; - } - const result = await response.json(); - return result; -} - -function queryStringFromQueryParams(queryParams?: object): string { - // if params are undefined or empty, return an empty string - if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) { - return ''; - } - // stringify the formatted object - const stringifiedParams = queryString.stringify(queryParams); - return `?${stringifiedParams}`; -} diff --git a/packages/website/ts/utils/fetch_utils.ts b/packages/website/ts/utils/fetch_utils.ts new file mode 100644 index 000000000..d2e902db5 --- /dev/null +++ b/packages/website/ts/utils/fetch_utils.ts @@ -0,0 +1,33 @@ +import { logUtils } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as queryString from 'query-string'; + +import { errorReporter } from 'ts/utils/error_reporter'; + +export const fetchUtils = { + async requestAsync(baseUrl: string, path: string, queryParams?: object): Promise { + const query = queryStringFromQueryParams(queryParams); + const url = `${baseUrl}${path}${query}`; + 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); + throw error; + } + const result = await response.json(); + return result; + }, +}; + +function queryStringFromQueryParams(queryParams?: object): string { + // if params are undefined or empty, return an empty string + if (_.isUndefined(queryParams) || _.isEmpty(queryParams)) { + return ''; + } + // stringify the formatted object + const stringifiedParams = queryString.stringify(queryParams); + return `?${stringifiedParams}`; +} -- cgit 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') 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 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') 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 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') 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 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 +- packages/website/ts/containers/legacy_portal.ts | 92 +++++ packages/website/ts/containers/portal.ts | 88 ---- packages/website/ts/index.tsx | 2 +- 8 files changed, 631 insertions(+), 629 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 create mode 100644 packages/website/ts/containers/legacy_portal.ts delete mode 100644 packages/website/ts/containers/portal.ts (limited to 'packages/website/ts') 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)}
- + ); } diff --git a/packages/website/ts/containers/legacy_portal.ts b/packages/website/ts/containers/legacy_portal.ts new file mode 100644 index 000000000..3b1172a44 --- /dev/null +++ b/packages/website/ts/containers/legacy_portal.ts @@ -0,0 +1,92 @@ +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { + LegacyPortal as LegacyPortalComponent, + LegacyPortalProps as LegacyPortalComponentProps, +} from 'ts/components/legacy_portal/legacy_portal'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + tokenByAddress: TokenByAddress; + lastForceTokenStateRefetch: number; + userEtherBalanceInWei: BigNumber; + screenWidth: ScreenWidths; + shouldBlockchainErrDialogBeOpen: boolean; + userAddress: string; + userSuppliedOrderCache: Order; + flashMessage?: string | React.ReactNode; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: LegacyPortalComponentProps): ConnectedState => { + const receiveAssetToken = state.sideToAssetToken[Side.Receive]; + const depositAssetToken = state.sideToAssetToken[Side.Deposit]; + const receiveAddress = !_.isUndefined(receiveAssetToken.address) + ? receiveAssetToken.address + : constants.NULL_ADDRESS; + const depositAddress = !_.isUndefined(depositAssetToken.address) + ? depositAssetToken.address + : constants.NULL_ADDRESS; + const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); + const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); + const hashData = { + depositAmount, + depositTokenContractAddr: depositAddress, + feeRecipientAddress: constants.NULL_ADDRESS, + makerFee: constants.MAKER_FEE, + orderExpiryTimestamp: state.orderExpiryTimestamp, + orderMakerAddress: state.userAddress, + orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, + receiveAmount, + receiveTokenContractAddr: receiveAddress, + takerFee: constants.TAKER_FEE, + orderSalt: state.orderSalt, + }; + return { + blockchainErr: state.blockchainErr, + blockchainIsLoaded: state.blockchainIsLoaded, + hashData, + injectedProviderName: state.injectedProviderName, + networkId: state.networkId, + nodeVersion: state.nodeVersion, + orderFillAmount: state.orderFillAmount, + providerType: state.providerType, + screenWidth: state.screenWidth, + shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, + tokenByAddress: state.tokenByAddress, + lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, + userAddress: state.userAddress, + userEtherBalanceInWei: state.userEtherBalanceInWei, + userSuppliedOrderCache: state.userSuppliedOrderCache, + flashMessage: state.flashMessage, + translate: state.translate, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const LegacyPortal: React.ComponentClass = connect( + mapStateToProps, + mapDispatchToProps, +)(LegacyPortalComponent); diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts deleted file mode 100644 index 725564ead..000000000 --- a/packages/website/ts/containers/portal.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { BigNumber } from '@0xproject/utils'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { Portal as PortalComponent, PortalAllProps as PortalComponentAllProps } from 'ts/components/portal'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -interface ConnectedState { - blockchainErr: BlockchainErrs; - blockchainIsLoaded: boolean; - hashData: HashData; - injectedProviderName: string; - networkId: number; - nodeVersion: string; - orderFillAmount: BigNumber; - providerType: ProviderType; - tokenByAddress: TokenByAddress; - lastForceTokenStateRefetch: number; - userEtherBalanceInWei: BigNumber; - screenWidth: ScreenWidths; - shouldBlockchainErrDialogBeOpen: boolean; - userAddress: string; - userSuppliedOrderCache: Order; - flashMessage?: string | React.ReactNode; - translate: Translate; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, ownProps: PortalComponentAllProps): ConnectedState => { - const receiveAssetToken = state.sideToAssetToken[Side.Receive]; - const depositAssetToken = state.sideToAssetToken[Side.Deposit]; - const receiveAddress = !_.isUndefined(receiveAssetToken.address) - ? receiveAssetToken.address - : constants.NULL_ADDRESS; - const depositAddress = !_.isUndefined(depositAssetToken.address) - ? depositAssetToken.address - : constants.NULL_ADDRESS; - const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); - const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); - const hashData = { - depositAmount, - depositTokenContractAddr: depositAddress, - feeRecipientAddress: constants.NULL_ADDRESS, - makerFee: constants.MAKER_FEE, - orderExpiryTimestamp: state.orderExpiryTimestamp, - orderMakerAddress: state.userAddress, - orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, - receiveAmount, - receiveTokenContractAddr: receiveAddress, - takerFee: constants.TAKER_FEE, - orderSalt: state.orderSalt, - }; - return { - blockchainErr: state.blockchainErr, - blockchainIsLoaded: state.blockchainIsLoaded, - hashData, - injectedProviderName: state.injectedProviderName, - networkId: state.networkId, - nodeVersion: state.nodeVersion, - orderFillAmount: state.orderFillAmount, - providerType: state.providerType, - screenWidth: state.screenWidth, - shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, - tokenByAddress: state.tokenByAddress, - lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, - userAddress: state.userAddress, - userEtherBalanceInWei: state.userEtherBalanceInWei, - userSuppliedOrderCache: state.userSuppliedOrderCache, - flashMessage: state.flashMessage, - translate: state.translate, - }; -}; - -const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const Portal: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( - PortalComponent, -); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 6b347145f..66154e9b8 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -35,7 +35,7 @@ import 'less/all.less'; // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. const LazyPortal = createLazyComponent('Portal', async () => - System.import(/* webpackChunkName: "portal" */ 'ts/containers/portal'), + System.import(/* webpackChunkName: "portal" */ 'ts/containers/legacy_portal'), ); const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), -- cgit From 941342cc2412d5dccfad8fc56fc5e36d3a0e6b1a Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 23 Apr 2018 16:41:02 -0700 Subject: Fix lazy load component name --- packages/website/ts/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/website/ts') diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 66154e9b8..d99187151 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -34,8 +34,8 @@ import 'less/all.less'; // cause we only want to import the module when the user navigates to the page. // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. -const LazyPortal = createLazyComponent('Portal', async () => - System.import(/* webpackChunkName: "portal" */ 'ts/containers/legacy_portal'), +const LazyPortal = createLazyComponent('LegacyPortal', async () => + System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), ); const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), -- cgit 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 +++++++++++++++++++++++ packages/website/ts/containers/portal.ts | 88 ++++++++++ packages/website/ts/index.tsx | 11 +- 3 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 packages/website/ts/components/portal/portal.tsx create mode 100644 packages/website/ts/containers/portal.ts (limited to 'packages/website/ts') 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); + } +} diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts new file mode 100644 index 000000000..3f0feb6e9 --- /dev/null +++ b/packages/website/ts/containers/portal.ts @@ -0,0 +1,88 @@ +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + tokenByAddress: TokenByAddress; + lastForceTokenStateRefetch: number; + userEtherBalanceInWei: BigNumber; + screenWidth: ScreenWidths; + shouldBlockchainErrDialogBeOpen: boolean; + userAddress: string; + userSuppliedOrderCache: Order; + flashMessage?: string | React.ReactNode; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: PortalComponentProps): ConnectedState => { + const receiveAssetToken = state.sideToAssetToken[Side.Receive]; + const depositAssetToken = state.sideToAssetToken[Side.Deposit]; + const receiveAddress = !_.isUndefined(receiveAssetToken.address) + ? receiveAssetToken.address + : constants.NULL_ADDRESS; + const depositAddress = !_.isUndefined(depositAssetToken.address) + ? depositAssetToken.address + : constants.NULL_ADDRESS; + const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); + const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); + const hashData = { + depositAmount, + depositTokenContractAddr: depositAddress, + feeRecipientAddress: constants.NULL_ADDRESS, + makerFee: constants.MAKER_FEE, + orderExpiryTimestamp: state.orderExpiryTimestamp, + orderMakerAddress: state.userAddress, + orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, + receiveAmount, + receiveTokenContractAddr: receiveAddress, + takerFee: constants.TAKER_FEE, + orderSalt: state.orderSalt, + }; + return { + blockchainErr: state.blockchainErr, + blockchainIsLoaded: state.blockchainIsLoaded, + hashData, + injectedProviderName: state.injectedProviderName, + networkId: state.networkId, + nodeVersion: state.nodeVersion, + orderFillAmount: state.orderFillAmount, + providerType: state.providerType, + screenWidth: state.screenWidth, + shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, + tokenByAddress: state.tokenByAddress, + lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, + userAddress: state.userAddress, + userEtherBalanceInWei: state.userEtherBalanceInWei, + userSuppliedOrderCache: state.userSuppliedOrderCache, + flashMessage: state.flashMessage, + translate: state.translate, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Portal: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( + PortalComponent, +); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index d99187151..7b7a7eb2e 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -34,9 +34,14 @@ import 'less/all.less'; // cause we only want to import the module when the user navigates to the page. // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. -const LazyPortal = createLazyComponent('LegacyPortal', async () => - System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), -); +const LazyPortal = + utils.isDevelopment() || utils.isStaging() + ? createLazyComponent('Portal', async () => + System.import(/* webpackChunkName: "portal" */ 'ts/containers/portal'), + ) + : createLazyComponent('LegacyPortal', async () => + System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), + ); const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), ); -- cgit 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') 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') 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') 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 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') 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 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') 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 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 ++--- packages/website/ts/utils/configs.ts | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/website/ts') 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; }); diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts index edfd04291..a214593d4 100644 --- a/packages/website/ts/utils/configs.ts +++ b/packages/website/ts/utils/configs.ts @@ -14,6 +14,7 @@ export const configs = { BASE_URL, BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', CRYPTO_COMPARE_BASE_URL: 'https://min-api.cryptocompare.com/data', + FIAT_QUOTE_CURRENCY_SYMBOL: 'USD', DEFAULT_DERIVATION_PATH: `44'/60'/0'`, // WARNING: ZRX & WETH MUST always be default trackedTokens DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'], -- cgit 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') 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 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 ++++-------------------- packages/website/ts/types.ts | 3 +- packages/website/ts/utils/backend_client.ts | 10 +++--- packages/website/ts/utils/configs.ts | 2 -- 4 files changed, 12 insertions(+), 49 deletions(-) (limited to 'packages/website/ts') 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, diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 2544e6735..f4fddb556 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -509,8 +509,7 @@ export interface WebsiteBackendRelayerInfo { } export interface WebsiteBackendPriceInfo { - price: string; - address: string; + [symbol: string]: string; } export interface WebsiteBackendGasInfo { diff --git a/packages/website/ts/utils/backend_client.ts b/packages/website/ts/utils/backend_client.ts index ab0fb4f32..63e06fda7 100644 --- a/packages/website/ts/utils/backend_client.ts +++ b/packages/website/ts/utils/backend_client.ts @@ -14,13 +14,13 @@ export const backendClient = { const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, ETH_GAS_STATION_ENDPOINT); return result; }, - async getPriceInfosAsync(tokenAddresses: string[]): Promise { - if (_.isEmpty(tokenAddresses)) { - return []; + async getPriceInfoAsync(tokenSymbols: string[]): Promise { + if (_.isEmpty(tokenSymbols)) { + return {}; } - const joinedTokenAddresses = tokenAddresses.join(','); + const joinedTokenSymbols = tokenSymbols.join(','); const queryParams = { - tokens: joinedTokenAddresses, + tokens: joinedTokenSymbols, }; const result = await fetchUtils.requestAsync(configs.BACKEND_BASE_URL, PRICES_ENDPOINT, queryParams); return result; diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts index a214593d4..a54fc56a8 100644 --- a/packages/website/ts/utils/configs.ts +++ b/packages/website/ts/utils/configs.ts @@ -13,8 +13,6 @@ export const configs = { BACKEND_BASE_URL: 'https://website-api.0xproject.com', BASE_URL, BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', - CRYPTO_COMPARE_BASE_URL: 'https://min-api.cryptocompare.com/data', - FIAT_QUOTE_CURRENCY_SYMBOL: 'USD', DEFAULT_DERIVATION_PATH: `44'/60'/0'`, // WARNING: ZRX & WETH MUST always be default trackedTokens DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'], -- cgit 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') 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 From f08738e13379ea86a33ad9be9f7579e637e69acb Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 25 Apr 2018 15:41:30 -0700 Subject: Add Greg and Remco to the about page --- packages/website/ts/pages/about/about.tsx | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'packages/website/ts') diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index 97be59526..d78cca703 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -113,7 +113,7 @@ const teamRow4: ProfileInfo[] = [ { name: 'Blake Henderson', title: 'Operations Associate', - description: `Operations and Analytics. Previously analytics at LinkedIn. Economics at UC San Diego. `, + description: `Operations and Analytics. Previously analytics at LinkedIn. Economics at UC San Diego.`, image: '/images/team/blake.jpg', linkedIn: 'https://www.linkedin.com/in/blakerhenderson/', github: '', @@ -130,6 +130,27 @@ const teamRow4: ProfileInfo[] = [ }, ]; +const teamRow5: ProfileInfo[] = [ + { + name: 'Greg Hysen', + title: 'Blockchain Engineer', + description: `Smart contract R&D. Previously lead distributed systems engineer at Hivemapper. Computer Science at University of Waterloo.`, + image: '/images/team/greg.jpeg', + linkedIn: 'https://www.linkedin.com/in/gregory-hysen-71741463/', + github: 'https://github.com/hysz', + medium: '', + }, + { + name: 'Remco Bloemen', + title: 'Technical Fellow', + description: `Previously cofounder at Neufund and Coblue. Part III at Cambridge. PhD dropout at Twente Business School.`, + image: '/images/team/remco.jpeg', + linkedIn: 'https://www.linkedin.com/in/remcobloemen/', + github: 'http://github.com/recmo', + medium: '', + }, +]; + const advisors: ProfileInfo[] = [ { name: 'Fred Ehrsam', @@ -223,6 +244,7 @@ export class About extends React.Component {
{this._renderProfiles(teamRow2)}
{this._renderProfiles(teamRow3)}
{this._renderProfiles(teamRow4)}
+
{this._renderProfiles(teamRow5)}
Date: Tue, 24 Apr 2018 16:36:35 +0200 Subject: Move order utils to @0xproject/order-utils --- .../ts/containers/order_utils_documentation.ts | 99 ++++++++++++++++++++++ packages/website/ts/index.tsx | 7 ++ .../website/ts/pages/documentation/doc_page.tsx | 1 + packages/website/ts/types.ts | 2 + packages/website/ts/utils/utils.ts | 3 +- 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 packages/website/ts/containers/order_utils_documentation.ts (limited to 'packages/website/ts') diff --git a/packages/website/ts/containers/order_utils_documentation.ts b/packages/website/ts/containers/order_utils_documentation.ts new file mode 100644 index 000000000..64aa7300f --- /dev/null +++ b/packages/website/ts/containers/order_utils_documentation.ts @@ -0,0 +1,99 @@ +import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { DocPackages, Environments, WebsitePaths } from 'ts/types'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +/* tslint:disable:no-var-requires */ +const IntroMarkdown = require('md/docs/order_utils/introduction'); +const InstallationMarkdown = require('md/docs/order_utils/installation'); +/* tslint:enable:no-var-requires */ + +const docSections = { + introduction: 'introduction', + installation: 'installation', + usage: 'usage', + types: 'types', +}; + +const docsInfoConfig: DocsInfoConfig = { + id: DocPackages.OrderUtils, + type: SupportedDocJson.TypeDoc, + displayName: 'Order utils', + packageUrl: 'https://github.com/0xProject/0x-monorepo', + menu: { + introduction: [docSections.introduction], + install: [docSections.installation], + usage: [docSections.usage], + types: [docSections.types], + }, + sectionNameToMarkdown: { + [docSections.introduction]: IntroMarkdown, + [docSections.installation]: InstallationMarkdown, + }, + sectionNameToModulePath: { + [docSections.usage]: [ + '"order-utils/src/order_hash"', + '"order-utils/src/signature_utils"', + '"order-utils/src/order_factory"', + '"order-utils/src/salt"', + '"order-utils/src/assert"', + '"order-utils/src/constants"', + ], + [docSections.types]: ['"order-utils/src/types"', '"types/src/index"'], + }, + menuSubsectionToVersionWhenIntroduced: {}, + sections: docSections, + visibleConstructors: [], + typeConfigs: { + // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is + // currently no way to extract the re-exported types from index.ts via TypeDoc :( + publicTypes: [ + 'OrderError', + 'Order', + 'SignedOrder', + 'ECSignature', + 'Provider', + 'JSONRPCRequestPayload', + 'JSONRPCResponsePayload', + 'JSONRPCErrorCallback', + ], + typeNameToExternalLink: { + BigNumber: constants.URL_BIGNUMBERJS_GITHUB, + }, + }, +}; +const docsInfo = new DocsInfo(docsInfoConfig); + +interface ConnectedState { + docsVersion: string; + availableDocVersions: string[]; + docsInfo: DocsInfo; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({ + docsVersion: state.docsVersion, + availableDocVersions: state.availableDocVersions, + translate: state.translate, + docsInfo, +}); + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Documentation: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( + DocPageComponent, +); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index d99187151..9535dd222 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -61,6 +61,9 @@ const LazySolCovDocumentation = createLazyComponent('Documentation', async () => const LazySubprovidersDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "subproviderDocs" */ 'ts/containers/subproviders_documentation'), ); +const LazyOrderUtilsDocumentation = createLazyComponent('Documentation', async () => + System.import(/* webpackChunkName: "orderUtilsDocs" */ 'ts/containers/order_utils_documentation'), +); analytics.init(); // tslint:disable-next-line:no-floating-promises @@ -93,6 +96,10 @@ render( path={`${WebsitePaths.Subproviders}/:version?`} component={LazySubprovidersDocumentation} /> + 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 +- packages/website/ts/types.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'packages/website/ts') 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) => ( diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index fb4f22873..05adca460 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -504,7 +504,6 @@ export interface TokenState { // TODO: Add topTokens and headerUrl properties once available from backend export interface WebsiteBackendRelayerInfo { - id: string; name: string; dailyTxnVolume: string; url: string; -- cgit From 528008b1a9d6d74434b34568bb4c3ba29a355b0c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 3 May 2018 12:35:07 +0200 Subject: Add new section to homepage --- packages/website/ts/pages/landing/landing.tsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'packages/website/ts') diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx index f961220fd..a63c24fb7 100644 --- a/packages/website/ts/pages/landing/landing.tsx +++ b/packages/website/ts/pages/landing/landing.tsx @@ -37,6 +37,8 @@ interface Project { } const THROTTLE_TIMEOUT = 100; +const WHATS_NEW_TITLE = '18 ideas for 0x relayers in 2018'; +const WHATS_NEW_URL = 'https://blog.0xproject.com/18-ideas-for-0x-relayers-in-2018-80a1498b955f'; const relayersAndDappProjects: Project[] = [ { @@ -233,6 +235,7 @@ export class Landing extends React.Component { return (
+ {this._renderWhatsNew()}
@@ -302,6 +305,28 @@ export class Landing extends React.Component {
); } + private _renderWhatsNew() { + return ( + + ); + } private _renderProjects(projects: Project[], title: string, backgroundColor: string, isTitleCenter: boolean) { const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const projectList = _.map(projects, (project: Project, i: number) => { -- cgit 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') 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 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 +++++--- packages/website/ts/types.ts | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'packages/website/ts') 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} diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 05adca460..484f09e5d 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -502,11 +502,12 @@ export interface TokenState { price?: BigNumber; } -// TODO: Add topTokens and headerUrl properties once available from backend +// TODO: Add topTokens property once available from backend export interface WebsiteBackendRelayerInfo { name: string; dailyTxnVolume: string; url: string; + headerImgUrl: string; } export interface WebsiteBackendPriceInfo { -- cgit 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 ++++++++++++---------- packages/website/ts/types.ts | 1 + 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'packages/website/ts') 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 -
- - - + + ); }; diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 484f09e5d..693077ee6 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -507,6 +507,7 @@ export interface WebsiteBackendRelayerInfo { name: string; dailyTxnVolume: string; url: string; + appUrl?: string; headerImgUrl: string; } -- cgit 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 ++++++ packages/website/ts/types.ts | 1 + 2 files changed, 7 insertions(+) (limited to 'packages/website/ts') 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 +++++++++++++++++++++++ packages/website/ts/containers/portal.ts | 88 ++++++++++ packages/website/ts/index.tsx | 11 +- 3 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 packages/website/ts/components/portal/portal.tsx create mode 100644 packages/website/ts/containers/portal.ts (limited to 'packages/website/ts') 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); + } +} diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts new file mode 100644 index 000000000..3f0feb6e9 --- /dev/null +++ b/packages/website/ts/containers/portal.ts @@ -0,0 +1,88 @@ +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + blockchainErr: BlockchainErrs; + blockchainIsLoaded: boolean; + hashData: HashData; + injectedProviderName: string; + networkId: number; + nodeVersion: string; + orderFillAmount: BigNumber; + providerType: ProviderType; + tokenByAddress: TokenByAddress; + lastForceTokenStateRefetch: number; + userEtherBalanceInWei: BigNumber; + screenWidth: ScreenWidths; + shouldBlockchainErrDialogBeOpen: boolean; + userAddress: string; + userSuppliedOrderCache: Order; + flashMessage?: string | React.ReactNode; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: PortalComponentProps): ConnectedState => { + const receiveAssetToken = state.sideToAssetToken[Side.Receive]; + const depositAssetToken = state.sideToAssetToken[Side.Deposit]; + const receiveAddress = !_.isUndefined(receiveAssetToken.address) + ? receiveAssetToken.address + : constants.NULL_ADDRESS; + const depositAddress = !_.isUndefined(depositAssetToken.address) + ? depositAssetToken.address + : constants.NULL_ADDRESS; + const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); + const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); + const hashData = { + depositAmount, + depositTokenContractAddr: depositAddress, + feeRecipientAddress: constants.NULL_ADDRESS, + makerFee: constants.MAKER_FEE, + orderExpiryTimestamp: state.orderExpiryTimestamp, + orderMakerAddress: state.userAddress, + orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS, + receiveAmount, + receiveTokenContractAddr: receiveAddress, + takerFee: constants.TAKER_FEE, + orderSalt: state.orderSalt, + }; + return { + blockchainErr: state.blockchainErr, + blockchainIsLoaded: state.blockchainIsLoaded, + hashData, + injectedProviderName: state.injectedProviderName, + networkId: state.networkId, + nodeVersion: state.nodeVersion, + orderFillAmount: state.orderFillAmount, + providerType: state.providerType, + screenWidth: state.screenWidth, + shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen, + tokenByAddress: state.tokenByAddress, + lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, + userAddress: state.userAddress, + userEtherBalanceInWei: state.userEtherBalanceInWei, + userSuppliedOrderCache: state.userSuppliedOrderCache, + flashMessage: state.flashMessage, + translate: state.translate, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Portal: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( + PortalComponent, +); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 9535dd222..1b1255214 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -34,9 +34,14 @@ import 'less/all.less'; // cause we only want to import the module when the user navigates to the page. // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. -const LazyPortal = createLazyComponent('LegacyPortal', async () => - System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), -); +const LazyPortal = + utils.isDevelopment() || utils.isStaging() + ? createLazyComponent('Portal', async () => + System.import(/* webpackChunkName: "portal" */ 'ts/containers/portal'), + ) + : createLazyComponent('LegacyPortal', async () => + System.import(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'), + ); const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), ); -- cgit 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') 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') 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 +- packages/website/ts/pages/wiki/wiki.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/website/ts') 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) => { diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx index 7ed2b750d..edca5834d 100644 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ b/packages/website/ts/pages/wiki/wiki.tsx @@ -47,7 +47,7 @@ const styles: Styles = { left: 0, bottom: 0, right: 0, - overflowZ: 'hidden', + overflow: 'hidden', height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', }, -- cgit 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') 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 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') 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 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') 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 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') 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 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') 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 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') 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 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 +++++------ packages/website/ts/types.ts | 9 +++++- 3 files changed, 17 insertions(+), 41 deletions(-) (limited to 'packages/website/ts') 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); } diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 2754075a7..f6752aef1 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -503,19 +503,26 @@ export interface TokenState { price?: BigNumber; } -// TODO: Add topTokens property once available from backend export interface WebsiteBackendRelayerInfo { name: string; dailyTxnVolume: string; url: string; appUrl?: string; headerImgUrl: string; + topTokens: WebsiteBackendTokenInfo[]; } export interface WebsiteBackendPriceInfo { [symbol: string]: string; } +export interface WebsiteBackendTokenInfo { + address: string; + decimals: number; + name: string; + symbol: string; +} + export interface WebsiteBackendGasInfo { average: number; } -- cgit 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') 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 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 ++- packages/website/ts/types.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'packages/website/ts') 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 (
- +
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index f6752aef1..67e4a5d7d 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -508,7 +508,7 @@ export interface WebsiteBackendRelayerInfo { dailyTxnVolume: string; url: string; appUrl?: string; - headerImgUrl: string; + headerImgUrl?: string; topTokens: WebsiteBackendTokenInfo[]; } -- cgit 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') 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 From 017b5a23d87c0a7926edba60827710f830c89309 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 9 May 2018 23:26:51 +0200 Subject: Fix website and 0x.js docs --- .../ts/containers/zero_ex_js_documentation.ts | 10 ++++- packages/website/ts/utils/utils.ts | 43 +++++++++++++--------- 2 files changed, 34 insertions(+), 19 deletions(-) (limited to 'packages/website/ts') diff --git a/packages/website/ts/containers/zero_ex_js_documentation.ts b/packages/website/ts/containers/zero_ex_js_documentation.ts index 40853cb9e..f68e2335f 100644 --- a/packages/website/ts/containers/zero_ex_js_documentation.ts +++ b/packages/website/ts/containers/zero_ex_js_documentation.ts @@ -68,32 +68,38 @@ const docsInfoConfig: DocsInfoConfig = { [zeroExJsDocSections.exchange]: [ '"0x.js/src/contract_wrappers/exchange_wrapper"', '"src/contract_wrappers/exchange_wrapper"', + '"contract-wrappers/src/contract_wrappers/exchange_wrapper"', ], [zeroExJsDocSections.tokenRegistry]: [ '"0x.js/src/contract_wrappers/token_registry_wrapper"', '"src/contract_wrappers/token_registry_wrapper"', + '"contract-wrappers/src/contract_wrappers/token_registry_wrapper"', ], [zeroExJsDocSections.token]: [ '"0x.js/src/contract_wrappers/token_wrapper"', '"src/contract_wrappers/token_wrapper"', + '"contract-wrappers/src/contract_wrappers/token_wrapper"', ], [zeroExJsDocSections.etherToken]: [ '"0x.js/src/contract_wrappers/ether_token_wrapper"', '"src/contract_wrappers/ether_token_wrapper"', + '"contract-wrappers/src/contract_wrappers/ether_token_wrapper"', ], [zeroExJsDocSections.proxy]: [ '"0x.js/src/contract_wrappers/proxy_wrapper"', '"0x.js/src/contract_wrappers/token_transfer_proxy_wrapper"', - '"src/contract_wrappers/token_transfer_proxy_wrapper"', + '"contract-wrappers/src/contract_wrappers/token_transfer_proxy_wrapper"', ], [zeroExJsDocSections.orderWatcher]: [ '"0x.js/src/order_watcher/order_state_watcher"', '"src/order_watcher/order_state_watcher"', + '"order-watcher/src/order_watcher/order_watcher"', ], [zeroExJsDocSections.types]: [ '"0x.js/src/types"', '"src/types"', '"types/src/index"', + '"contract-wrappers/src/types"', '"0x.js/src/contract_wrappers/generated/ether_token"', '"0x.js/src/contract_wrappers/generated/token"', '"0x.js/src/contract_wrappers/generated/exchange"', @@ -114,7 +120,7 @@ const docsInfoConfig: DocsInfoConfig = { 'Order', 'SignedOrder', 'ECSignature', - 'ZeroExError', + 'ContractWrappersError', 'EventCallback', 'EventCallbackAsync', 'EventCallbackSync', diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index 0d77b9e72..472870f31 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -1,4 +1,4 @@ -import { ECSignature, ExchangeContractErrs, ZeroEx, ZeroExError } from '0x.js'; +import { ContractWrappersError, ECSignature, ExchangeContractErrs, ZeroEx } from '0x.js'; import { OrderError } from '@0xproject/order-utils'; import { constants as sharedConstants, EtherscanLinkSuffixes, Networks } from '@0xproject/react-shared'; import { Provider } from '@0xproject/types'; @@ -6,7 +6,17 @@ import { BigNumber } from '@0xproject/utils'; import deepEqual = require('deep-equal'); import * as _ from 'lodash'; import * as moment from 'moment'; -import { Environments, Order, Providers, ScreenWidths, Side, SideToAssetToken, Token, TokenByAddress } from 'ts/types'; +import { + BlockchainCallErrs, + Environments, + Order, + Providers, + ScreenWidths, + Side, + SideToAssetToken, + Token, + TokenByAddress, +} from 'ts/types'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import * as u2f from 'ts/vendor/u2f_api'; @@ -193,21 +203,20 @@ export const utils = { const isUniqueSymbol = _.isUndefined(tokenWithSameSymbolIfExists); return isUniqueName && isUniqueSymbol; }, - zeroExErrToHumanReadableErrMsg(error: ZeroExError | ExchangeContractErrs, takerAddress: string): string { - const ZeroExErrorToHumanReadableError: { [error: string]: string } = { - [ZeroExError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist', - [ZeroExError.EtherTokenContractDoesNotExist]: 'EtherToken contract does not exist', - [ZeroExError.TokenTransferProxyContractDoesNotExist]: 'TokenTransferProxy contract does not exist', - [ZeroExError.TokenRegistryContractDoesNotExist]: 'TokenRegistry contract does not exist', - [ZeroExError.TokenContractDoesNotExist]: 'Token contract does not exist', - [ZeroExError.ZRXContractDoesNotExist]: 'ZRX contract does not exist', - [ZeroExError.UnhandledError]: 'Unhandled error occured', - [ZeroExError.UserHasNoAssociatedAddress]: 'User has no addresses available', + zeroExErrToHumanReadableErrMsg(error: ContractWrappersError | ExchangeContractErrs, takerAddress: string): string { + const ContractWrappersErrorToHumanReadableError: { [error: string]: string } = { + [ContractWrappersError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist', + [ContractWrappersError.EtherTokenContractDoesNotExist]: 'EtherToken contract does not exist', + [ContractWrappersError.TokenTransferProxyContractDoesNotExist]: + 'TokenTransferProxy contract does not exist', + [ContractWrappersError.TokenRegistryContractDoesNotExist]: 'TokenRegistry contract does not exist', + [ContractWrappersError.TokenContractDoesNotExist]: 'Token contract does not exist', + [ContractWrappersError.ZRXContractDoesNotExist]: 'ZRX contract does not exist', + [BlockchainCallErrs.UserHasNoAssociatedAddresses]: 'User has no addresses available', [OrderError.InvalidSignature]: 'Order signature is not valid', - [ZeroExError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network', - [ZeroExError.InvalidJump]: 'Invalid jump occured while executing the transaction', - [ZeroExError.OutOfGas]: 'Transaction ran out of gas', - [ZeroExError.NoNetworkId]: 'No network id detected', + [ContractWrappersError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network', + [ContractWrappersError.InvalidJump]: 'Invalid jump occured while executing the transaction', + [ContractWrappersError.OutOfGas]: 'Transaction ran out of gas', }; const exchangeContractErrorToHumanReadableError: { [error: string]: string; @@ -240,7 +249,7 @@ export const utils = { [ExchangeContractErrs.InsufficientRemainingFillAmount]: 'Insufficient remaining fill amount', }; const humanReadableErrorMsg = - exchangeContractErrorToHumanReadableError[error] || ZeroExErrorToHumanReadableError[error]; + exchangeContractErrorToHumanReadableError[error] || ContractWrappersErrorToHumanReadableError[error]; return humanReadableErrorMsg; }, isParityNode(nodeVersion: string): boolean { -- cgit 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') 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 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') 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 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') 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 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 ++-- .../ts/containers/deployer_documentation.ts | 102 --------------------- .../ts/containers/sol_compiler_documentation.ts | 99 ++++++++++++++++++++ .../ts/containers/subproviders_documentation.ts | 2 +- packages/website/ts/index.tsx | 9 +- .../website/ts/pages/documentation/doc_page.tsx | 2 +- packages/website/ts/types.ts | 6 +- 7 files changed, 118 insertions(+), 118 deletions(-) delete mode 100644 packages/website/ts/containers/deployer_documentation.ts create mode 100644 packages/website/ts/containers/sol_compiler_documentation.ts (limited to 'packages/website/ts') 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() || diff --git a/packages/website/ts/containers/deployer_documentation.ts b/packages/website/ts/containers/deployer_documentation.ts deleted file mode 100644 index e20cc195b..000000000 --- a/packages/website/ts/containers/deployer_documentation.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { Dispatcher } from 'ts/redux/dispatcher'; -import { State } from 'ts/redux/reducer'; -import { DocPackages, Environments, WebsitePaths } from 'ts/types'; -import { configs } from 'ts/utils/configs'; -import { constants } from 'ts/utils/constants'; -import { Translate } from 'ts/utils/translate'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown = require('md/docs/deployer/introduction'); -const InstallationMarkdown = require('md/docs/deployer/installation'); -const UsageMarkdown = require('md/docs/deployer/usage'); -/* tslint:enable:no-var-requires */ - -const docSections = { - introduction: 'introduction', - installation: 'installation', - usage: 'usage', - compiler: 'compiler', - deployer: 'deployer', - types: docConstants.TYPES_SECTION_NAME, -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.Deployer, - type: SupportedDocJson.TypeDoc, - displayName: 'Deployer', - packageUrl: 'https://github.com/0xProject/0x-monorepo', - menu: { - introduction: [docSections.introduction], - install: [docSections.installation], - usage: [docSections.usage], - compiler: [docSections.compiler], - deployer: [docSections.deployer], - types: [docSections.types], - }, - sectionNameToMarkdown: { - [docSections.introduction]: IntroMarkdown, - [docSections.installation]: InstallationMarkdown, - [docSections.usage]: UsageMarkdown, - }, - sectionNameToModulePath: { - [docSections.compiler]: ['"deployer/src/compiler"'], - [docSections.deployer]: ['"deployer/src/deployer"'], - [docSections.types]: ['"deployer/src/utils/types"', '"types/src/index"'], - }, - menuSubsectionToVersionWhenIntroduced: {}, - sections: docSections, - visibleConstructors: [docSections.compiler, docSections.deployer], - typeConfigs: { - // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is - // currently no way to extract the re-exported types from index.ts via TypeDoc :( - publicTypes: [ - 'CompilerOptions', - 'DeployerOptions', - 'BaseDeployerOptions', - 'UrlDeployerOptions', - 'ProviderDeployerOptions', - 'TxData', - ], - typeNameToExternalLink: { - Web3: constants.URL_WEB3_DOCS, - BigNumber: constants.URL_BIGNUMBERJS_GITHUB, - ContractInstance: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L98', - }, - typeNameToPrefix: { - ContractInstance: 'Web3', - }, - }, -}; -const docsInfo = new DocsInfo(docsInfoConfig); - -interface ConnectedState { - docsVersion: string; - availableDocVersions: string[]; - docsInfo: DocsInfo; - translate: Translate; -} - -interface ConnectedDispatch { - dispatcher: Dispatcher; -} - -const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({ - docsVersion: state.docsVersion, - availableDocVersions: state.availableDocVersions, - translate: state.translate, - docsInfo, -}); - -const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ - dispatcher: new Dispatcher(dispatch), -}); - -export const Documentation: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( - DocPageComponent, -); diff --git a/packages/website/ts/containers/sol_compiler_documentation.ts b/packages/website/ts/containers/sol_compiler_documentation.ts new file mode 100644 index 000000000..0cf595645 --- /dev/null +++ b/packages/website/ts/containers/sol_compiler_documentation.ts @@ -0,0 +1,99 @@ +import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { DocPackages, Environments, WebsitePaths } from 'ts/types'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; + +/* tslint:disable:no-var-requires */ +const IntroMarkdown = require('md/docs/sol-compiler/introduction'); +const InstallationMarkdown = require('md/docs/sol-compiler/installation'); +const UsageMarkdown = require('md/docs/sol-compiler/usage'); +/* tslint:enable:no-var-requires */ + +const docSections = { + introduction: 'introduction', + installation: 'installation', + usage: 'usage', + compiler: 'compiler', + types: docConstants.TYPES_SECTION_NAME, +}; + +const docsInfoConfig: DocsInfoConfig = { + id: DocPackages.SolCompiler, + type: SupportedDocJson.TypeDoc, + displayName: 'Sol Compiler', + packageUrl: 'https://github.com/0xProject/0x-monorepo', + menu: { + introduction: [docSections.introduction], + install: [docSections.installation], + usage: [docSections.usage], + compiler: [docSections.compiler], + types: [docSections.types], + }, + sectionNameToMarkdown: { + [docSections.introduction]: IntroMarkdown, + [docSections.installation]: InstallationMarkdown, + [docSections.usage]: UsageMarkdown, + }, + sectionNameToModulePath: { + [docSections.compiler]: ['"sol-compiler/src/compiler"'], + [docSections.types]: ['"sol-compiler/src/utils/types"', '"types/src/index"'], + }, + menuSubsectionToVersionWhenIntroduced: {}, + sections: docSections, + visibleConstructors: [docSections.compiler], + typeConfigs: { + // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is + // currently no way to extract the re-exported types from index.ts via TypeDoc :( + publicTypes: [ + 'CompilerOptions', + 'DeployerOptions', + 'BaseDeployerOptions', + 'UrlDeployerOptions', + 'ProviderDeployerOptions', + 'TxData', + ], + typeNameToExternalLink: { + Web3: constants.URL_WEB3_DOCS, + BigNumber: constants.URL_BIGNUMBERJS_GITHUB, + ContractInstance: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L98', + }, + typeNameToPrefix: { + ContractInstance: 'Web3', + }, + }, +}; +const docsInfo = new DocsInfo(docsInfoConfig); + +interface ConnectedState { + docsVersion: string; + availableDocVersions: string[]; + docsInfo: DocsInfo; + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({ + docsVersion: state.docsVersion, + availableDocVersions: state.availableDocVersions, + translate: state.translate, + docsInfo, +}); + +const mapDispatchToProps = (dispatch: Dispatch): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Documentation: React.ComponentClass = connect(mapStateToProps, mapDispatchToProps)( + DocPageComponent, +); diff --git a/packages/website/ts/containers/subproviders_documentation.ts b/packages/website/ts/containers/subproviders_documentation.ts index a14d06a3f..2178baea8 100644 --- a/packages/website/ts/containers/subproviders_documentation.ts +++ b/packages/website/ts/containers/subproviders_documentation.ts @@ -74,7 +74,7 @@ const docsInfoConfig: DocsInfoConfig = { [docSections.redundantRPCSubprovider]: ['"subproviders/src/subproviders/redundant_rpc"'], [docSections.ganacheSubprovider]: ['"subproviders/src/subproviders/ganache"'], [docSections.nonceTrackerSubprovider]: ['"subproviders/src/subproviders/nonce_tracker"'], - [docSections.types]: ['"deployer/src/utils/types"', '"types/src/index"', '"subproviders/src/types"'], + [docSections.types]: ['"sol-compiler/src/utils/types"', '"types/src/index"', '"subproviders/src/types"'], }, menuSubsectionToVersionWhenIntroduced: {}, sections: docSections, diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 1b1255214..2688d0259 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -54,8 +54,8 @@ const LazyConnectDocumentation = createLazyComponent('Documentation', async () = const LazyWeb3WrapperDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "web3WrapperDocs" */ 'ts/containers/web3_wrapper_documentation'), ); -const LazyDeployerDocumentation = createLazyComponent('Documentation', async () => - System.import(/* webpackChunkName: "deployerDocs" */ 'ts/containers/deployer_documentation'), +const LazySolCompilerDocumentation = createLazyComponent('Documentation', async () => + System.import(/* webpackChunkName: "solCompilerDocs" */ 'ts/containers/sol_compiler_documentation'), ); const LazyJSONSchemasDocumentation = createLazyComponent('Documentation', async () => System.import(/* webpackChunkName: "jsonSchemasDocs" */ 'ts/containers/json_schemas_documentation'), @@ -91,7 +91,10 @@ render( - + Date: Thu, 10 May 2018 15:18:33 +0200 Subject: Add a legacy endpoint for the deployer --- packages/website/ts/index.tsx | 4 ++++ packages/website/ts/types.ts | 1 + 2 files changed, 5 insertions(+) (limited to 'packages/website/ts') diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 2688d0259..49bcdeaac 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -126,6 +126,10 @@ render( path={`${WebsiteLegacyPaths.Web3Wrapper}/:version?`} component={LazyWeb3WrapperDocumentation} /> + diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 51a3bcba6..58929a0c6 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -344,6 +344,7 @@ export enum Docs { export enum WebsiteLegacyPaths { ZeroExJs = '/docs/0xjs', Web3Wrapper = '/docs/web3_wrapper', + Deployer = '/docs/deployer', } export enum WebsitePaths { -- cgit From f854f3ee2bd74bbb61ed465099168b4d391f92c8 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 10 May 2018 15:20:00 +0200 Subject: Remove unused deployer docs configs --- .../ts/containers/sol_compiler_documentation.ts | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'packages/website/ts') diff --git a/packages/website/ts/containers/sol_compiler_documentation.ts b/packages/website/ts/containers/sol_compiler_documentation.ts index 0cf595645..2f6486146 100644 --- a/packages/website/ts/containers/sol_compiler_documentation.ts +++ b/packages/website/ts/containers/sol_compiler_documentation.ts @@ -28,7 +28,7 @@ const docSections = { const docsInfoConfig: DocsInfoConfig = { id: DocPackages.SolCompiler, type: SupportedDocJson.TypeDoc, - displayName: 'Sol Compiler', + displayName: 'Solidity Compiler', packageUrl: 'https://github.com/0xProject/0x-monorepo', menu: { introduction: [docSections.introduction], @@ -52,22 +52,9 @@ const docsInfoConfig: DocsInfoConfig = { typeConfigs: { // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is // currently no way to extract the re-exported types from index.ts via TypeDoc :( - publicTypes: [ - 'CompilerOptions', - 'DeployerOptions', - 'BaseDeployerOptions', - 'UrlDeployerOptions', - 'ProviderDeployerOptions', - 'TxData', - ], - typeNameToExternalLink: { - Web3: constants.URL_WEB3_DOCS, - BigNumber: constants.URL_BIGNUMBERJS_GITHUB, - ContractInstance: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L98', - }, - typeNameToPrefix: { - ContractInstance: 'Web3', - }, + publicTypes: ['CompilerOptions'], + typeNameToExternalLink: {}, + typeNameToPrefix: {}, }, }; const docsInfo = new DocsInfo(docsInfoConfig); -- cgit 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') 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